diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 59db8eb1959..cdfb5f85a9d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3169,6 +3169,74 @@ namespace ranges { }; inline constexpr _Fill_n_fn fill_n{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::generate + class _Generate_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se, copy_constructible _Fn> + requires invocable<_Fn&> && indirectly_writable<_Out, invoke_result_t<_Fn&>> + constexpr _Out operator()(_Out _First, _Se _Last, _Fn _Gen) const { + _Adl_verify_range(_First, _Last); + _Seek_wrapped(_First, _Generate_unchecked(_Get_unwrapped(_STD move(_First)), + _Get_unwrapped(_STD move(_Last)), _Pass_fn(_Gen))); + return _First; + } + + template + requires invocable<_Fn&> && output_range<_Rng, invoke_result_t<_Fn&>> + constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, _Fn _Gen) const { + auto _First = _RANGES begin(_Range); + _Seek_wrapped( + _First, _Generate_unchecked(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Pass_fn(_Gen))); + return _First; + } + // clang-format on + private: + template + _NODISCARD static constexpr _Out _Generate_unchecked(_Out _First, const _Se _Last, _Fn _Gen) { + _STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Out>); + _STL_INTERNAL_STATIC_ASSERT(sentinel_for<_Se, _Out>); + _STL_INTERNAL_STATIC_ASSERT(copy_constructible<_Fn>); + _STL_INTERNAL_STATIC_ASSERT(invocable<_Fn&>); + _STL_INTERNAL_STATIC_ASSERT(indirectly_writable<_Out, invoke_result_t<_Fn&>>); + + for (; _First != _Last; ++_First) { + *_First = _Gen(); + } + + return _First; + } + }; + + inline constexpr _Generate_fn generate{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::generate_n + class _Generate_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template + requires invocable<_Fn&> && indirectly_writable<_Out, invoke_result_t<_Fn&>> + constexpr _Out operator()(_Out _First, iter_difference_t<_Out> _Count, _Fn _Gen) const { + if (_Count > 0) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + do { + *_UFirst = _Gen(); + ++_UFirst; + } while (--_Count > 0); + + _Seek_wrapped(_First, _STD move(_UFirst)); + } + + return _First; + } + }; + + inline constexpr _Generate_n_fn generate_n{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts diff --git a/tests/std/test.lst b/tests/std/test.lst index 6358d0afa94..90f915cf24c 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -254,6 +254,8 @@ tests\P0896R4_ranges_alg_find_if tests\P0896R4_ranges_alg_find_if_not tests\P0896R4_ranges_alg_for_each tests\P0896R4_ranges_alg_for_each_n +tests\P0896R4_ranges_alg_generate +tests\P0896R4_ranges_alg_generate_n tests\P0896R4_ranges_alg_heap tests\P0896R4_ranges_alg_is_permutation tests\P0896R4_ranges_alg_is_sorted diff --git a/tests/std/tests/P0896R4_ranges_alg_generate/env.lst b/tests/std/tests/P0896R4_ranges_alg_generate/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_generate/test.cpp b/tests/std/tests/P0896R4_ranges_alg_generate/test.cpp new file mode 100644 index 00000000000..6d9cb19528a --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate/test.cpp @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include + +using namespace std; + +constexpr auto iota_gen = [val = 0]() mutable { return val++; }; + +// Validate dangling story +STATIC_ASSERT(same_as{}, iota_gen)), ranges::dangling>); +STATIC_ASSERT(same_as{}, iota_gen)), int*>); + +struct instantiator { + template Out> + static constexpr void call() { + using ranges::generate, ranges::iterator_t; + + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + auto result = generate(out_wrapper, iota_gen); + STATIC_ASSERT(same_as>); + assert(result == out_wrapper.end()); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + auto result = generate(out_wrapper.begin(), out_wrapper.end(), iota_gen); + STATIC_ASSERT(same_as>); + assert(result == out_wrapper.end()); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_generate_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_generate_n/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate_n/env.lst @@ -0,0 +1,4 @@ +# Copyright (c) Microsoft Corporation. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +RUNALL_INCLUDE ..\concepts_matrix.lst diff --git a/tests/std/tests/P0896R4_ranges_alg_generate_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_generate_n/test.cpp new file mode 100644 index 00000000000..f08ba74d46d --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_generate_n/test.cpp @@ -0,0 +1,53 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include + +#include + +using namespace std; + +struct instantiator { + template Out> + static constexpr void call() { + using ranges::generate_n, ranges::equal, ranges::iterator_t; + + const auto iota_gen = [val = 0]() mutable { return val++; }; + + { + int output[] = {13, 42, 1367}; + Out out_wrapper{output}; + auto result = generate_n(out_wrapper.begin(), ranges::distance(output), iota_gen); + STATIC_ASSERT(same_as>); + assert(result == out_wrapper.end()); + for (int i = 0; i < 3; ++i) { + assert(i == output[i]); + } + } + + constexpr int expected_output[] = {13, 42, 1367}; + int output[] = {13, 42, 1367}; + { + Out out_wrapper{output}; + auto result = generate_n(out_wrapper.begin(), 0, iota_gen); + STATIC_ASSERT(same_as>); + assert(result.peek() == output); + assert(equal(output, expected_output)); + } + { + Out out_wrapper{output}; + auto result = generate_n(out_wrapper.begin(), -1, iota_gen); + STATIC_ASSERT(same_as>); + assert(result.peek() == output); + assert(equal(output, expected_output)); + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +}