Skip to content

Add ranget drop and skip methods #4347

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

Merged
Merged
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
21 changes: 20 additions & 1 deletion src/util/range.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ struct ranget final
public:
using value_type = typename iteratort::value_type;

ranget(iteratort begin, iteratort end) : begin_value(begin), end_value(end)
ranget(iteratort begin, iteratort end)
: begin_value(std::move(begin)), end_value(std::move(end))
{
}

Expand Down Expand Up @@ -341,6 +342,24 @@ struct ranget final
return begin_value == end_value;
}

/// Return an new range containing the same elements except for the first
/// \p count elements.
/// If the range has fewer elements, returns an empty range.
ranget<iteratort> drop(std::size_t count) &&
{
for(; count > 0 && begin_value != end_value; --count)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Could this be defined in terms of std::advance and std::distance? I think you could advance the begin iterator by the std::min of count and the distance between the begin and the end iterators.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe, but I don't know if it's worth it. Some distance functions work by iterating from the current position to the end, so using that plus advance would end up being less efficient.

++begin_value;
return ranget<iteratort>{std::move(begin_value), std::move(end_value)};
}

/// Return an new range containing the same elements except for the first
/// \p count elements.
/// If the range has fewer elements, returns an empty range.
ranget<iteratort> drop(std::size_t count) const &
{
return ranget<iteratort>{begin(), end()}.drop(count);
}

iteratort begin() const
{
return begin_value;
Expand Down
39 changes: 39 additions & 0 deletions unit/util/range.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,45 @@ SCENARIO("range tests", "[core][util][range]")
++it;
REQUIRE(it == filtered_range.end());
}

THEN("Drop first 2 elements")
{
auto range = make_range(list);
auto drop_range = range.drop(2);
auto it = drop_range.begin();
REQUIRE(*it == "acdef");
drop_range = std::move(drop_range).drop(1);
REQUIRE(drop_range.empty());
// Check the original is unmodified
REQUIRE(!range.empty());
REQUIRE(*range.begin() == "abc");
}
THEN("Drop first 5 elements")
{
auto range = make_range(list);
auto skip_range = range.drop(5);
REQUIRE(skip_range.empty());
// Check the original is unmodified
REQUIRE(!range.empty());
REQUIRE(*range.begin() == "abc");
}
THEN("Drop first 2 elements, move version")
{
auto range = make_range(list);
range = std::move(range).drop(2);
REQUIRE(!range.empty());
auto it = range.begin();
REQUIRE(*it == "acdef");
range = std::move(range).drop(1);
REQUIRE(range.empty());
}
THEN("Drop first 5 elements, move version")
{
auto range = make_range(list);
range = std::move(range).drop(5);
REQUIRE(range.empty());
}

THEN(
"A const instance of a `filter_iteratort` can mutate the input "
"collection.")
Expand Down