Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ranges::base #1179

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions include/range/v3/base.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/// \file
// Range v3 library
//
// Copyright Andrey Diduh 2019
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//

#ifndef RANGE_V3_BASE_HPP
#define RANGE_V3_BASE_HPP

#include <range/v3/range_concepts.hpp>
#include <range/v3/view/all.hpp>

namespace ranges
{
inline namespace v3
{
namespace detail
{
template<class V>
RANGES_CXX14_CONSTEXPR auto base_loop(V&& v, std::integral_constant<int, 0>)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
std::forward<V>(v)
)
template<class V>
RANGES_CXX14_CONSTEXPR auto base_loop(V&& v, std::integral_constant<int, 1>)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
v.base()
)
template<int N, class V>
RANGES_CXX14_CONSTEXPR auto base_loop(V&& v, std::integral_constant<int, N>)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
base_loop( v.base(), std::integral_constant<int, N-1>{})
)
template<int N, class V>
RANGES_CXX14_CONSTEXPR auto base_loop(V&& v)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
base_loop(std::forward<V>(v), std::integral_constant<int, N>{})
)

template<typename... Ts> struct make_void { typedef void type;};
template<typename... Ts> using void_t = typename make_void<Ts...>::type;

template<class T>
using remove_reference_t = typename std::remove_reference<T>::type;

template<class From, class To, int I = 0, bool is_same = std::is_same< remove_reference_t<From>, remove_reference_t<To> >::value>
struct base_distance;

template<class From, class To, int I>
struct base_distance<From, To, I, true>{
static const constexpr int value = I;
};

template<class From, class To, int I>
struct base_distance<From, To, I, false>{
template< class, class = void_t<> >
struct has_base {
static const constexpr int value = -1;
};
template<class T>
struct has_base<T, void_t<decltype(std::declval<T>().base())>> {
static const constexpr int value = base_distance<decltype(std::declval<From>().base()), To, I+1>::value;
};

static const constexpr int value = has_base<From>::value;
};

template<class I, class BaseRange>
struct iterator_or_sentinel_base_distance{
static const constexpr int iterator_n = detail::base_distance<I, iterator_t<BaseRange>>::value;
static const constexpr int value = iterator_n >= 0 ? iterator_n : detail::base_distance<I, sentinel_t<BaseRange>>::value;
static_assert(value >= 0 , "");
};
}

// iterators

// TODO: static_assert(N > 0)
template<int N = 1, typename I,
CONCEPT_REQUIRES_(Iterator<I>())>
RANGES_CXX14_CONSTEXPR auto base(I&& iter)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
detail::base_loop<N>(std::forward<I>(iter))
)

template<typename BaseIterator, typename I,
CONCEPT_REQUIRES_(Iterator<BaseIterator>() && Iterator<I>())>
RANGES_CXX14_CONSTEXPR auto base(I&& iter)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
base<
detail::base_distance<I, BaseIterator>::value
>(std::forward<I>(iter))
)

template<typename BaseRange, typename I,
CONCEPT_REQUIRES_(Iterator<I>() && Range<BaseRange>())>
RANGES_CXX14_CONSTEXPR auto base(I&& iter)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
base<
detail::iterator_or_sentinel_base_distance<I, BaseRange>::value
>(std::forward<I>(iter))
)
/*template<typename BaseRange, typename I,
CONCEPT_REQUIRES_(Iterator<I>() && Range<BaseRange>())>
RANGES_CXX14_CONSTEXPR auto base(I&& iter, BaseRange&&)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
base<iterator_t<BaseRange>>(std::forward<I>(iter))
)*/

// ranges

template<int N = 1, typename R,
CONCEPT_REQUIRES_(Range<R>())>
RANGES_CXX14_CONSTEXPR auto base(R&& range)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
detail::base_loop<N>(std::forward<R>(range))
)
template<typename BaseRange, typename R,
CONCEPT_REQUIRES_(Range<R>() && Range<BaseRange>())>
RANGES_CXX14_CONSTEXPR auto base(R&& range/*, std::false_type*/)
RANGES_DECLTYPE_AUTO_RETURN_NOEXCEPT
(
base<
detail::base_distance<R, view::all_t<BaseRange>>::value
>(view::all(std::forward<R>(range)))
)
}
}

