diff --git a/stl/inc/algorithm b/stl/inc/algorithm index 7032aaf5d91..72d749e4f28 100644 --- a/stl/inc/algorithm +++ b/stl/inc/algorithm @@ -2830,6 +2830,46 @@ namespace ranges { }; inline constexpr _Find_first_of_fn find_first_of{_Not_quite_object::_Construct_tag{}}; + + // ALIAS TEMPLATE swap_ranges_result + template + using swap_ranges_result = in_in_result<_In1, _In2>; + + // VARIABLE ranges::swap_ranges + class _Swap_ranges_fn : private _Not_quite_object { + public: + using _Not_quite_object::_Not_quite_object; + + // clang-format off + template _Se1, input_iterator _It2, sentinel_for<_It2> _Se2> + requires indirectly_swappable<_It1, _It2> + constexpr swap_ranges_result<_It1, _It2> operator()( + _It1 _First1, _Se1 _Last1, _It2 _First2, _Se2 _Last2) const { + _Adl_verify_range(_First1, _Last1); + _Adl_verify_range(_First2, _Last2); + auto _UFirst1 = _Get_unwrapped(_STD move(_First1)); + auto _ULast1 = _Get_unwrapped(_STD move(_Last1)); + auto _UFirst2 = _Get_unwrapped(_STD move(_First2)); + auto _ULast2 = _Get_unwrapped(_STD move(_Last2)); + for (; _UFirst1 != _ULast1 && _UFirst2 != _ULast2; ++_UFirst1, (void) ++_UFirst2) { + _RANGES iter_swap(_UFirst1, _UFirst2); + } + + _Seek_wrapped(_First1, _STD move(_UFirst1)); + _Seek_wrapped(_First2, _STD move(_UFirst2)); + return {_STD move(_First1), _STD move(_First2)}; + } + + template + requires indirectly_swappable, iterator_t<_Rng2>> + constexpr swap_ranges_result, borrowed_iterator_t<_Rng2>> operator()( + _Rng1&& _Range1, _Rng2&& _Range2) const { + return (*this)(_RANGES begin(_Range1), _RANGES end(_Range1), _RANGES begin(_Range2), _RANGES end(_Range2)); + } + // clang-format on + }; + + inline constexpr _Swap_ranges_fn swap_ranges{_Not_quite_object::_Construct_tag{}}; } // namespace ranges #endif // __cpp_lib_concepts diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index daa8abd69c0..c02c977f56a 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 413f56a4325..8f296b4a3c5 100644 --- a/tests/std/test.lst +++ b/tests/std/test.lst @@ -260,6 +260,7 @@ tests\P0896R4_ranges_alg_move tests\P0896R4_ranges_alg_none_of tests\P0896R4_ranges_alg_search tests\P0896R4_ranges_alg_search_n +tests\P0896R4_ranges_alg_swap_ranges tests\P0896R4_ranges_iterator_machinery tests\P0896R4_ranges_range_machinery tests\P0896R4_ranges_subrange diff --git a/tests/std/tests/P0896R4_ranges_alg_swap_ranges/env.lst b/tests/std/tests/P0896R4_ranges_alg_swap_ranges/env.lst new file mode 100644 index 00000000000..f3ccc8613c6 --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_swap_ranges/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_swap_ranges/test.cpp b/tests/std/tests/P0896R4_ranges_alg_swap_ranges/test.cpp new file mode 100644 index 00000000000..6f2bc96611f --- /dev/null +++ b/tests/std/tests/P0896R4_ranges_alg_swap_ranges/test.cpp @@ -0,0 +1,66 @@ +// Copyright (c) Microsoft Corporation. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception + +#include +#include +#include +#include +#include +#include + +#include + +constexpr void smoke_test() { + using ranges::swap_ranges, ranges::swap_ranges_result, ranges::iterator_t; + using std::same_as; + using I1 = iterator_t>; + + // Validate that swap_ranges_result aliases in_in_result + STATIC_ASSERT(same_as, ranges::in_in_result>); + + { // Validate ranges overload + using R = std::array; + R range1 = {13, 53, 1876}; + R range2 = {34, 243, 9366}; + int const expected_output1[] = {34, 243, 9366}; + int const expected_output2[] = {13, 53, 1876}; + auto result = swap_ranges(basic_borrowed_range{range1}, basic_borrowed_range{range2}); + STATIC_ASSERT(same_as>); + assert(result.in1 == basic_borrowed_range{range1}.end()); + assert(result.in2 == basic_borrowed_range{range2}.end()); + assert(ranges::equal(range1, expected_output1)); + assert(ranges::equal(range2, expected_output2)); + } + { // Validate iterator + sentinel overload + int range1[] = {13, 53, 1876}; + int range2[] = {34, 243, 9366}; + basic_borrowed_range wrapped_range1{range1}; + basic_borrowed_range wrapped_range2{range2}; + int const expected_output1[] = {34, 243, 9366}; + int const expected_output2[] = {13, 53, 1876}; + auto result = + swap_ranges(wrapped_range1.begin(), wrapped_range1.end(), wrapped_range2.begin(), wrapped_range2.end()); + STATIC_ASSERT(same_as>); + assert(result.in1 == wrapped_range1.end()); + assert(result.in2 == wrapped_range2.end()); + assert(ranges::equal(range1, expected_output1)); + assert(ranges::equal(range2, expected_output2)); + } +} + +int main() { +#if defined(__clang__) || defined(__EDG__) // TRANSITION, VSO-938163 + STATIC_ASSERT((smoke_test(), true)); +#endif // TRANSITION, VSO-938163 + smoke_test(); +} + +struct instantiator { + template + static void call(In1 in1 = {}, In2 in2 = {}) { + (void) ranges::swap_ranges(in1, in2); + (void) ranges::swap_ranges(ranges::begin(in1), ranges::end(in1), ranges::begin(in2), ranges::end(in2)); + } +}; + +template void test_in_in();