зеркало из https://github.com/microsoft/STL.git
Implement ranges::remove family (#1005)
This commit is contained in:
Родитель
002cdc65a9
Коммит
16db9931be
|
@ -386,6 +386,21 @@ namespace ranges {
|
||||||
inline constexpr _For_each_n_fn for_each_n{_Not_quite_object::_Construct_tag{}};
|
inline constexpr _For_each_n_fn for_each_n{_Not_quite_object::_Construct_tag{}};
|
||||||
|
|
||||||
// VARIABLE ranges::find
|
// VARIABLE ranges::find
|
||||||
|
// clang-format off
|
||||||
|
// concept-constrained for strict enforcement as it is used by several algorithms
|
||||||
|
template <input_iterator _It, sentinel_for<_It> _Se, class _Ty, class _Pj>
|
||||||
|
requires indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
||||||
|
_NODISCARD constexpr _It _Find_unchecked(_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj) {
|
||||||
|
for (; _First != _Last; ++_First) {
|
||||||
|
if (_STD invoke(_Proj, *_First) == _Val) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _First;
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
class _Find_fn : private _Not_quite_object {
|
class _Find_fn : private _Not_quite_object {
|
||||||
public:
|
public:
|
||||||
using _Not_quite_object::_Not_quite_object;
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
@ -395,16 +410,10 @@ namespace ranges {
|
||||||
requires indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
requires indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
||||||
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const {
|
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||||
_Adl_verify_range(_First, _Last);
|
_Adl_verify_range(_First, _Last);
|
||||||
// Performance note: investigate using _Find_unchecked when same_as<_Pj, identity>
|
auto _UResult = _RANGES _Find_unchecked(
|
||||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val, _Pass_fn(_Proj));
|
||||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
|
||||||
for (; _UFirst != _ULast; ++_UFirst) {
|
|
||||||
if (_STD invoke(_Proj, *_UFirst) == _Val) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
_Seek_wrapped(_First, _STD move(_UResult));
|
||||||
return _First;
|
return _First;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -412,7 +421,12 @@ namespace ranges {
|
||||||
requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty*>
|
requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty*>
|
||||||
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(
|
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(
|
||||||
_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const {
|
_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Val, _Pass_fn(_Proj));
|
auto _First = _RANGES begin(_Range);
|
||||||
|
auto _UResult =
|
||||||
|
_RANGES _Find_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Val, _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
_Seek_wrapped(_First, _STD move(_UResult));
|
||||||
|
return _First;
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
};
|
};
|
||||||
|
@ -430,6 +444,18 @@ _NODISCARD _FwdIt find_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr
|
||||||
#ifdef __cpp_lib_concepts
|
#ifdef __cpp_lib_concepts
|
||||||
namespace ranges {
|
namespace ranges {
|
||||||
// VARIABLE ranges::find_if
|
// VARIABLE ranges::find_if
|
||||||
|
// concept-constrained for strict enforcement as it is used by several algorithms
|
||||||
|
template <input_iterator _It, sentinel_for<_It> _Se, class _Pj, indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||||
|
_NODISCARD constexpr _It _Find_if_unchecked(_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) {
|
||||||
|
for (; _First != _Last; ++_First) {
|
||||||
|
if (_STD invoke(_Pred, _STD invoke(_Proj, *_First))) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _First;
|
||||||
|
}
|
||||||
|
|
||||||
class _Find_if_fn : private _Not_quite_object {
|
class _Find_if_fn : private _Not_quite_object {
|
||||||
public:
|
public:
|
||||||
using _Not_quite_object::_Not_quite_object;
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
@ -438,22 +464,22 @@ namespace ranges {
|
||||||
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||||
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
_NODISCARD constexpr _It operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||||
_Adl_verify_range(_First, _Last);
|
_Adl_verify_range(_First, _Last);
|
||||||
auto _UFirst = _Get_unwrapped(_STD move(_First));
|
auto _UResult = _RANGES _Find_if_unchecked(
|
||||||
const auto _ULast = _Get_unwrapped(_STD move(_Last));
|
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||||
for (; _UFirst != _ULast; ++_UFirst) {
|
|
||||||
if (_STD invoke(_Pred, _STD invoke(_Proj, *_UFirst))) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
_Seek_wrapped(_First, _STD move(_UFirst));
|
_Seek_wrapped(_First, _STD move(_UResult));
|
||||||
return _First;
|
return _First;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <input_range _Rng, class _Pj = identity,
|
template <input_range _Rng, class _Pj = identity,
|
||||||
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||||
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
_NODISCARD constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||||
return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
auto _First = _RANGES begin(_Range);
|
||||||
|
auto _UResult = _RANGES _Find_if_unchecked(
|
||||||
|
_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
_Seek_wrapped(_First, _STD move(_UResult));
|
||||||
|
return _First;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -3985,13 +4011,247 @@ _FwdIt2 remove_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _P
|
||||||
template <class _ExPo, class _FwdIt, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
template <class _ExPo, class _FwdIt, class _Ty, _Enable_if_execution_policy_t<_ExPo> = 0>
|
||||||
_NODISCARD _FwdIt remove(
|
_NODISCARD _FwdIt remove(
|
||||||
_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept; // terminates
|
_ExPo&& _Exec, const _FwdIt _First, const _FwdIt _Last, const _Ty& _Val) noexcept; // terminates
|
||||||
#endif // _HAS_CXX17
|
|
||||||
|
|
||||||
#if _HAS_CXX17
|
|
||||||
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
template <class _ExPo, class _FwdIt, class _Pr, _Enable_if_execution_policy_t<_ExPo> = 0>
|
||||||
_NODISCARD _FwdIt remove_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
_NODISCARD _FwdIt remove_if(_ExPo&& _Exec, _FwdIt _First, const _FwdIt _Last, _Pr _Pred) noexcept; // terminates
|
||||||
#endif // _HAS_CXX17
|
#endif // _HAS_CXX17
|
||||||
|
|
||||||
|
#ifdef __cpp_lib_concepts
|
||||||
|
namespace ranges {
|
||||||
|
// VARIABLE ranges::remove
|
||||||
|
class _Remove_fn : private _Not_quite_object {
|
||||||
|
public:
|
||||||
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <permutable _It, sentinel_for<_It> _Se, class _Ty, class _Pj = identity>
|
||||||
|
requires indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
||||||
|
_NODISCARD constexpr subrange<_It> operator()(_It _First, _Se _Last, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||||
|
_Adl_verify_range(_First, _Last);
|
||||||
|
auto _UResult = _Remove_unchecked(
|
||||||
|
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Val, _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
return _Rewrap_subrange<subrange<_It>>(_First, _STD move(_UResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <forward_range _Rng, class _Ty, class _Pj = identity>
|
||||||
|
requires permutable<iterator_t<_Rng>>
|
||||||
|
&& indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty*>
|
||||||
|
_NODISCARD constexpr borrowed_subrange_t<_Rng> operator()(
|
||||||
|
_Rng&& _Range, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||||
|
auto _UResult = _Remove_unchecked(_Ubegin(_Range), _Uend(_Range), _Val, _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
return _Rewrap_subrange<borrowed_subrange_t<_Rng>>(_Range, _STD move(_UResult));
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
private:
|
||||||
|
template <class _It, class _Se, class _Ty, class _Pj>
|
||||||
|
_NODISCARD static constexpr subrange<_It> _Remove_unchecked(
|
||||||
|
_It _First, const _Se _Last, const _Ty& _Val, _Pj _Proj) {
|
||||||
|
// Remove projected values equal to _Val from [_First, _Last)
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(permutable<_It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>);
|
||||||
|
|
||||||
|
_First = _RANGES _Find_unchecked(_STD move(_First), _Last, _Val, _Proj);
|
||||||
|
auto _Next = _First;
|
||||||
|
if (_First == _Last) {
|
||||||
|
return {_STD move(_Next), _STD move(_First)};
|
||||||
|
}
|
||||||
|
|
||||||
|
while (++_First != _Last) {
|
||||||
|
if (_STD invoke(_Proj, *_First) != _Val) {
|
||||||
|
*_Next = _RANGES iter_move(_First);
|
||||||
|
++_Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {_STD move(_Next), _STD move(_First)};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _Remove_fn remove{_Not_quite_object::_Construct_tag{}};
|
||||||
|
|
||||||
|
// VARIABLE ranges::remove_if
|
||||||
|
class _Remove_if_fn : private _Not_quite_object {
|
||||||
|
public:
|
||||||
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
|
||||||
|
template <permutable _It, sentinel_for<_It> _Se, class _Pj = identity,
|
||||||
|
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||||
|
_NODISCARD constexpr subrange<_It> operator()(_It _First, _Se _Last, _Pr _Pred, _Pj _Proj = {}) const {
|
||||||
|
_Adl_verify_range(_First, _Last);
|
||||||
|
auto _UResult = _Remove_if_unchecked(
|
||||||
|
_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
return _Rewrap_subrange<subrange<_It>>(_First, _STD move(_UResult));
|
||||||
|
}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <forward_range _Rng, class _Pj = identity,
|
||||||
|
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||||
|
requires permutable<iterator_t<_Rng>>
|
||||||
|
_NODISCARD constexpr borrowed_subrange_t<_Rng> operator()(_Rng&& _Range, _Pr _Pred, _Pj _Proj = {}) const {
|
||||||
|
auto _UResult = _Remove_if_unchecked(_Ubegin(_Range), _Uend(_Range), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
return _Rewrap_subrange<borrowed_subrange_t<_Rng>>(_Range, _STD move(_UResult));
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
private:
|
||||||
|
template <class _It, class _Se, class _Pr, class _Pj>
|
||||||
|
_NODISCARD static constexpr subrange<_It> _Remove_if_unchecked(
|
||||||
|
_It _First, const _Se _Last, _Pr _Pred, _Pj _Proj) {
|
||||||
|
// Remove values whose projection satisfies _Pred from [_First, _Last)
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(permutable<_It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>);
|
||||||
|
|
||||||
|
_First = _RANGES _Find_if_unchecked(_STD move(_First), _Last, _Pred, _Proj);
|
||||||
|
auto _Next = _First;
|
||||||
|
if (_First == _Last) {
|
||||||
|
return {_STD move(_Next), _STD move(_First)};
|
||||||
|
}
|
||||||
|
|
||||||
|
while (++_First != _Last) {
|
||||||
|
if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) {
|
||||||
|
*_Next = _RANGES iter_move(_First);
|
||||||
|
++_Next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {_STD move(_Next), _STD move(_First)};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _Remove_if_fn remove_if{_Not_quite_object::_Construct_tag{}};
|
||||||
|
|
||||||
|
// ALIAS TEMPLATE remove_copy_result
|
||||||
|
template <class _In, class _Out>
|
||||||
|
using remove_copy_result = in_out_result<_In, _Out>;
|
||||||
|
|
||||||
|
// VARIABLE ranges::remove_copy
|
||||||
|
class _Remove_copy_fn : private _Not_quite_object {
|
||||||
|
public:
|
||||||
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <input_iterator _It, sentinel_for<_It> _Se, weakly_incrementable _Out, class _Ty, class _Pj = identity>
|
||||||
|
requires indirectly_copyable<_It, _Out>
|
||||||
|
&& indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>
|
||||||
|
constexpr remove_copy_result<_It, _Out> operator()(
|
||||||
|
_It _First, _Se _Last, _Out _Result, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||||
|
_Adl_verify_range(_First, _Last);
|
||||||
|
auto _UResult = _Remove_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)),
|
||||||
|
_Get_unwrapped_unverified(_STD move(_Result)), _Val, _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
_Seek_wrapped(_First, _STD move(_UResult.in));
|
||||||
|
_Seek_wrapped(_Result, _STD move(_UResult.out));
|
||||||
|
return {_STD move(_First), _STD move(_Result)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <input_range _Rng, weakly_incrementable _Out, class _Ty, class _Pj = identity>
|
||||||
|
requires indirectly_copyable<iterator_t<_Rng>, _Out>
|
||||||
|
&& indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Rng>, _Pj>, const _Ty*>
|
||||||
|
constexpr remove_copy_result<borrowed_iterator_t<_Rng>, _Out> operator()(
|
||||||
|
_Rng&& _Range, _Out _Result, const _Ty& _Val, _Pj _Proj = {}) const {
|
||||||
|
auto _First = _RANGES begin(_Range);
|
||||||
|
auto _UResult = _Remove_copy_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range),
|
||||||
|
_Get_unwrapped_unverified(_STD move(_Result)), _Val, _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
_Seek_wrapped(_First, _STD move(_UResult.in));
|
||||||
|
_Seek_wrapped(_Result, _STD move(_UResult.out));
|
||||||
|
return {_STD move(_First), _STD move(_Result)};
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
private:
|
||||||
|
template <class _It, class _Se, class _Out, class _Ty, class _Pj>
|
||||||
|
_NODISCARD static constexpr remove_copy_result<_It, _Out> _Remove_copy_unchecked(
|
||||||
|
_It _First, const _Se _Last, _Out _Result, const _Ty& _Val, _Pj _Proj) {
|
||||||
|
// Copy [_First, _Last) to _Result except projected values equal to _Val
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirect_binary_predicate<ranges::equal_to, projected<_It, _Pj>, const _Ty*>);
|
||||||
|
|
||||||
|
for (; _First != _Last; ++_First) {
|
||||||
|
if (_STD invoke(_Proj, *_First) != _Val) {
|
||||||
|
*_Result = *_First;
|
||||||
|
++_Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {_STD move(_First), _STD move(_Result)};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _Remove_copy_fn remove_copy{_Not_quite_object::_Construct_tag{}};
|
||||||
|
|
||||||
|
// ALIAS TEMPLATE remove_copy_if_result
|
||||||
|
template <class _In, class _Out>
|
||||||
|
using remove_copy_if_result = in_out_result<_In, _Out>;
|
||||||
|
|
||||||
|
// VARIABLE ranges::remove_copy_if
|
||||||
|
class _Remove_copy_if_fn : private _Not_quite_object {
|
||||||
|
public:
|
||||||
|
using _Not_quite_object::_Not_quite_object;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
template <input_iterator _It, sentinel_for<_It> _Se, weakly_incrementable _Out, class _Pj = identity,
|
||||||
|
indirect_unary_predicate<projected<_It, _Pj>> _Pr>
|
||||||
|
requires indirectly_copyable<_It, _Out>
|
||||||
|
constexpr remove_copy_if_result<_It, _Out> operator()(
|
||||||
|
_It _First, _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const {
|
||||||
|
_Adl_verify_range(_First, _Last);
|
||||||
|
auto _UResult =
|
||||||
|
_Remove_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)),
|
||||||
|
_Get_unwrapped_unverified(_STD move(_Result)), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
_Seek_wrapped(_First, _STD move(_UResult.in));
|
||||||
|
_Seek_wrapped(_Result, _STD move(_UResult.out));
|
||||||
|
return {_STD move(_First), _STD move(_Result)};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <input_range _Rng, weakly_incrementable _Out, class _Pj = identity,
|
||||||
|
indirect_unary_predicate<projected<iterator_t<_Rng>, _Pj>> _Pr>
|
||||||
|
requires indirectly_copyable<iterator_t<_Rng>, _Out>
|
||||||
|
constexpr remove_copy_if_result<borrowed_iterator_t<_Rng>, _Out> operator()(
|
||||||
|
_Rng&& _Range, _Out _Result, _Pr _Pred, _Pj _Proj = {}) const {
|
||||||
|
auto _First = _RANGES begin(_Range);
|
||||||
|
auto _UResult = _Remove_copy_if_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range),
|
||||||
|
_Get_unwrapped_unverified(_STD move(_Result)), _Pass_fn(_Pred), _Pass_fn(_Proj));
|
||||||
|
|
||||||
|
_Seek_wrapped(_First, _STD move(_UResult.in));
|
||||||
|
_Seek_wrapped(_Result, _STD move(_UResult.out));
|
||||||
|
return {_STD move(_First), _STD move(_Result)};
|
||||||
|
}
|
||||||
|
// clang-format on
|
||||||
|
private:
|
||||||
|
template <class _It, class _Se, class _Out, class _Pr, class _Pj>
|
||||||
|
_NODISCARD static constexpr remove_copy_if_result<_It, _Out> _Remove_copy_if_unchecked(
|
||||||
|
_It _First, const _Se _Last, _Out _Result, _Pr _Pred, _Pj _Proj) {
|
||||||
|
// Copy [_First, _Last) to _Result except projected values that satisfy _Pred
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(weakly_incrementable<_Out>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirectly_copyable<_It, _Out>);
|
||||||
|
_STL_INTERNAL_STATIC_ASSERT(indirect_unary_predicate<_Pr, projected<_It, _Pj>>);
|
||||||
|
|
||||||
|
for (; _First != _Last; ++_First) {
|
||||||
|
if (!_STD invoke(_Pred, _STD invoke(_Proj, *_First))) {
|
||||||
|
*_Result = *_First;
|
||||||
|
++_Result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {_STD move(_First), _STD move(_Result)};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
inline constexpr _Remove_copy_if_fn remove_copy_if{_Not_quite_object::_Construct_tag{}};
|
||||||
|
} // namespace ranges
|
||||||
|
#endif // __cpp_lib_concepts
|
||||||
|
|
||||||
// FUNCTION TEMPLATE unique
|
// FUNCTION TEMPLATE unique
|
||||||
template <class _FwdIt, class _Pr>
|
template <class _FwdIt, class _Pr>
|
||||||
_NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
_NODISCARD _CONSTEXPR20 _FwdIt unique(_FwdIt _First, _FwdIt _Last, _Pr _Pred) {
|
||||||
|
|
|
@ -1008,6 +1008,11 @@ constexpr void test_in_write() {
|
||||||
with_input_ranges<with_writable_iterators<Instantiator, Element2>, Element1>::call();
|
with_input_ranges<with_writable_iterators<Instantiator, Element2>, Element1>::call();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Instantiator, class Element1, class Element2>
|
||||||
|
constexpr void test_fwd_write() {
|
||||||
|
with_forward_ranges<with_writable_iterators<Instantiator, Element2>, Element1>::call();
|
||||||
|
}
|
||||||
|
|
||||||
template <class Instantiator, class Element>
|
template <class Instantiator, class Element>
|
||||||
constexpr void test_read() {
|
constexpr void test_read() {
|
||||||
with_input_iterators<Instantiator, Element>::call();
|
with_input_iterators<Instantiator, Element>::call();
|
||||||
|
|
|
@ -266,6 +266,10 @@ tests\P0896R4_ranges_alg_none_of
|
||||||
tests\P0896R4_ranges_alg_partition
|
tests\P0896R4_ranges_alg_partition
|
||||||
tests\P0896R4_ranges_alg_partition_copy
|
tests\P0896R4_ranges_alg_partition_copy
|
||||||
tests\P0896R4_ranges_alg_partition_point
|
tests\P0896R4_ranges_alg_partition_point
|
||||||
|
tests\P0896R4_ranges_alg_remove
|
||||||
|
tests\P0896R4_ranges_alg_remove_copy
|
||||||
|
tests\P0896R4_ranges_alg_remove_copy_if
|
||||||
|
tests\P0896R4_ranges_alg_remove_if
|
||||||
tests\P0896R4_ranges_alg_replace
|
tests\P0896R4_ranges_alg_replace
|
||||||
tests\P0896R4_ranges_alg_replace_copy
|
tests\P0896R4_ranges_alg_replace_copy
|
||||||
tests\P0896R4_ranges_alg_replace_copy_if
|
tests\P0896R4_ranges_alg_replace_copy_if
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,69 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <span>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
using namespace std;
|
||||||
|
using P = pair<int, int>;
|
||||||
|
|
||||||
|
// Validate dangling story
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove(borrowed<false>{}, 42)), ranges::dangling>);
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove(borrowed<true>{}, 42)), ranges::subrange<int*>>);
|
||||||
|
|
||||||
|
struct instantiator {
|
||||||
|
static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}};
|
||||||
|
|
||||||
|
template <ranges::forward_range Read>
|
||||||
|
static constexpr void call() {
|
||||||
|
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163
|
||||||
|
#pragma warning(suppress : 4127) // conditional expression is constant
|
||||||
|
if (!ranges::contiguous_range<Read> || !is_constant_evaluated())
|
||||||
|
#endif // TRANSITION, VSO-938163
|
||||||
|
{
|
||||||
|
using ranges::remove, ranges::subrange, ranges::equal, ranges::iterator_t;
|
||||||
|
|
||||||
|
size_t projectionCounter = 0;
|
||||||
|
auto projection = [&projectionCounter](const P& val) {
|
||||||
|
++projectionCounter;
|
||||||
|
return val.second;
|
||||||
|
};
|
||||||
|
|
||||||
|
{ // Validate iterator + sentinel overload
|
||||||
|
P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
|
||||||
|
auto result = remove(wrapped_input.begin(), wrapped_input.end(), 47, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), subrange<iterator_t<Read>>>);
|
||||||
|
assert(result.begin() == next(wrapped_input.begin(), 3));
|
||||||
|
assert(result.end() == wrapped_input.end());
|
||||||
|
assert(equal(expected, span{input}.first<3>()));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
projectionCounter = 0;
|
||||||
|
|
||||||
|
{ // Validate range overload
|
||||||
|
P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
|
||||||
|
auto result = remove(wrapped_input, 47, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), subrange<iterator_t<Read>>>);
|
||||||
|
assert(result.begin() == next(wrapped_input.begin(), 3));
|
||||||
|
assert(result.end() == wrapped_input.end());
|
||||||
|
assert(equal(expected, span{input}.first<3>()));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
STATIC_ASSERT((test_fwd<instantiator, P>(), true));
|
||||||
|
test_fwd<instantiator, P>();
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
using namespace std;
|
||||||
|
using P = pair<int, int>;
|
||||||
|
|
||||||
|
// Validate that remove_copy_result aliases in_out_result
|
||||||
|
STATIC_ASSERT(same_as<ranges::remove_copy_result<int, double>, ranges::in_out_result<int, double>>);
|
||||||
|
|
||||||
|
// Validate dangling story
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove_copy(borrowed<false>{}, static_cast<int*>(nullptr), 42)),
|
||||||
|
ranges::remove_copy_result<ranges::dangling, int*>>);
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove_copy(borrowed<true>{}, static_cast<int*>(nullptr), 42)),
|
||||||
|
ranges::remove_copy_result<int*, int*>>);
|
||||||
|
|
||||||
|
struct instantiator {
|
||||||
|
static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||||
|
static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}};
|
||||||
|
|
||||||
|
template <ranges::input_range Read, indirectly_writable<ranges::range_reference_t<Read>> Write>
|
||||||
|
static constexpr void call() {
|
||||||
|
// Fails checking the indirect_binary_predicate requirement in C1XX's permissive mode with proxy iterators
|
||||||
|
// (probably related to VSO-566808)
|
||||||
|
constexpr bool non_proxy =
|
||||||
|
is_reference_v<ranges::range_reference_t<Read>> && is_reference_v<iter_reference_t<Write>>;
|
||||||
|
if constexpr (non_proxy || !is_permissive) {
|
||||||
|
using ranges::remove_copy, ranges::remove_copy_result, ranges::equal, ranges::iterator_t;
|
||||||
|
|
||||||
|
size_t projectionCounter = 0;
|
||||||
|
auto projection = [&projectionCounter](const P& val) {
|
||||||
|
++projectionCounter;
|
||||||
|
return val.second;
|
||||||
|
};
|
||||||
|
|
||||||
|
{ // Validate iterator + sentinel overload
|
||||||
|
P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
|
||||||
|
auto result = remove_copy(wrapped_input.begin(), wrapped_input.end(), Write{output}, 47, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), remove_copy_result<iterator_t<Read>, Write>>);
|
||||||
|
assert(result.in == wrapped_input.end());
|
||||||
|
assert(result.out.peek() == output + 3);
|
||||||
|
assert(equal(output, expected));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
projectionCounter = 0;
|
||||||
|
|
||||||
|
{ // Validate range overload
|
||||||
|
P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
|
||||||
|
auto result = remove_copy(wrapped_input, Write{output}, 47, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), remove_copy_result<iterator_t<Read>, Write>>);
|
||||||
|
assert(result.in == wrapped_input.end());
|
||||||
|
assert(result.out.peek() == output + 3);
|
||||||
|
assert(equal(output, expected));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
#ifndef _PREFAST_ // TRANSITION, GH-1030
|
||||||
|
STATIC_ASSERT((test_in_write<instantiator, const P, P>(), true));
|
||||||
|
#endif // TRANSITION, GH-1030
|
||||||
|
test_in_write<instantiator, const P, P>();
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
using namespace std;
|
||||||
|
using P = pair<int, int>;
|
||||||
|
|
||||||
|
constexpr auto matches = [](const int val) { return val == 47; };
|
||||||
|
|
||||||
|
// Validate that remove_copy_if_result aliases in_out_result
|
||||||
|
STATIC_ASSERT(same_as<ranges::remove_copy_if_result<int, double>, ranges::in_out_result<int, double>>);
|
||||||
|
|
||||||
|
// Validate dangling story
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove_copy_if(borrowed<false>{}, static_cast<int*>(nullptr), matches)),
|
||||||
|
ranges::remove_copy_if_result<ranges::dangling, int*>>);
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove_copy_if(borrowed<true>{}, static_cast<int*>(nullptr), matches)),
|
||||||
|
ranges::remove_copy_if_result<int*, int*>>);
|
||||||
|
|
||||||
|
struct instantiator {
|
||||||
|
static constexpr P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||||
|
static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}};
|
||||||
|
|
||||||
|
template <ranges::input_range Read, indirectly_writable<ranges::range_reference_t<Read>> Write>
|
||||||
|
static constexpr void call() {
|
||||||
|
// Fails checking the indirect_binary_predicate requirement in C1XX's permissive mode with proxy iterators
|
||||||
|
// (probably related to VSO-566808)
|
||||||
|
constexpr bool non_proxy =
|
||||||
|
is_reference_v<ranges::range_reference_t<Read>> && is_reference_v<iter_reference_t<Write>>;
|
||||||
|
if constexpr (non_proxy || !is_permissive) {
|
||||||
|
using ranges::remove_copy_if, ranges::remove_copy_if_result, ranges::equal, ranges::iterator_t;
|
||||||
|
|
||||||
|
size_t projectionCounter = 0;
|
||||||
|
auto projection = [&projectionCounter](const P& val) {
|
||||||
|
++projectionCounter;
|
||||||
|
return val.second;
|
||||||
|
};
|
||||||
|
|
||||||
|
{ // Validate iterator + sentinel overload
|
||||||
|
P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
auto result =
|
||||||
|
remove_copy_if(wrapped_input.begin(), wrapped_input.end(), Write{output}, matches, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), remove_copy_if_result<iterator_t<Read>, Write>>);
|
||||||
|
assert(result.in == wrapped_input.end());
|
||||||
|
assert(result.out.peek() == output + 3);
|
||||||
|
assert(equal(output, expected));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
projectionCounter = 0;
|
||||||
|
|
||||||
|
{ // Validate range overload
|
||||||
|
P output[3] = {{-1, -1}, {-1, -1}, {-1, -1}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
auto result = remove_copy_if(wrapped_input, Write{output}, matches, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), remove_copy_if_result<iterator_t<Read>, Write>>);
|
||||||
|
assert(result.in == wrapped_input.end());
|
||||||
|
assert(result.out.peek() == output + 3);
|
||||||
|
assert(equal(output, expected));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
#ifndef _PREFAST_ // TRANSITION, GH-1030
|
||||||
|
STATIC_ASSERT((test_in_write<instantiator, const P, P>(), true));
|
||||||
|
#endif // TRANSITION, GH-1030
|
||||||
|
test_in_write<instantiator, const P, P>();
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
# Copyright (c) Microsoft Corporation.
|
||||||
|
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
RUNALL_INCLUDE ..\concepts_matrix.lst
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright (c) Microsoft Corporation.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cassert>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <span>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <range_algorithm_support.hpp>
|
||||||
|
using namespace std;
|
||||||
|
using P = pair<int, int>;
|
||||||
|
|
||||||
|
constexpr auto matches = [](const int val) { return val == 47; };
|
||||||
|
|
||||||
|
// Validate dangling story
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove_if(borrowed<false>{}, matches)), ranges::dangling>);
|
||||||
|
STATIC_ASSERT(same_as<decltype(ranges::remove_if(borrowed<true>{}, matches)), ranges::subrange<int*>>);
|
||||||
|
|
||||||
|
struct instantiator {
|
||||||
|
static constexpr P expected[3] = {{0, 99}, {2, 99}, {4, 99}};
|
||||||
|
|
||||||
|
template <ranges::forward_range Read>
|
||||||
|
static constexpr void call() {
|
||||||
|
#if !defined(__clang__) && !defined(__EDG__) // TRANSITION, VSO-938163
|
||||||
|
#pragma warning(suppress : 4127) // conditional expression is constant
|
||||||
|
if (!ranges::contiguous_range<Read> || !is_constant_evaluated())
|
||||||
|
#endif // TRANSITION, VSO-938163
|
||||||
|
{
|
||||||
|
using ranges::remove_if, ranges::subrange, ranges::equal, ranges::iterator_t;
|
||||||
|
|
||||||
|
size_t projectionCounter = 0;
|
||||||
|
auto projection = [&projectionCounter](const P& val) {
|
||||||
|
++projectionCounter;
|
||||||
|
return val.second;
|
||||||
|
};
|
||||||
|
|
||||||
|
{ // Validate iterator + sentinel overload
|
||||||
|
P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
|
||||||
|
auto result = remove_if(wrapped_input.begin(), wrapped_input.end(), matches, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), subrange<iterator_t<Read>>>);
|
||||||
|
assert(result.begin() == next(wrapped_input.begin(), 3));
|
||||||
|
assert(result.end() == wrapped_input.end());
|
||||||
|
assert(equal(expected, span{input}.first<3>()));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
|
||||||
|
projectionCounter = 0;
|
||||||
|
|
||||||
|
{ // Validate range overload
|
||||||
|
P input[5] = {{0, 99}, {1, 47}, {2, 99}, {3, 47}, {4, 99}};
|
||||||
|
Read wrapped_input{input};
|
||||||
|
|
||||||
|
auto result = remove_if(wrapped_input, matches, projection);
|
||||||
|
STATIC_ASSERT(same_as<decltype(result), subrange<iterator_t<Read>>>);
|
||||||
|
assert(result.begin() == next(wrapped_input.begin(), 3));
|
||||||
|
assert(result.end() == wrapped_input.end());
|
||||||
|
assert(equal(expected, span{input}.first<3>()));
|
||||||
|
assert(projectionCounter == ranges::size(input));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
STATIC_ASSERT((test_fwd<instantiator, P>(), true));
|
||||||
|
test_fwd<instantiator, P>();
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче