Skip to content

Commit

Permalink
Implement ranges::drop_while_view (#1366)
Browse files Browse the repository at this point in the history
Co-authored-by: Casey Carter <[email protected]>
Co-authored-by: Stephan T. Lavavej <[email protected]>
  • Loading branch information
3 people authored Nov 6, 2020
1 parent 0650fa4 commit 1093aa6
Show file tree
Hide file tree
Showing 9 changed files with 624 additions and 52 deletions.
52 changes: 0 additions & 52 deletions stl/inc/algorithm
Original file line number Diff line number Diff line change
Expand Up @@ -490,58 +490,6 @@ template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_E
_NODISCARD _FwdIt find_if_not(_ExPo&& _Exec, _FwdIt _First, _FwdIt _Last, _Pr _Pred) noexcept; // terminates
#endif // _HAS_CXX17

#ifdef __cpp_lib_concepts
namespace ranges {
// VARIABLE ranges::find_if_not
class _Find_if_not_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
_Adl_verify_range(_First, _Last);

auto _UResult = _Find_if_not_unchecked(
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj));

_Seek_wrapped(_First, _STD move(_UResult));
return _First;
}

template <input_range _Rng, class _Pj = identity,
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
auto _First = _RANGES begin(_Range);

auto _UResult = _Find_if_not_unchecked(
_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));

_Seek_wrapped(_First, _STD move(_UResult));
return _First;
}

private:
template <class _It, class _Se, class _Pj, class _Pr>
_NODISCARD static constexpr _It _Find_if_not_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) {
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>);
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
_STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>);

for (; _First != _Last; ++_First) {
if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) {
break;
}
}

return _First;
}
};

inline constexpr _Find_if_not_fn find_if_not{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts

// FUNCTION TEMPLATE adjacent_find
template <class _FwdIt, class _Pr>
_NODISCARD _CONSTEXPR20 _FwdIt adjacent_find(const _FwdIt _First, _FwdIt _Last, _Pr _Pred) {
Expand Down
98 changes: 98 additions & 0 deletions stl/inc/ranges
Original file line number Diff line number Diff line change
Expand Up @@ -2052,6 +2052,104 @@ namespace ranges {
inline constexpr _Counted_fn counted;
} // namespace views

// CLASS TEMPLATE ranges::drop_while_view
// clang-format off
template <view _Vw, class _Pr>
requires input_range<_Vw> && is_object_v<_Pr> && indirect_unary_predicate<const _Pr, iterator_t<_Vw>>
class drop_while_view : public _Cached_position_t<forward_range<_Vw>, _Vw, drop_while_view<_Vw, _Pr>> {
// clang-format on
private:
/* [[no_unique_address]] */ _Vw _Range{};
/* [[no_unique_address]] */ _Semiregular_box<_Pr> _Pred{};

public:
drop_while_view() = default;

constexpr drop_while_view(_Vw _Range_, _Pr _Pred_) noexcept(
is_nothrow_move_constructible_v<_Vw>&& is_nothrow_move_constructible_v<_Pr>) // strengthened
: _Range(_STD move(_Range_)), _Pred{in_place, _STD move(_Pred_)} {}

_NODISCARD constexpr _Vw base() const& noexcept(
is_nothrow_copy_constructible_v<_Vw>) /* strengthened */ requires copy_constructible<_Vw> {
return _Range;
}
_NODISCARD constexpr _Vw base() && noexcept(is_nothrow_move_constructible_v<_Vw>) /* strengthened */ {
return _STD move(_Range);
}

_NODISCARD constexpr const _Pr& pred() const noexcept /* strengthened */ {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "value-initialized drop_while_view has no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
return *_Pred;
}

_NODISCARD constexpr auto begin() {
#if _CONTAINER_DEBUG_LEVEL > 0
_STL_VERIFY(_Pred, "LWG-3490 forbids calling begin on a drop_while_view with no predicate");
#endif // _CONTAINER_DEBUG_LEVEL > 0
if constexpr (forward_range<_Vw>) {
if (this->_Has_cache()) {
return this->_Get_cache(_Range);
}
}

auto _First = _RANGES find_if_not(_Range, _STD cref(*_Pred));
if constexpr (forward_range<_Vw>) {
this->_Set_cache(_Range, _First);
}

return _First;
}

_NODISCARD constexpr auto end() noexcept(noexcept(_RANGES end(_Range))) /* strengthened */ {
return _RANGES end(_Range);
}
};

template <class _Rng, class _Pr>
drop_while_view(_Rng&&, _Pr) -> drop_while_view<views::all_t<_Rng>, _Pr>;

namespace views {
// VARIABLE views::drop_while
class _Drop_while_fn {
private:
template <class _Pr>
struct _Partial : _Pipe::_Base<_Partial<_Pr>> {
/* [[no_unique_address]] */ _Semiregular_box<_Pr> _Pred;

template <viewable_range _Rng>
_NODISCARD constexpr auto operator()(_Rng&& _Range) const& noexcept(
noexcept(drop_while_view{_STD forward<_Rng>(_Range), *_Pred})) requires requires {
drop_while_view{static_cast<_Rng&&>(_Range), *_Pred};
}
{ return drop_while_view{_STD forward<_Rng>(_Range), *_Pred}; }

template <viewable_range _Rng>
_NODISCARD constexpr auto operator()(_Rng&& _Range) && noexcept(
noexcept(drop_while_view{_STD forward<_Rng>(_Range), _STD move(*_Pred)})) requires requires {
drop_while_view{static_cast<_Rng&&>(_Range), _STD move(*_Pred)};
}
{ return drop_while_view{_STD forward<_Rng>(_Range), _STD move(*_Pred)}; }
};

public:
template <viewable_range _Rng, class _Pr>
_NODISCARD constexpr auto operator()(_Rng&& _Range, _Pr _Pred) const
noexcept(noexcept(drop_while_view{_STD forward<_Rng>(_Range), _STD move(_Pred)})) requires requires {
drop_while_view{static_cast<_Rng&&>(_Range), _STD move(_Pred)};
}
{ return drop_while_view{_STD forward<_Rng>(_Range), _STD move(_Pred)}; }

template <_Copy_constructible_object _Pr>
_NODISCARD constexpr auto operator()(_Pr _Pred) const noexcept(is_nothrow_move_constructible_v<_Pr>) {
return _Partial<_Pr>{._Pred = {in_place, _STD move(_Pred)}};
}
};

inline constexpr _Drop_while_fn drop_while;
} // namespace views

// CLASS TEMPLATE ranges::reverse_view
// clang-format off
template <view _Vw>
Expand Down
48 changes: 48 additions & 0 deletions stl/inc/xutility
Original file line number Diff line number Diff line change
Expand Up @@ -5882,6 +5882,54 @@ namespace ranges {
};

inline constexpr _Find_if_fn find_if{_Not_quite_object::_Construct_tag{}};

// VARIABLE ranges::find_if_not
class _Find_if_not_fn : private _Not_quite_object {
public:
using _Not_quite_object::_Not_quite_object;

template <input_iterator _It, sentinel_for<_It> _Se, class _Pj = identity,
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
_Adl_verify_range(_First, _Last);

auto _UResult = _Find_if_not_unchecked(
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj));

_Seek_wrapped(_First, _STD move(_UResult));
return _First;
}

template <input_range _Rng, class _Pj = identity,
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
auto _First = _RANGES begin(_Range);

auto _UResult = _Find_if_not_unchecked(
_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));

