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

Enumerate with arbitrary starting index #1800

Draft
wants to merge 3 commits into
base: master
Choose a base branch
from
Draft
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
24 changes: 20 additions & 4 deletions include/range/v3/view/enumerate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace ranges
{
private:
friend range_access;
size_t start_{0};

struct cursor
{
Expand Down Expand Up @@ -72,10 +73,12 @@ namespace ranges

public:
cursor() = default;
cursor(size_t n) : index_{n}
{}
};
cursor begin_cursor() const
{
return cursor{};
return cursor{start_};
}
unreachable_sentinel_t end_cursor() const
{
Expand All @@ -84,6 +87,8 @@ namespace ranges

public:
index_view() = default;
index_view(size_t n) : start_{n}
{}
};

} // namespace detail
Expand All @@ -103,17 +108,28 @@ namespace ranges
{
template(typename Rng)(
requires viewable_range<Rng>)
auto operator()(Rng && rng) const
auto operator()(Rng && rng, size_t n = 0) const
{
using D = range_difference_t<Rng>;
using S = detail::iter_size_t<iterator_t<Rng>>;
return zip(detail::index_view<S, D>(), all(static_cast<Rng &&>(rng)));
return zip(detail::index_view<S, D>(n), all(static_cast<Rng &&>(rng)));
}
};

struct enumerate_start_at_fn : enumerate_fn
{
using enumerate_fn::operator();

constexpr auto operator()(size_t n) const
{
return make_view_closure(
bind_back(enumerate_fn{}, n));
}
};

/// \relates enumerate_fn
/// \ingroup group-views
RANGES_INLINE_VARIABLE(view_closure<enumerate_fn>, enumerate)
RANGES_INLINE_VARIABLE(view_closure<enumerate_start_at_fn>, enumerate)
} // namespace views
/// @}
} // namespace ranges
Expand Down
65 changes: 61 additions & 4 deletions test/view/enumerate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
using std::begin;

template<class RangeT>
void test_enumerate_with(RangeT &&range)
void test_enumerate_with(RangeT &&range, int n = 0)
{
auto enumerated_range = ranges::views::enumerate(range);
auto enumerated_range = ranges::views::enumerate(range, n);
CPP_assert(ranges::borrowed_range<decltype(enumerated_range)>);

std::size_t idx_ref = 0;
std::size_t idx_ref = n;
auto it_ref = begin( range );

for(auto it = enumerated_range.begin(); it != enumerated_range.end(); ++it)
Expand All @@ -50,20 +50,39 @@ int main()
test_enumerate_with(es);
}

{ // test array with starting index
int const es[] = { 9,8,7,6,5,4,3,2,1,0 };
test_enumerate_with(es, 7);
}

{ // test with vector of complex value type
std::vector<std::list<int>> range{ {1, 2, 3}, { 3,5,6,7 }, { 10,5,6,1 }, { 1,2,3,4 } };
const auto rcopy = range;

test_enumerate_with(range);

// check that range hasn't accidentially been modified
// check that range hasn't accidentally been modified
CHECK(rcopy == range);

// check with empty range
range.clear();
test_enumerate_with(range);
}

{ // test with vector of complex value type with starting index
std::vector<std::list<int>> range{ {1, 2, 3}, { 3,5,6,7 }, { 10,5,6,1 }, { 1,2,3,4 } };
const auto rcopy = range;

test_enumerate_with(range, 2);

// check that range hasn't accidentally been modified
CHECK(rcopy == range);

// check with empty range
range.clear();
test_enumerate_with(range, 2);
}

{ // test with list
std::list<int> range{ 9,8,7,6,5,4,3,2,1 };
test_enumerate_with(range);
Expand All @@ -72,10 +91,22 @@ int main()
test_enumerate_with(range);
}

{ // test with list with starting index
std::list<int> range{ 9,8,7,6,5,4,3,2,1 };
test_enumerate_with(range, 1);

range.clear();
test_enumerate_with(range, 1);
}

{ // test with initializer_list
test_enumerate_with(std::initializer_list<int>{9, 8, 7, 6, 5, 4, 3, 2, 1});
}

{ // test with initializer_list with starting index
test_enumerate_with(std::initializer_list<int>{9, 8, 7, 6, 5, 4, 3, 2, 1}, 49);
}

{
auto range = ranges::views::iota(0, 0);
test_enumerate_with(range);
Expand All @@ -84,6 +115,14 @@ int main()
test_enumerate_with(range);
}

{
auto range = ranges::views::iota(0, 0);
test_enumerate_with(range, 2);

range = ranges::views::iota(-10000, 10000);
test_enumerate_with(range, 2);
}

{
auto range = ranges::views::iota((std::uintmax_t)0, (std::uintmax_t)0);
test_enumerate_with(range);
Expand All @@ -92,6 +131,14 @@ int main()
test_enumerate_with(range2);
}

{
auto range = ranges::views::iota((std::uintmax_t)0, (std::uintmax_t)0);
test_enumerate_with(range, 42);

auto range2 = ranges::views::iota((std::intmax_t) -10000, (std::intmax_t) 10000);
test_enumerate_with(range2, 42);
}

// https://github.com/ericniebler/range-v3/issues/1141
{
using namespace ranges;
Expand All @@ -103,5 +150,15 @@ int main()
CPP_assert(same_as<range_value_t<X>, std::pair<detail::diffmax_t, char const*>>);
}

{
using namespace ranges;
auto x = views::indices( std::uintmax_t( 100 ) )
| views::transform([](std::uintmax_t) { return "";})
| views::enumerate(99);
using X = decltype(x);
CPP_assert(same_as<range_difference_t<X>, detail::diffmax_t>);
CPP_assert(same_as<range_value_t<X>, std::pair<detail::diffmax_t, char const*>>);
}

return ::test_result();
}