#endif //RANGE_V3_BASE_HPP
1 change: 1 addition & 0 deletions include/range/v3/core.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include <range/v3/range_for.hpp>
#include <range/v3/index.hpp>
#include <range/v3/at.hpp>
#include <range/v3/base.hpp>
#include <range/v3/back.hpp>
#include <range/v3/front.hpp>
#include <range/v3/istream_range.hpp>
Expand Down
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ add_subdirectory(utility)
add_subdirectory(view)
add_subdirectory(experimental)

rv3_add_test(test.base base base.cpp)
rv3_add_test(test.config config config.cpp)
rv3_add_test(test.container_conversion container_conversion container_conversion.cpp)
rv3_add_test(test.constexpr_core constexpr_core constexpr_core.cpp)
Expand Down
112 changes: 112 additions & 0 deletions test/base.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/// \file
// Range v3 library
//
// Copyright Andrey Diduh 2019
//
// Use, modification and distribution is subject to the
// Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//
// Project home: https://github.com/ericniebler/range-v3
//

#include <vector>
#include <iostream>

#include <range/v3/base.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/drop.hpp>
#include <range/v3/view/take_exactly.hpp>
#include <range/v3/view/const.hpp>

#include "./simple_test.hpp"
#include "./test_utils.hpp"

using namespace ranges;

struct Data
{
int i;

bool operator==(const Data& other) const
{
return i == other.i;
}
};
using Vec = std::vector<Data>;
using Iter = ranges::iterator_t<Vec>;

void test_base_n()
{
Vec vec = { {1}, {2}, {3}, {4} };
auto list = vec | view::transform(&Data::i) | view::const_;

// ITERATOR
// base()
{
check_equal( list.begin().base(), ranges::base(list.begin()) );
}
// base<N>()
{
check_equal( list.begin().base(), ranges::base<1>(list.begin()) );
check_equal( list.begin().base().base(), ranges::base<2>(list.begin()) );
check_equal( list.begin().base().base(), ranges::base(ranges::base(list.begin())) );
check_equal( vec.begin(), ranges::base<2>(list.begin()) );
}

// RANGE
// base()
{
check_equal( list.base(), ranges::base(list) );
}
// base<N>()
{
check_equal( list.base(), ranges::base<1>(list) );
check_equal( list.base().base(), ranges::base<2>(list) );
check_equal( list.base().base(), ranges::base(ranges::base(list)) );
check_equal( vec, ranges::base<2>(list) );
}
}

void test_base_of()
{
Vec vec = { {1}, {2}, {3}, {4} };

auto repeat = [](const int& i) -> const int& { return i; };

auto list = vec | view::transform(&Data::i) | view::take_exactly(3);
auto list2 = list | view::transform(repeat) | view::transform(repeat) | view::transform(repeat);

// Not every view introduce new iterator, so:
// list.begin().base().base() != vec.begin()

// ITERATOR
{
check_equal( vec.begin(), ranges::base<Iter>(list.begin()) );
check_equal( vec.begin(), ranges::base<Iter>(list2.begin()) );
check_equal( list.begin(), ranges::base<decltype(list.begin())>(list2.begin()) );

// 0-base
check_equal( list.begin(), ranges::base<decltype(list.begin())>(list.begin()) );
check_equal( vec.begin(), ranges::base<Vec>(list.begin()) );
}

// RANGE
{
check_equal( vec, ranges::base<Vec>(list) );
check_equal( vec, ranges::base<Vec>(list2) );
check_equal( list, ranges::base<decltype(list)>(list2) );

// 0-base
check_equal( list, ranges::base<decltype(list)>(list) );
}
}

int main()
{
test_base_n();
test_base_of();

return test_result();
}