diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7032aaf5d..ae9ed824d 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -3003,6 +3003,85 @@ _FwdIt2 replace_copy_if(_ExPo&&, _FwdIt1 _First, _FwdIt1 _Last, _FwdIt2 _Dest, _ } #endif // _HAS_CXX17 +#ifdef __cpp_lib_concepts +namespace ranges { + // VARIABLE ranges::fill + class _Fill_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _It, sentinel_for<_It> _Se> + constexpr _It operator()(_It _First, _Se _Last, const _Ty& _Value) const { + _Adl_verify_range(_First, _Last); + auto _UFirst = _Get_unwrapped(_STD move(_First)); + const auto _ULast = _Get_unwrapped(_STD move(_Last)); + if constexpr (_Fill_memset_is_safe) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + const auto _Distance = static_cast(_ULast - _UFirst); + _CSTD memset(_UFirst, static_cast(_Value), _Distance); + _UFirst += _Distance; + _Seek_wrapped(_First, _UFirst); + return _First; + } + } + + for (; _UFirst != _ULast; ++_UFirst) { + *_UFirst = _Value; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + return _First; + } + + template _Rng> + constexpr borrowed_iterator_t<_Rng> operator()(_Rng&& _Range, const _Ty& _Value) const { + auto _First = _RANGES begin(_Range); + _Seek_wrapped(_First, (*this)(_Get_unwrapped(_STD move(_First)), _Uend(_Range), _Value)); + return _First; + } + }; + + inline constexpr _Fill_fn fill{_Not_quite_object::_Construct_tag{}}; + + // VARIABLE ranges::fill_n + class _Fill_n_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + template _It> + constexpr _It operator()(_It _First, iter_difference_t<_It> _Count, const _Ty& _Value) const { + if (_Count > 0) { + auto _UFirst = _Get_unwrapped_n(_STD move(_First), _Count); + if constexpr (_Fill_memset_is_safe) { +#ifdef __cpp_lib_is_constant_evaluated + if (!_STD is_constant_evaluated()) +#endif // __cpp_lib_is_constant_evaluated + { + _CSTD memset(_UFirst, static_cast(_Value), static_cast(_Count)); + _UFirst += _Count; + _Seek_wrapped(_First, _UFirst); // no need to move since _UFirst is a pointer + return _First; + } + } + + for (; _Count > 0; ++_UFirst, (void) --_Count) { + *_UFirst = _Value; + } + + _Seek_wrapped(_First, _STD move(_UFirst)); + } + + return _First; + } + }; + + inline constexpr _Fill_n_fn fill_n{_Not_quite_object::_Construct_tag{}}; +} // namespace ranges +#endif // __cpp_lib_concepts + // FUNCTION TEMPLATE generate template _CONSTEXPR20 void generate(_FwdIt _First, _FwdIt _Last, _Fn _Func) { // replace [_First, _Last) with _Func() diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index daa8abd69..c02c977f5 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -807,6 +807,55 @@ struct with_input_ranges { } }; +template +struct with_output_ranges { + template + static constexpr void call() { + using namespace test; + + // For all ranges, IsCommon implies Eq. + // For single-pass ranges, Eq is uninteresting without IsCommon (there's only one valid iterator + // value at a time, and no reason to compare it with itself for equality). + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + Continuation::template call>(); + + with_forward_ranges::template call(); + } +}; + template struct with_input_iterators { template @@ -854,6 +903,11 @@ struct with_difference { } }; +template +constexpr void test_out() { + with_output_ranges::call(); +} + template constexpr void test_in() { with_input_ranges::call(); diff --git a/tests/std/test.lst b/tests/std/test.lst index 413f56a43..4d280bb4d 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -245,6 +245,8 @@ tests\P0896R4_ranges_alg_copy_n tests\P0896R4_ranges_alg_count tests\P0896R4_ranges_alg_count_if tests\P0896R4_ranges_alg_equal +tests\P0896R4_ranges_alg_fill +tests\P0896R4_ranges_alg_fill_n tests\P0896R4_ranges_alg_find tests\P0896R4_ranges_alg_find_end tests\P0896R4_ranges_alg_find_first_of diff --git a/tests/std/tests/P0896R4_ranges_alg_fill/env.lst b/tests/std/tests/P0896R4_ranges_alg_fill/env.lst new file mode 100644 index 000000000..f3ccc8613 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_fill/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_fill/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp new file mode 100644 index 000000000..b933a7b3b --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_fill/test.cpp @@ -0,0 +1,40 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +struct instantiator { + template + static constexpr void call() { + using ranges::fill; + { + int output[] = {13, 42, 1367}; + const int value = 7; + auto result = fill(ranges::begin(output), ranges::end(output), value); + for (const auto& elem : output) { + assert(elem == value); + } + assert(result == ranges::end(output)); + } + { // Validate ranges overload + int output[] = {13, 42, 1367}; + const int value = 13; + auto result = fill(output, value); + for (const auto& elem : output) { + assert(elem == value); + } + assert(result == ranges::end(output)); + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +} diff --git a/tests/std/tests/P0896R4_ranges_alg_fill_n/env.lst b/tests/std/tests/P0896R4_ranges_alg_fill_n/env.lst new file mode 100644 index 000000000..f3ccc8613 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_fill_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_fill_n/test.cpp b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp new file mode 100644 index 000000000..62b72bb01 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_fill_n/test.cpp @@ -0,0 +1,45 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include + +#include + +struct instantiator { + template + static constexpr void call() { + using ranges::fill_n; + + const int expected_output[] = {13, 42, 1367}; + const int value = 7; + { + int output[] = {13, 42, 1367}; + auto result = fill_n(ranges::begin(output), ranges::distance(output), value); + for (const auto& elem : output) { + assert(elem == value); + } + assert(result == ranges::end(output)); + } + { + int output[] = {13, 42, 1367}; + auto result = fill_n(ranges::begin(output), 0, value); + assert(ranges::equal(output, expected_output)); + assert(result == ranges::begin(output)); + } + { + int output[] = {13, 42, 1367}; + auto result = fill_n(ranges::begin(output), -1, value); + assert(ranges::equal(output, expected_output)); + assert(result == ranges::begin(output)); + } + } +}; + +int main() { + STATIC_ASSERT((test_out(), true)); + test_out(); +}