_Seek_wrapped(_First, _STD move(_UResult));
return _First;
}

private:
template <class _It, class _Se, class _Pj, class _Pr>
_NODISCARD static constexpr _It _Find_if_not_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) {
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>);
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
_STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>);

for (; _First != _Last; ++_First) {
if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) {
break;
}
}

return _First;
}
};

inline constexpr _Find_if_not_fn find_if_not{_Not_quite_object::_Construct_tag{}};
} // namespace ranges
#endif // __cpp_lib_concepts

Expand Down
2 changes: 2 additions & 0 deletions tests/std/test.lst
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,8 @@ tests\P0896R4_views_common
tests\P0896R4_views_counted
tests\P0896R4_views_counted_death
tests\P0896R4_views_drop
tests\P0896R4_views_drop_while
tests\P0896R4_views_drop_while_death
tests\P0896R4_views_empty
tests\P0896R4_views_filter
tests\P0896R4_views_filter_death
Expand Down
1 change: 1 addition & 0 deletions tests/std/tests/P0896R4_ranges_range_machinery/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ STATIC_ASSERT(test_cpo(ranges::views::all));
STATIC_ASSERT(test_cpo(ranges::views::common));
STATIC_ASSERT(test_cpo(ranges::views::counted));
STATIC_ASSERT(test_cpo(ranges::views::drop));
STATIC_ASSERT(test_cpo(ranges::views::drop_while));
STATIC_ASSERT(test_cpo(ranges::views::filter));
STATIC_ASSERT(test_cpo(ranges::views::reverse));
STATIC_ASSERT(test_cpo(ranges::views::single));
Expand Down
4 changes: 4 additions & 0 deletions tests/std/tests/P0896R4_views_drop_while/env.lst
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# Copyright (c) Microsoft Corporation.
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

RUNALL_INCLUDE ..\concepts_matrix.lst
Loading

0 comments on commit 1093aa6

Please sign in to comment.