diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -53,7 +53,7 @@ Write,replace_if,Not assigned,n/a,Not started Write,replace_copy,Not assigned,n/a,Not started Write,replace_copy_if,Not assigned,n/a,Not started -Write,swap_ranges,Not assigned,n/a,Not started +Write,swap_ranges,Not assigned,n/a,Complete Write,reverse_copy,Not assigned,n/a,Not started Write,rotate_copy,Not assigned,n/a,Not started Write,sample,Not assigned,n/a,Not started diff --git a/libcxx/include/__algorithm/swap_ranges.h b/libcxx/include/__algorithm/swap_ranges.h --- a/libcxx/include/__algorithm/swap_ranges.h +++ b/libcxx/include/__algorithm/swap_ranges.h @@ -9,12 +9,17 @@ #ifndef _LIBCPP___ALGORITHM_SWAP_RANGES_H #define _LIBCPP___ALGORITHM_SWAP_RANGES_H +#include <__algorithm/in_in_result.h> #include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iter_swap.h> +#include <__ranges/concepts.h> +#include <__ranges/dangling.h> #include <__utility/swap.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header +# pragma GCC system_header #endif _LIBCPP_BEGIN_NAMESPACE_STD @@ -27,6 +32,49 @@ return __first2; } +#ifndef _LIBCPP_HAS_NO_RANGES + +namespace ranges { +template +using swap_ranges_result = in_in_result<_I1, _I2>; + +namespace __swap_ranges { +struct __fn { + template _S1, + input_iterator _I2, sentinel_for<_I2> _S2> + requires indirectly_swappable<_I1, _I2> + constexpr ranges::swap_ranges_result<_I1, _I2> operator()(_I1 __first1, _S1 __last1, + _I2 __first2, _S2 __last2) const + { + while (__first1 != __last1 && + __first2 != __last2) + { + ranges::iter_swap(__first1, __first2); + ++__first1; + ++__first2; + } + return {__first1, __first2}; + } + + template + requires indirectly_swappable, iterator_t<_R2>> + constexpr ranges::swap_ranges_result, borrowed_iterator_t<_R2>> + operator()(_R1&& __r1, _R2&& __r2) const + { + return operator()(ranges::begin(__r1), ranges::end(__r1), + ranges::begin(__r2), ranges::end(__r2)); + } +}; +} // namespace __swap_ranges + +inline namespace __cpo { + inline constexpr auto swap_ranges = __swap_ranges::__fn{}; +} // namespace __cpo +} // namespace ranges + +#endif // _LIBCPP_HAS_NO_RANGES + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___ALGORITHM_SWAP_RANGES_H diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -192,6 +192,16 @@ constexpr ForwardIterator2 // constexpr in C++20 swap_ranges(ForwardIterator1 first1, ForwardIterator1 last1, ForwardIterator2 first2); +template S1, input_­iterator I2, sentinel_­for S2> + requires indirectly_­swappable + constexpr ranges::swap_ranges_result + ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); + +template + requires indirectly_­swappable, iterator_t> + constexpr ranges::swap_ranges_result, borrowed_iterator_t> + ranges::swap_ranges(R1&& r1, R2&& r2); + template constexpr void // constexpr in C++20 iter_swap(ForwardIterator1 a, ForwardIterator2 b); @@ -649,14 +659,13 @@ */ +#include <__bits> // __libcpp_clz #include <__config> #include <__debug> -#include <__bits> // __libcpp_clz #include #include #include #include -#include // needed to provide swap_ranges. #include #include #include diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.swap/ranges.swap_ranges.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// template S1, input_­iterator I2, sentinel_­for S2> +// requires indirectly_­swappable +// constexpr ranges::swap_ranges_result +// ranges::swap_ranges(I1 first1, S1 last1, I2 first2, S2 last2); +// template +// requires indirectly_­swappable, iterator_t> +// constexpr ranges::swap_ranges_result, borrowed_iterator_t> +// ranges::swap_ranges(R1&& r1, R2&& r2); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +template +constexpr void test1() { + int i[3] = {1, 2, 3}; + int j[3] = {4, 5, 6}; + auto r = std::ranges::swap_ranges(Iter1(i), Iter1(i + 3), Iter2(j), Iter2(j + 3)); + ASSERT_SAME_TYPE(decltype(r), std::ranges::swap_ranges_result); + assert(base(r.in1) == i + 3); + assert(base(r.in2) == j + 3); + assert(i[0] == 4); + assert(i[1] == 5); + assert(i[2] == 6); + assert(j[0] == 1); + assert(j[1] == 2); + assert(j[2] == 3); +} + +constexpr bool tests1() { + test1, forward_iterator>(); + test1, bidirectional_iterator>(); + test1, random_access_iterator>(); + test1, int*>(); + + test1, forward_iterator>(); + test1, bidirectional_iterator>(); + test1, random_access_iterator>(); + test1, int*>(); + + test1, forward_iterator>(); + test1, bidirectional_iterator>(); + test1, random_access_iterator>(); + test1, int*>(); + + test1>(); + test1>(); + test1>(); + test1(); + + return true; +} + +template +constexpr void test2() { + Range r1 = {1, 2, 3}; + Range r2 = {4, 5, 6}; + + auto r = std::ranges::swap_ranges(r1, r2); + ASSERT_SAME_TYPE(decltype(r), std::ranges::in_in_result, std::ranges::iterator_t>); + assert(r.in1 == std::ranges::end(r1)); + assert(r.in2 == std::ranges::end(r2)); + + assert(r1[0] == 4); + assert(r1[1] == 5); + assert(r1[2] == 6); + assert(r2[0] == 1); + assert(r2[1] == 2); + assert(r2[2] == 3); +} + +constexpr bool tests2() { + test2>(); + test2(); + + return true; +} + +int main(int, char**) { + tests1(); + tests2(); + static_assert(tests1()); + static_assert(tests2()); + return 0; +}