diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 945936ee546..3670a2963d9 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -336,21 +336,40 @@ namespace ranges { indirectly_unary_invocable> _Fn> constexpr for_each_result<_It, _Fn> operator()(_It _First, _Se _Last, _Fn _Func, _Pj _Proj = {}) const { _Adl_verify_range(_First, _Last); - auto _UFirst = _Get_unwrapped(_STD move(_First)); - const auto _ULast = _Get_unwrapped(_STD move(_Last)); - for (; _UFirst != _ULast; ++_UFirst) { - _STD invoke(_Func, _STD invoke(_Proj, *_UFirst)); - } - _Seek_wrapped(_First, _STD move(_UFirst)); - return {_STD move(_First), _STD move(_Func)}; + auto _UResult = _For_each_unchecked( + _Get_unwrapped(_STD move(_First)), _Get_unwrapped(_STD move(_Last)), _STD move(_Func), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.fun)}; } template , _Pj>> _Fn> constexpr for_each_result, _Fn> operator()( _Rng&& _Range, _Fn _Func, _Pj _Proj = {}) const { - return (*this)(_RANGES begin(_Range), _RANGES end(_Range), _STD move(_Func), _Pass_fn(_Proj)); + auto _First = _RANGES begin(_Range); + + auto _UResult = _For_each_unchecked( + _Get_unwrapped(_STD move(_First)), _Uend(_Range), _STD move(_Func), _Pass_fn(_Proj)); + + _Seek_wrapped(_First, _STD move(_UResult.in)); + return {_STD move(_First), _STD move(_UResult.fun)}; + } + + private: + template + _NODISCARD static constexpr for_each_result<_It, _Fn> _For_each_unchecked( + _It _First, const _Se _Last, _Fn _Func, _Pj _Proj) { + _STL_INTERNAL_STATIC_ASSERT(input_iterator<_It>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _It>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_unary_invocable<_Fn, projected<_It, _Pj>>); + + for (; _First != _Last; ++_First) { + _STD invoke(_Func, _STD invoke(_Proj, *_First)); + } + + return {_STD move(_First), _STD move(_Func)}; } }; diff --git a/tests/std/tests/P0896R4_ranges_alg_for_each/test.cpp b/tests/std/tests/P0896R4_ranges_alg_for_each/test.cpp index 5732d181cc9..076f1fc4c0e 100644 --- a/tests/std/tests/P0896R4_ranges_alg_for_each/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_for_each/test.cpp @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#include #include #include #include @@ -10,66 +9,59 @@ #include #include +using namespace std; +using P = pair; -constexpr void smoke_test() { - using ranges::for_each, ranges::for_each_result, ranges::in_fun_result, ranges::iterator_t; - using std::identity, std::same_as; - using P = std::pair; - using R = std::array; +constexpr auto incr = [](auto& y) { ++y; }; - // Validate that for_each_result aliases in_fun_result - STATIC_ASSERT(same_as, in_fun_result>); +// Validate that for_each_result aliases in_fun_result +STATIC_ASSERT(same_as, ranges::in_fun_result>); - // Validate dangling story - STATIC_ASSERT( - same_as{}, identity{})), for_each_result>); - STATIC_ASSERT(same_as{}, identity{})), for_each_result>); +// Validate dangling story +STATIC_ASSERT(same_as{}, identity{})), + ranges::for_each_result>); +STATIC_ASSERT( + same_as{}, identity{})), ranges::for_each_result>); - R const values = {{{0, 42}, {2, 42}, {4, 42}}}; - auto incr = [](auto& y) { ++y; }; +struct instantiator { + static constexpr P expected[3] = {{1, 42}, {3, 42}, {5, 42}}; - { - auto pairs = values; - auto result = for_each(basic_borrowed_range{pairs}, incr, get_first); - STATIC_ASSERT(same_as>, decltype(incr)>>); - assert(result.in == basic_borrowed_range{pairs}.end()); - int some_value = 1729; - result.fun(some_value); - assert(some_value == 1730); - R const expected = {{{1, 42}, {3, 42}, {5, 42}}}; - assert(ranges::equal(pairs, expected)); - } - { - auto pairs = values; - basic_borrowed_range wrapped_pairs{pairs}; - auto result = for_each(wrapped_pairs.begin(), wrapped_pairs.end(), incr, get_second); - STATIC_ASSERT(same_as>, decltype(incr)>>); - assert(result.in == wrapped_pairs.end()); - int some_value = 1729; - result.fun(some_value); - assert(some_value == 1730); - R const expected = {{{0, 43}, {2, 43}, {4, 43}}}; - assert(ranges::equal(pairs, expected)); - } -} + template + static constexpr void call() { + using ranges::for_each, ranges::for_each_result, ranges::iterator_t; -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} + { // Validate iterator + sentinel overload + P input[3] = {{0, 42}, {2, 42}, {4, 42}}; + ReadWrite wrapped_input{input}; -struct instantiator { - template - static void call(In&& in = {}) { - using I = ranges::iterator_t; - using Fun = void (*)(std::iter_common_reference_t); - ranges::for_each(in, Fun{}); - ranges::for_each(ranges::begin(in), ranges::end(in), Fun{}); + auto result = for_each(wrapped_input.begin(), wrapped_input.end(), incr, get_first); + STATIC_ASSERT( + same_as, remove_const_t>>); + assert(result.in == wrapped_input.end()); + assert(ranges::equal(expected, input)); + + int some_value = 1729; + result.fun(some_value); + assert(some_value == 1730); + } + { // Validate range overload + P input[3] = {{0, 42}, {2, 42}, {4, 42}}; + ReadWrite wrapped_input{input}; + + auto result = for_each(wrapped_input, incr, get_first); + STATIC_ASSERT( + same_as, remove_const_t>>); + assert(result.in == wrapped_input.end()); + assert(ranges::equal(expected, input)); - using ProjFun = void (*)(unique_tag<0>); - ranges::for_each(in, ProjFun{}, ProjectionFor{}); - ranges::for_each(ranges::begin(in), ranges::end(in), ProjFun{}, ProjectionFor{}); + int some_value = 1729; + result.fun(some_value); + assert(some_value == 1730); + } } }; -template void test_in(); +int main() { + STATIC_ASSERT((test_in(), true)); + test_in(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_for_each_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_for_each_n/test.cpp index 8f0cad3e233..068156df664 100644 --- a/tests/std/tests/P0896R4_ranges_alg_for_each_n/test.cpp +++ b/tests/std/tests/P0896R4_ranges_alg_for_each_n/test.cpp @@ -2,53 +2,40 @@ // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception #include -#include #include #include #include #include #include +using namespace std; +using P = pair; -constexpr void smoke_test() { - using ranges::for_each_n, ranges::for_each_n_result, ranges::in_fun_result, ranges::iterator_t; - using std::same_as; - using P = std::pair; - using R = std::array; - - // Validate that for_each_n_result aliases in_fun_result - STATIC_ASSERT(same_as, in_fun_result>); - - R pairs = {{{0, 42}, {2, 42}, {4, 42}}}; - auto incr = [](auto& y) { ++y; }; - - basic_borrowed_range wrapped_pairs{pairs}; - auto result = for_each_n(wrapped_pairs.begin(), ranges::distance(pairs), incr, get_first); - STATIC_ASSERT(same_as>, decltype(incr)>>); - assert(result.in == wrapped_pairs.end()); - int some_value = 1729; - result.fun(some_value); - assert(some_value == 1730); - R const expected = {{{1, 42}, {3, 42}, {5, 42}}}; - assert(ranges::equal(pairs, expected)); -} +constexpr auto incr = [](auto& y) { ++y; }; -int main() { - STATIC_ASSERT((smoke_test(), true)); - smoke_test(); -} +// Validate that for_each_n_result aliases in_fun_result +STATIC_ASSERT(same_as, ranges::in_fun_result>); struct instantiator { - template - static void call(In in = {}) { - using std::iter_difference_t; + static constexpr P expected[3] = {{1, 42}, {3, 42}, {5, 42}}; - using Fun = void (*)(std::iter_common_reference_t); - ranges::for_each_n(std::move(in), iter_difference_t{}, Fun{}); + template ReadWrite> + static constexpr void call() { + using ranges::for_each_n, ranges::for_each_n_result, ranges::iterator_t, ranges::distance; + P input[3] = {{0, 42}, {2, 42}, {4, 42}}; - using ProjFun = void (*)(unique_tag<0>); - ranges::for_each_n(std::move(in), iter_difference_t{}, ProjFun{}, ProjectionFor{}); + auto result = for_each_n(ReadWrite{input}, distance(input), incr, get_first); + STATIC_ASSERT(same_as>>); + assert(result.in.peek() == end(input)); + assert(ranges::equal(expected, input)); + + int some_value = 1729; + result.fun(some_value); + assert(some_value == 1730); } }; -template void test_read(); +int main() { + STATIC_ASSERT((test_read(), true)); + test_read(); +}