From e0800f119e62a03c9e1c2e494f98a758bf6a0312 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 27 Feb 2024 23:47:20 -0800 Subject: [PATCH 01/25] [libc++][ranges] implement ranges::shift_left --- libcxx/include/CMakeLists.txt | 1 + .../include/__algorithm/ranges_shift_left.h | 68 +++++++++++++++++++ libcxx/include/__algorithm/shift_left.h | 36 ++++++---- libcxx/include/algorithm | 8 +++ libcxx/include/libcxx.imp | 1 + libcxx/include/module.modulemap.in | 1 + libcxx/modules/std/algorithm.inc | 2 +- ...es_robust_against_proxy_iterators.pass.cpp | 3 + .../niebloid.compile.pass.cpp | 3 + 9 files changed, 109 insertions(+), 14 deletions(-) create mode 100644 libcxx/include/__algorithm/ranges_shift_left.h diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index cafd8c6e00d96..22929225fff72 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -183,6 +183,7 @@ set(files __algorithm/ranges_set_intersection.h __algorithm/ranges_set_symmetric_difference.h __algorithm/ranges_set_union.h + __algorithm/ranges_shift_left.h __algorithm/ranges_shuffle.h __algorithm/ranges_sort.h __algorithm/ranges_sort_heap.h diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h new file mode 100644 index 0000000000000..bf82ce3269382 --- /dev/null +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___ALGORITHM_RANGES_SHIFT_LEFT_H +#define _LIBCPP___ALGORITHM_RANGES_SHIFT_LEFT_H + +#include <__algorithm/shift_left.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/permutable.h> +#include <__ranges/concepts.h> +#include <__ranges/subrange.h> +#include <__utility/move.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +#if _LIBCPP_STD_VER >= 23 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { +namespace __shift_left { + +struct __fn { + template + _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> static __shift_left_impl( + _Iter __first, _Sent __last, iter_difference_t<_Iter> __n) { + auto __ret = std::__shift_left<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__n)); + return {std::move(__ret.first), std::move(__ret.second)}; + } + + template _Sent> + _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) const { + return __shift_left_impl(std::move(__first), std::move(__last), std::move(__n)); + } + + template < forward_range _Range> + _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, range_difference_t<_Range> __n) const { + return __shift_left_impl(ranges::begin(__range), ranges::end(__range), std::move(__n)); + } +}; + +} // namespace __shift_left + +inline namespace __cpo { +inline constexpr auto shift_left = __shift_left::__fn{}; +} // namespace __cpo +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER == 23 + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___ALGORITHM_RANGES_SHIFT_LEFT_H diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 06cd7c5f87644..e6b8153ecebec 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -24,30 +24,40 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 -template -inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator -shift_left(_ForwardIterator __first, - _ForwardIterator __last, - typename iterator_traits<_ForwardIterator>::difference_type __n) { +template +inline _LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> +__shift_left(_Iter __first, _Sent __last, typename iterator_traits<_Iter>::difference_type __n) { + _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); + if (__n == 0) { - return __last; + return {std::move(__first), std::move(__end)}; } - _ForwardIterator __m = __first; - if constexpr (__has_random_access_iterator_category<_ForwardIterator>::value) { - if (__n >= __last - __first) { - return __first; + _Iter __m = __first; + if constexpr (__has_random_access_iterator_category<_Iter>::value) { + if (__n >= __end - __first) { + return {std::move(__first), std::move(__first)}; } __m += __n; } else { for (; __n > 0; --__n) { - if (__m == __last) { - return __first; + if (__m == __end) { + return {std::move(__first), std::move(__first)}; } ++__m; } } - return std::move(__m, __last, __first); + + _Iter __result = std::__move<_AlgPolicy>(__m, __end, __first).second; + return {std::move(__first), std::move(__result)}; +} + +template +inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator +shift_left(_ForwardIterator __first, + _ForwardIterator __last, + typename iterator_traits<_ForwardIterator>::difference_type __n) { + return std::__shift_left<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __n).second; } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/algorithm b/libcxx/include/algorithm index 70e30bc87e812..d9b4e87a8a2ad 100644 --- a/libcxx/include/algorithm +++ b/libcxx/include/algorithm @@ -843,6 +843,13 @@ namespace ranges { uniform_random_bit_generator> O sample(R&& r, O out, range_difference_t n, Gen&& g); // since C++20 + template S> + constexpr subrange ranges::shift_left(I first, S last, iter_difference_t n); // since C++23 + + template + requires permutable> + constexpr borrowed_subrange_t ranges::shift_left(R&& r, range_difference_t n) // since C++23 + template S, class Gen> requires permutable && uniform_random_bit_generator> @@ -1960,6 +1967,7 @@ template #include <__algorithm/ranges_set_intersection.h> #include <__algorithm/ranges_set_symmetric_difference.h> #include <__algorithm/ranges_set_union.h> +#include <__algorithm/ranges_shift_left.h> #include <__algorithm/ranges_shuffle.h> #include <__algorithm/ranges_sort.h> #include <__algorithm/ranges_sort_heap.h> diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp index 22fbea99b848b..1af11eba2d260 100644 --- a/libcxx/include/libcxx.imp +++ b/libcxx/include/libcxx.imp @@ -183,6 +183,7 @@ { include: [ "<__algorithm/ranges_set_intersection.h>", "private", "", "public" ] }, { include: [ "<__algorithm/ranges_set_symmetric_difference.h>", "private", "", "public" ] }, { include: [ "<__algorithm/ranges_set_union.h>", "private", "", "public" ] }, + { include: [ "<__algorithm/ranges_shift_left.h>", "private", "", "public" ] }, { include: [ "<__algorithm/ranges_shuffle.h>", "private", "", "public" ] }, { include: [ "<__algorithm/ranges_sort.h>", "private", "", "public" ] }, { include: [ "<__algorithm/ranges_sort_heap.h>", "private", "", "public" ] }, diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 219906aa9a566..def640397570d 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -987,6 +987,7 @@ module std_private_algorithm_ranges_set_union [system export std_private_algorithm_in_in_out_result export std_private_functional_ranges_operations } +module std_private_algorithm_ranges_shift_left [system] { header "__algorithm/ranges_shift_left.h" } module std_private_algorithm_ranges_shuffle [system] { header "__algorithm/ranges_shuffle.h" } module std_private_algorithm_ranges_sort [system] { header "__algorithm/ranges_sort.h" diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc index e7796bfa26af8..0a4e1c1ba6cc9 100644 --- a/libcxx/modules/std/algorithm.inc +++ b/libcxx/modules/std/algorithm.inc @@ -354,7 +354,7 @@ export namespace std { using std::shift_left; namespace ranges { - // using std::ranges::shift_left; + using std::ranges::shift_left; } using std::shift_right; diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp index 139f1999bc9dc..c64945e34994d 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp @@ -154,6 +154,9 @@ constexpr void run_tests() { test(std::ranges::remove_if, in, unary_pred); test(std::ranges::reverse, in); test_mid(std::ranges::rotate, in, mid); +#if TEST_STD_VER >= 23 + test(std::ranges::shift_left, in, count); +#endif if (!std::is_constant_evaluated()) // `shuffle` isn't `constexpr`. test(std::ranges::shuffle, in, rand_gen()); if (!std::is_constant_evaluated()) { diff --git a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp index 9506ca1c768bd..886d112b5276d 100644 --- a/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp +++ b/libcxx/test/std/library/description/conventions/customization.point.object/niebloid.compile.pass.cpp @@ -146,6 +146,9 @@ static_assert(test(std::ranges::set_difference, a, a, a)); static_assert(test(std::ranges::set_intersection, a, a, a)); static_assert(test(std::ranges::set_symmetric_difference, a, a, a)); static_assert(test(std::ranges::set_union, a, a, a)); +#if TEST_STD_VER >= 23 +static_assert(test(std::ranges::shift_left, a, 42)); +#endif static_assert(test(std::ranges::shuffle, a, g)); static_assert(test(std::ranges::sort, a)); static_assert(test(std::ranges::sort_heap, a)); From 68a86357dee32a6958fa1e8e89940c7ca354277b Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 00:30:35 -0800 Subject: [PATCH 02/25] [libc++][ranges] format code with 'clang-format' --- .../algorithms/ranges_robust_against_proxy_iterators.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp index c64945e34994d..92b224e427ab3 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp @@ -155,7 +155,7 @@ constexpr void run_tests() { test(std::ranges::reverse, in); test_mid(std::ranges::rotate, in, mid); #if TEST_STD_VER >= 23 - test(std::ranges::shift_left, in, count); + test(std::ranges::shift_left, in, count); #endif if (!std::is_constant_evaluated()) // `shuffle` isn't `constexpr`. test(std::ranges::shuffle, in, rand_gen()); From ade17074240be5093dd83bc53b277e505152f213 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 11:28:07 -0800 Subject: [PATCH 03/25] [libc++][ranges] check '_LIBCPP_STD_VER' in 'algorithm.inc' --- libcxx/modules/std/algorithm.inc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/modules/std/algorithm.inc b/libcxx/modules/std/algorithm.inc index 0a4e1c1ba6cc9..2364899c1e031 100644 --- a/libcxx/modules/std/algorithm.inc +++ b/libcxx/modules/std/algorithm.inc @@ -353,9 +353,11 @@ export namespace std { // [alg.shift], shift using std::shift_left; +#if _LIBCPP_STD_VER >= 23 namespace ranges { using std::ranges::shift_left; } +#endif // _LIBCPP_STD_VER >= 23 using std::shift_right; From c84792977c9ed053915e27097e0c7f9d03d99d2b Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 11:54:13 -0800 Subject: [PATCH 04/25] [libc++][ranges] add missing headers to 'shift_left.h' and 'ranges_shift_left.h' --- libcxx/include/__algorithm/ranges_shift_left.h | 1 + libcxx/include/__algorithm/shift_left.h | 1 + 2 files changed, 2 insertions(+) diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h index bf82ce3269382..4595fc7d7031e 100644 --- a/libcxx/include/__algorithm/ranges_shift_left.h +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -16,6 +16,7 @@ #include <__ranges/concepts.h> #include <__ranges/subrange.h> #include <__utility/move.h> +#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index e6b8153ecebec..01d9f1c035f36 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -9,6 +9,7 @@ #ifndef _LIBCPP___ALGORITHM_SHIFT_LEFT_H #define _LIBCPP___ALGORITHM_SHIFT_LEFT_H +#include <__algorithm/iterator_operations.h> #include <__algorithm/move.h> #include <__config> #include <__iterator/iterator_traits.h> From 40691ad54b3dc1d30b1edf93138c7adfaa2ab8cc Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 12:33:50 -0800 Subject: [PATCH 05/25] [libc++][ranges] add missing headers to 'shift_left.h' --- libcxx/include/__algorithm/shift_left.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 01d9f1c035f36..8df1bff87f042 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -13,6 +13,7 @@ #include <__algorithm/move.h> #include <__config> #include <__iterator/iterator_traits.h> +#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header From 4de17871d76a7a390f127962ed6036ea233496d7 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 12:34:21 -0800 Subject: [PATCH 06/25] [libc++][ranges] add missing constraints to 'ranges_shift_left.h' --- libcxx/include/__algorithm/ranges_shift_left.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h index 4595fc7d7031e..bee3e865c87ed 100644 --- a/libcxx/include/__algorithm/ranges_shift_left.h +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -46,7 +46,8 @@ struct __fn { return __shift_left_impl(std::move(__first), std::move(__last), std::move(__n)); } - template < forward_range _Range> + template + requires permutable> _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> operator()(_Range&& __range, range_difference_t<_Range> __n) const { return __shift_left_impl(ranges::begin(__range), ranges::end(__range), std::move(__n)); @@ -62,7 +63,7 @@ inline constexpr auto shift_left = __shift_left::__fn{}; _LIBCPP_END_NAMESPACE_STD -#endif // _LIBCPP_STD_VER == 23 +#endif // _LIBCPP_STD_VER >= 23 _LIBCPP_POP_MACROS From 02a20d966ee090a749d88c22f346210f26d666af Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 12:38:39 -0800 Subject: [PATCH 07/25] [libc++][ranges] format code with 'clang-format' --- libcxx/include/__algorithm/ranges_shift_left.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h index bee3e865c87ed..9a0cd3a4223c0 100644 --- a/libcxx/include/__algorithm/ranges_shift_left.h +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -47,7 +47,7 @@ struct __fn { } template - requires permutable> + requires permutable> _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> operator()(_Range&& __range, range_difference_t<_Range> __n) const { return __shift_left_impl(ranges::begin(__range), ranges::end(__range), std::move(__n)); From 9bd0eacf41c05c531e69c8bd920c5f0f54cffdc0 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 16:03:17 -0800 Subject: [PATCH 08/25] [libc++][ranges] add missing headers to 'ranges_shift_left.h' --- libcxx/include/__algorithm/ranges_shift_left.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h index 9a0cd3a4223c0..d9edf661d1d8c 100644 --- a/libcxx/include/__algorithm/ranges_shift_left.h +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -9,10 +9,13 @@ #ifndef _LIBCPP___ALGORITHM_RANGES_SHIFT_LEFT_H #define _LIBCPP___ALGORITHM_RANGES_SHIFT_LEFT_H +#include <__algorithm/iterator_operations.h> #include <__algorithm/shift_left.h> #include <__config> #include <__iterator/concepts.h> +#include <__iterator/incrementable_traits.h> #include <__iterator/permutable.h> +#include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/subrange.h> #include <__utility/move.h> From 7747973ecca54399cebb000beb039bf044523a6c Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 18:44:12 -0800 Subject: [PATCH 09/25] [libc++][ranges] implement 'ranges.shift_left.pass.cpp' to test 'ranges::shift_left.h' --- .../alg.shift/ranges.shift_left.pass.cpp | 194 ++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp new file mode 100644 index 0000000000000..38ef57d3bca00 --- /dev/null +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp @@ -0,0 +1,194 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 + +// template S> +// constexpr subrange ranges::shift_left(I first, S last, iter_difference_t n); + +// template +// requires permutable> +// constexpr borrowed_subrange_t ranges::shift_left(R&& r, range_difference_t n) + +#include +#include +#include +#include + +#include "almost_satisfies_types.h" +#include "test_iterators.h" +#include "MoveOnly.h" + +template +concept HasShiftLeftIt = requires(Iter iter, Sent sent, Count n) { std::ranges::shift_left(iter, sent, n); }; + +static_assert(HasShiftLeftIt); +static_assert(!HasShiftLeftIt); +static_assert(!HasShiftLeftIt); +static_assert(!HasShiftLeftIt); + +template +concept HasShiftLeftR = requires(Range range, Count n) { std::ranges::shift_left(range, n); }; + +static_assert(HasShiftLeftR>); +static_assert(!HasShiftLeftR); +static_assert(!HasShiftLeftR); +static_assert(!HasShiftLeftR); + +template +constexpr void test_iter_sent() { + { + const std::array original = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9}; + std::array scratch; + + // (iterator, sentinel) overload + for (size_t n = 0; n <= 15; ++n) { + for (size_t k = 0; k <= n + 2; ++k) { + auto begin = Iter(scratch.data()); + auto end = Sent(Iter(scratch.data() + n)); + std::ranges::copy(original.begin(), original.begin() + n, begin); + auto result = std::ranges::shift_left(begin, end, k); + + assert(result.begin() == begin); + if (k < n) { + assert(result.end() == Iter(scratch.data() + n - k)); + assert(std::ranges::equal(original.begin() + k, original.begin() + n, result.begin(), result.end())); + } else { + assert(result.end() == begin); + assert(std::ranges::equal(original.begin(), original.begin() + n, begin, end)); + } + } + } + + // (range) overload + for (size_t n = 0; n <= 15; ++n) { + for (size_t k = 0; k <= n + 2; ++k) { + auto begin = Iter(scratch.data()); + auto end = Sent(Iter(scratch.data() + n)); + std::ranges::copy(original.begin(), original.begin() + n, begin); + auto range = std::ranges::subrange(begin, end); + auto result = std::ranges::shift_left(range, k); + + assert(result.begin() == begin); + if (k < n) { + assert(result.end() == Iter(scratch.data() + n - k)); + assert(std::ranges::equal(original.begin() + k, original.begin() + n, begin, result.end())); + } else { + assert(result.end() == begin); + assert(std::ranges::equal(original.begin(), original.begin() + n, begin, end)); + } + } + } + } + + // n == 0 + { + std::array input = {0, 1, 2}; + const std::array expected = {0, 1, 2}; + + { // (iterator, sentinel) overload + auto in = input; + auto begin = Iter(in.data()); + auto end = Sent(Iter(in.data() + in.size())); + auto result = std::ranges::shift_left(begin, end, 0); + assert(std::ranges::equal(expected, result)); + assert(result.begin() == begin); + assert(result.end() == end); + } + + { // (range) overload + auto in = input; + auto begin = Iter(in.data()); + auto end = Sent(Iter(in.data() + in.size())); + auto range = std::ranges::subrange(begin, end); + auto result = std::ranges::shift_left(range, 0); + assert(std::ranges::equal(expected, result)); + assert(result.begin() == begin); + assert(result.end() == end); + } + } + + // n == len + { + std::array input = {0, 1, 2}; + const std::array expected = {0, 1, 2}; + + { // (iterator, sentinel) overload + auto in = input; + auto begin = Iter(in.data()); + auto end = Sent(Iter(in.data() + in.size())); + auto result = std::ranges::shift_left(begin, end, input.size()); + assert(std::ranges::equal(expected, input)); + assert(result.begin() == begin); + assert(result.end() == begin); + } + + { // (range) overload + auto in = input; + auto begin = Iter(in.data()); + auto end = Sent(Iter(in.data() + in.size())); + auto range = std::ranges::subrange(begin, end); + auto result = std::ranges::shift_left(range, input.size()); + assert(std::ranges::equal(expected, input)); + assert(result.begin() == begin); + assert(result.end() == begin); + } + } + + // n > len + { + std::array input = {0, 1, 2}; + const std::array expected = {0, 1, 2}; + + { // (iterator, sentinel) overload + auto in = input; + auto begin = Iter(in.data()); + auto end = Sent(Iter(in.data() + in.size())); + auto result = std::ranges::shift_left(begin, end, input.size() + 1); + assert(std::ranges::equal(expected, input)); + assert(result.begin() == begin); + assert(result.end() == begin); + } + + { // (range) overload + auto in = input; + auto begin = Iter(in.data()); + auto end = Sent(Iter(in.data() + in.size())); + auto range = std::ranges::subrange(begin, end); + auto result = std::ranges::shift_left(range, input.size() + 1); + assert(std::ranges::equal(expected, input)); + assert(result.begin() == begin); + assert(result.end() == begin); + } + } +} + +template +constexpr void test_iter() { + test_iter_sent(); + test_iter_sent>(); + test_iter_sent>(); +} + +constexpr bool test() { + test_iter>(); + test_iter>(); + test_iter>(); + test_iter>(); + test_iter(); + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} From aa1f598453e5a586e18c46993baa0cc5327effd9 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 18:50:42 -0800 Subject: [PATCH 10/25] [libc++][ranges] update the implementation status of 'P2440R1' --- libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/docs/Status/RangesAlgorithms.csv | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index eb415ed8c031f..5232d24f66ab6 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","LWG","A type trait to detect reference binding to temporary","February 2022","","" "`P2273R3 `__","LWG","Making ``std::unique_ptr`` constexpr","February 2022","|Complete|","16.0" "`P2387R3 `__","LWG","Pipe support for user-defined range adaptors","February 2022","","","|ranges|" -"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|" +"`P2440R1 `__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","|In progress|","","|ranges|" "`P2441R2 `__","LWG","``views::join_with``","February 2022","|In Progress|","","|ranges|" "`P2442R1 `__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|" "`P2443R1 `__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|" diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv index f7a51f732c4b1..1d9582373ea8a 100644 --- a/libcxx/docs/Status/RangesAlgorithms.csv +++ b/libcxx/docs/Status/RangesAlgorithms.csv @@ -5,7 +5,7 @@ C++23,`find_last_if `_,Unassigned,No patch yet,Not st C++23,`find_last_if_not `_,Unassigned,No patch yet,Not started C++23,`starts_with `_,Zijun Zhao,`D150735 `_,Complete C++23,`ends_with `_,Zijun Zhao, `D150831 `_,Complete -C++23,`shift_left `_,Unassigned,No patch yet,Not started +C++23,`shift_left `_,Xiaoyang Liu,`83231 `,✅ C++23,`shift_right `_,Unassigned,No patch yet,Not started C++23,`iota (algorithm) `_,Unassigned,No patch yet,Not started C++23,`fold `_,Unassigned,No patch yet,Not started From a68eb0265cfc3851221fd77ab2e71e4cb020c145 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 19:37:13 -0800 Subject: [PATCH 11/25] [libc++][ranges] attempt to reduce the steps required for 'constexpr' evaluation in 'ranges.shift_left.pass.cpp' --- .../alg.shift/ranges.shift_left.pass.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp index 38ef57d3bca00..2e664e47a17e2 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp @@ -45,11 +45,11 @@ static_assert(!HasShiftLeftR); template constexpr void test_iter_sent() { { - const std::array original = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5, 8, 9, 7, 9}; - std::array scratch; + const std::array original = {3, 1, 4, 1, 5, 9, 2, 6}; + std::array scratch; // (iterator, sentinel) overload - for (size_t n = 0; n <= 15; ++n) { + for (size_t n = 0; n <= original.size(); ++n) { for (size_t k = 0; k <= n + 2; ++k) { auto begin = Iter(scratch.data()); auto end = Sent(Iter(scratch.data() + n)); From 020a097ceb2079471d25ffcba7fb17a0ded98e70 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Wed, 28 Feb 2024 20:58:56 -0800 Subject: [PATCH 12/25] [libc++][ranges] fix an out-of-bounds access in 'ranges.shift_left.pass.cpp' --- .../alg.shift/ranges.shift_left.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp index 2e664e47a17e2..485a729fea50f 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp @@ -68,7 +68,7 @@ constexpr void test_iter_sent() { } // (range) overload - for (size_t n = 0; n <= 15; ++n) { + for (size_t n = 0; n <= original.size(); ++n) { for (size_t k = 0; k <= n + 2; ++k) { auto begin = Iter(scratch.data()); auto end = Sent(Iter(scratch.data() + n)); From e79f6430c5da5f95211ffb8df257bb436f8e63fd Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 3 Mar 2024 17:29:39 -0800 Subject: [PATCH 13/25] [libc++][ranges] refactor '__shift_left' to avoid redundant iteration --- libcxx/include/__algorithm/shift_left.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 8df1bff87f042..f609fc9cdc253 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -27,30 +27,30 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 template -inline _LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> -__shift_left(_Iter __first, _Sent __last, typename iterator_traits<_Iter>::difference_type __n) { - _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); - +_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> +__shift_left(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) { if (__n == 0) { + _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); return {std::move(__first), std::move(__end)}; } _Iter __m = __first; - if constexpr (__has_random_access_iterator_category<_Iter>::value) { - if (__n >= __end - __first) { + if constexpr (sized_sentinel_for<_Sent, _Iter>) { + auto __size = _IterOps<_AlgPolicy>::distance(__first, __last); + if (__n >= __size) { return {std::move(__first), std::move(__first)}; } - __m += __n; + _IterOps<_AlgPolicy>::advance(__m, __n); } else { for (; __n > 0; --__n) { - if (__m == __end) { + if (__m == __last) { return {std::move(__first), std::move(__first)}; } ++__m; } } - _Iter __result = std::__move<_AlgPolicy>(__m, __end, __first).second; + _Iter __result = std::__move<_AlgPolicy>(__m, __last, __first).second; return {std::move(__first), std::move(__result)}; } From 357f4eba5fa1157ff18c285aa108d345eef245e3 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Sun, 3 Mar 2024 17:32:42 -0800 Subject: [PATCH 14/25] [libc++][ranges] refactor 'ranges::shift_left' --- .../include/__algorithm/ranges_shift_left.h | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h index d9edf661d1d8c..439d4955edfa6 100644 --- a/libcxx/include/__algorithm/ranges_shift_left.h +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -36,24 +36,19 @@ namespace ranges { namespace __shift_left { struct __fn { - template - _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> static __shift_left_impl( - _Iter __first, _Sent __last, iter_difference_t<_Iter> __n) { + template _Sent> + _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Iter> + operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) { auto __ret = std::__shift_left<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__n)); return {std::move(__ret.first), std::move(__ret.second)}; } - template _Sent> - _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter> - operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) const { - return __shift_left_impl(std::move(__first), std::move(__last), std::move(__n)); - } - template requires permutable> - _LIBCPP_HIDE_FROM_ABI constexpr borrowed_subrange_t<_Range> - operator()(_Range&& __range, range_difference_t<_Range> __n) const { - return __shift_left_impl(ranges::begin(__range), ranges::end(__range), std::move(__n)); + _LIBCPP_HIDE_FROM_ABI static constexpr borrowed_subrange_t<_Range> + operator()(_Range&& __range, range_difference_t<_Range> __n) { + auto __ret = std::__shift_left<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), std::move(__n)); + return {std::move(__ret.first), std::move(__ret.second)}; } }; From c2fc0dc06986a94daf309b64622d0938dd7788e9 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Mon, 4 Mar 2024 22:09:03 -0800 Subject: [PATCH 15/25] [libc++][ranges] check the precondition in '__shift_left' --- libcxx/include/__algorithm/shift_left.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index f609fc9cdc253..3e020052d0373 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -29,6 +29,8 @@ _LIBCPP_BEGIN_NAMESPACE_STD template _LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> __shift_left(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) { + _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0, "__n must be greater than or equal to 0"); + if (__n == 0) { _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); return {std::move(__first), std::move(__end)}; From e2aa538f7705399dc7299a78cf3d5afcd0f51112 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Mon, 4 Mar 2024 22:27:04 -0800 Subject: [PATCH 16/25] [libc++][ranges] refactor 'ranges.shift_left.pass.cpp' --- .../alg.shift/ranges.shift_left.pass.cpp | 27 +++++++------------ 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp index 485a729fea50f..70a909736b841 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -26,16 +27,16 @@ #include "test_iterators.h" #include "MoveOnly.h" -template -concept HasShiftLeftIt = requires(Iter iter, Sent sent, Count n) { std::ranges::shift_left(iter, sent, n); }; +template +concept HasShiftLeftIt = requires(Iter iter, Sent sent, std::size_t n) { std::ranges::shift_left(iter, sent, n); }; static_assert(HasShiftLeftIt); static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); -template -concept HasShiftLeftR = requires(Range range, Count n) { std::ranges::shift_left(range, n); }; +template +concept HasShiftLeftR = requires(Range range, std::size_t n) { std::ranges::shift_left(range, n); }; static_assert(HasShiftLeftR>); static_assert(!HasShiftLeftR); @@ -170,25 +171,17 @@ constexpr void test_iter_sent() { } } -template -constexpr void test_iter() { - test_iter_sent(); - test_iter_sent>(); - test_iter_sent>(); -} - constexpr bool test() { - test_iter>(); - test_iter>(); - test_iter>(); - test_iter>(); - test_iter(); + types::for_each(types::forward_iterator_list{}, [] { + test_iter_sent(); + test_iter_sent>(); + test_iter_sent>(); + }); return true; } int main(int, char**) { test(); static_assert(test()); - return 0; } From 7cde5862eb72e8236385aa30dd2cd44f2a364762 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 5 Mar 2024 18:46:22 -0800 Subject: [PATCH 17/25] [libc++][ranges] add missing headers to 'shift_left.h' --- libcxx/include/__algorithm/shift_left.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 3e020052d0373..cfab41e56c2c8 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -11,6 +11,7 @@ #include <__algorithm/iterator_operations.h> #include <__algorithm/move.h> +#include <__assert> #include <__config> #include <__iterator/iterator_traits.h> #include <__utility/pair.h> From ead91b59531b9bfc5d328799965820d405ab408d Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 5 Mar 2024 19:20:46 -0800 Subject: [PATCH 18/25] [libc++][ranges] add benchmark for 'ranges::shift_left' --- libcxx/benchmarks/CMakeLists.txt | 1 + .../algorithms/ranges_shift_left.bench.cpp | 67 +++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt index b436e96f178b7..6dc3dda3c4b2b 100644 --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -191,6 +191,7 @@ set(BENCHMARK_TESTS algorithms/ranges_make_heap_then_sort_heap.bench.cpp algorithms/ranges_pop_heap.bench.cpp algorithms/ranges_push_heap.bench.cpp + algorithms/ranges_shift_left.bench.cpp algorithms/ranges_sort.bench.cpp algorithms/ranges_sort_heap.bench.cpp algorithms/ranges_stable_sort.bench.cpp diff --git a/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp b/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp new file mode 100644 index 0000000000000..5998ed6a71471 --- /dev/null +++ b/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include +#include +#include +#include + +#include "test_iterators.h" + +static void bm_shift_left_random_access_range_with_sized_sentinel(benchmark::State& state) { + std::vector a(state.range(), 1); + + for (auto _ : state) { + benchmark::DoNotOptimize(a); + + auto begin = random_access_iterator(a.data()); + auto end = random_access_iterator(a.data() + a.size()); + + static_assert(std::sized_sentinel_for); + static_assert(std::random_access_iterator); + + benchmark::DoNotOptimize(std::ranges::shift_left(begin, end, a.size() / 2)); + } +} +BENCHMARK(bm_shift_left_random_access_range_with_sized_sentinel)->RangeMultiplier(16)->Range(16, 16 << 20); + +static void bm_shift_left_forward_range_with_sized_sentinel(benchmark::State& state) { + std::vector a(state.range(), 1); + + for (auto _ : state) { + benchmark::DoNotOptimize(a); + + auto begin = forward_iterator(a.data()); + auto end = sized_sentinel(forward_iterator(a.data() + a.size())); + + static_assert(std::sized_sentinel_for); + static_assert(!std::random_access_iterator); + + benchmark::DoNotOptimize(std::ranges::shift_left(begin, end, a.size() / 2)); + } +} +BENCHMARK(bm_shift_left_forward_range_with_sized_sentinel)->RangeMultiplier(16)->Range(16, 16 << 20); + +static void bm_shift_left_forward_range(benchmark::State& state) { + std::vector a(state.range(), 1); + + for (auto _ : state) { + benchmark::DoNotOptimize(a); + + auto begin = forward_iterator(a.data()); + auto end = forward_iterator(a.data() + a.size()); + + static_assert(!std::sized_sentinel_for); + static_assert(!std::random_access_iterator); + + benchmark::DoNotOptimize(std::ranges::shift_left(begin, end, a.size() / 2)); + } +} +BENCHMARK(bm_shift_left_forward_range)->RangeMultiplier(16)->Range(16, 16 << 20); + +BENCHMARK_MAIN(); From e1360e07de5392f5db5ca6c35903892dda4f1ee8 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 5 Mar 2024 19:26:04 -0800 Subject: [PATCH 19/25] [libc++][ranges] add benchmark for 'ranges::shift_left' --- libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp b/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp index 5998ed6a71471..8f20f87f55866 100644 --- a/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp +++ b/libcxx/benchmarks/algorithms/ranges_shift_left.bench.cpp @@ -22,8 +22,8 @@ static void bm_shift_left_random_access_range_with_sized_sentinel(benchmark::Sta auto begin = random_access_iterator(a.data()); auto end = random_access_iterator(a.data() + a.size()); - static_assert(std::sized_sentinel_for); static_assert(std::random_access_iterator); + static_assert(std::sized_sentinel_for); benchmark::DoNotOptimize(std::ranges::shift_left(begin, end, a.size() / 2)); } @@ -39,8 +39,8 @@ static void bm_shift_left_forward_range_with_sized_sentinel(benchmark::State& st auto begin = forward_iterator(a.data()); auto end = sized_sentinel(forward_iterator(a.data() + a.size())); - static_assert(std::sized_sentinel_for); static_assert(!std::random_access_iterator); + static_assert(std::sized_sentinel_for); benchmark::DoNotOptimize(std::ranges::shift_left(begin, end, a.size() / 2)); } @@ -56,8 +56,8 @@ static void bm_shift_left_forward_range(benchmark::State& state) { auto begin = forward_iterator(a.data()); auto end = forward_iterator(a.data() + a.size()); - static_assert(!std::sized_sentinel_for); static_assert(!std::random_access_iterator); + static_assert(!std::sized_sentinel_for); benchmark::DoNotOptimize(std::ranges::shift_left(begin, end, a.size() / 2)); } From be2162db213d487a8c39effb1ee8d30c2f793c5c Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 24 Dec 2024 13:02:07 -0500 Subject: [PATCH 20/25] [libc++][ranges] implement 'ranges::shift_left' --- libcxx/docs/Status/Cxx23Papers.csv | 2 +- libcxx/test/benchmarks/algorithms/ranges_shift_left.bench.cpp | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv index 93b95d4aff39f..7fbccaad2fa99 100644 --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -46,7 +46,7 @@ "`P2255R2 `__","A type trait to detect reference binding to temporary","2022-02 (Virtual)","","","" "`P2273R3 `__","Making ``std::unique_ptr`` constexpr","2022-02 (Virtual)","|Complete|","16","" "`P2387R3 `__","Pipe support for user-defined range adaptors","2022-02 (Virtual)","|Complete|","19","" -"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|In progress|","","" +"`P2440R1 `__","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","2022-02 (Virtual)","|In Progress|","","" "`P2441R2 `__","``views::join_with``","2022-02 (Virtual)","|In Progress|","","" "`P2442R1 `__","Windowing range adaptors: ``views::chunk`` and ``views::slide``","2022-02 (Virtual)","","","" "`P2443R1 `__","``views::chunk_by``","2022-02 (Virtual)","|Complete|","18","" diff --git a/libcxx/test/benchmarks/algorithms/ranges_shift_left.bench.cpp b/libcxx/test/benchmarks/algorithms/ranges_shift_left.bench.cpp index 8f20f87f55866..9ba253c3dc15d 100644 --- a/libcxx/test/benchmarks/algorithms/ranges_shift_left.bench.cpp +++ b/libcxx/test/benchmarks/algorithms/ranges_shift_left.bench.cpp @@ -6,6 +6,8 @@ // //===----------------------------------------------------------------------===// +// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 + #include #include #include From f61bc69e7f46e1972949003456d60b04e41649d1 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 24 Dec 2024 13:11:17 -0500 Subject: [PATCH 21/25] [libc++][ranges] implement 'ranges::shift_left' --- .../include/__algorithm/ranges_shift_left.h | 21 ++++++++++++------- libcxx/include/__algorithm/shift_left.h | 2 +- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/libcxx/include/__algorithm/ranges_shift_left.h b/libcxx/include/__algorithm/ranges_shift_left.h index c00cb84256e77..7d494820cc412 100644 --- a/libcxx/include/__algorithm/ranges_shift_left.h +++ b/libcxx/include/__algorithm/ranges_shift_left.h @@ -13,13 +13,13 @@ #include <__algorithm/shift_left.h> #include <__config> #include <__iterator/concepts.h> +#include <__iterator/distance.h> #include <__iterator/incrementable_traits.h> #include <__iterator/permutable.h> #include <__ranges/access.h> #include <__ranges/concepts.h> #include <__ranges/subrange.h> #include <__utility/move.h> -#include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) # pragma GCC system_header @@ -28,10 +28,10 @@ _LIBCPP_PUSH_MACROS #include <__undef_macros> -#if _LIBCPP_STD_VER >= 23 - _LIBCPP_BEGIN_NAMESPACE_STD +#if _LIBCPP_STD_VER >= 23 + namespace ranges { namespace __shift_left { @@ -40,18 +40,23 @@ struct __fn { _LIBCPP_HIDE_FROM_ABI static constexpr subrange<_Iter> operator()(_Iter __first, _Sent __last, iter_difference_t<_Iter> __n) { auto __ret = std::__shift_left<_RangeAlgPolicy>(std::move(__first), std::move(__last), std::move(__n)); - return {__ret.first, __ret.second}; + return {std::move(__ret.first), std::move(__ret.second)}; } template requires permutable> _LIBCPP_HIDE_FROM_ABI static constexpr borrowed_subrange_t<_Range> operator()(_Range&& __range, range_difference_t<_Range> __n) { + if constexpr (sized_range<_Range>) { + if (__n >= ranges::distance(__range)) { + return {ranges::begin(__range), ranges::begin(__range)}; + } + } + auto __ret = std::__shift_left<_RangeAlgPolicy>(ranges::begin(__range), ranges::end(__range), std::move(__n)); - return {__ret.first, __ret.second}; + return {std::move(__ret.first), std::move(__ret.second)}; } }; - } // namespace __shift_left inline namespace __cpo { @@ -59,10 +64,10 @@ inline constexpr auto shift_left = __shift_left::__fn{}; } // namespace __cpo } // namespace ranges -_LIBCPP_END_NAMESPACE_STD - #endif // _LIBCPP_STD_VER >= 23 +_LIBCPP_END_NAMESPACE_STD + _LIBCPP_POP_MACROS #endif // _LIBCPP___ALGORITHM_RANGES_SHIFT_LEFT_H diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 00b1a9ad1e20b..36c0b3498bba2 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -36,7 +36,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> __shift_left( if (__n == 0) { _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); - return {__first, __end}; + return {std::move(__first), std::move(__end)}; } _Iter __m = __first; From 219655c284cd952f95cd67afa936aea5619dfd9a Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 24 Dec 2024 13:24:52 -0500 Subject: [PATCH 22/25] [libc++][ranges] implement 'ranges::shift_left' --- libcxx/include/__algorithm/shift_left.h | 17 +++++++---------- .../alg.shift/ranges.shift_left.pass.cpp | 17 +++++++++++++---- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 36c0b3498bba2..86f4ccea0dcc0 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -17,7 +17,7 @@ #include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header +# pragma GCC system_header #endif _LIBCPP_PUSH_MACROS @@ -28,11 +28,9 @@ _LIBCPP_BEGIN_NAMESPACE_STD #if _LIBCPP_STD_VER >= 20 template -_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> __shift_left( - _Iter __first, _Sent __last, - typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0, - "__n must be greater than or equal to 0"); +_LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> +__shift_left(_Iter __first, _Sent __last, typename _IterOps<_AlgPolicy>::template __difference_type<_Iter> __n) { + _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0, "__n must be greater than or equal to 0"); if (__n == 0) { _Iter __end = _IterOps<_AlgPolicy>::next(__first, __last); @@ -61,11 +59,10 @@ _LIBCPP_HIDE_FROM_ABI constexpr pair<_Iter, _Iter> __shift_left( template inline _LIBCPP_HIDE_FROM_ABI constexpr _ForwardIterator -shift_left(_ForwardIterator __first, _ForwardIterator __last, +shift_left(_ForwardIterator __first, + _ForwardIterator __last, typename iterator_traits<_ForwardIterator>::difference_type __n) { - return std::__shift_left<_ClassicAlgPolicy>(std::move(__first), - std::move(__last), __n) - .second; + return std::__shift_left<_ClassicAlgPolicy>(std::move(__first), std::move(__last), __n).second; } #endif // _LIBCPP_STD_VER >= 20 diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp index 70a909736b841..4dfacc6f11dc3 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp @@ -27,22 +27,31 @@ #include "test_iterators.h" #include "MoveOnly.h" -template -concept HasShiftLeftIt = requires(Iter iter, Sent sent, std::size_t n) { std::ranges::shift_left(iter, sent, n); }; +struct InvalidDifferenceT {}; + +template > +concept HasShiftLeftIt = requires(Iter iter, Sent sent, N n) { std::ranges::shift_left(iter, sent, n); }; static_assert(HasShiftLeftIt); +static_assert(HasShiftLeftIt>); +static_assert(HasShiftLeftIt>); + static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); -template -concept HasShiftLeftR = requires(Range range, std::size_t n) { std::ranges::shift_left(range, n); }; +static_assert(!HasShiftLeftIt); + +template > +concept HasShiftLeftR = requires(Range range, N n) { std::ranges::shift_left(range, n); }; static_assert(HasShiftLeftR>); static_assert(!HasShiftLeftR); static_assert(!HasShiftLeftR); static_assert(!HasShiftLeftR); +static_assert(!HasShiftLeftR, InvalidDifferenceT>); + template constexpr void test_iter_sent() { { From cdf0c9482ca1213097a0d3ce12b9188ca0655a9d Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 24 Dec 2024 13:31:11 -0500 Subject: [PATCH 23/25] [libc++][ranges] implement 'ranges::shift_left' --- .../alg.shift/ranges.shift_left.pass.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp index 4dfacc6f11dc3..1bd8f37551b55 100644 --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.shift/ranges.shift_left.pass.cpp @@ -35,23 +35,22 @@ concept HasShiftLeftIt = requires(Iter iter, Sent sent, N n) { std::ranges::shif static_assert(HasShiftLeftIt); static_assert(HasShiftLeftIt>); static_assert(HasShiftLeftIt>); +static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); static_assert(!HasShiftLeftIt); -static_assert(!HasShiftLeftIt); - template > concept HasShiftLeftR = requires(Range range, N n) { std::ranges::shift_left(range, n); }; static_assert(HasShiftLeftR>); +static_assert(!HasShiftLeftR, InvalidDifferenceT>); + static_assert(!HasShiftLeftR); static_assert(!HasShiftLeftR); static_assert(!HasShiftLeftR); -static_assert(!HasShiftLeftR, InvalidDifferenceT>); - template constexpr void test_iter_sent() { { From 20b1ccefc4cc380a3d092bc9db9b287e3eca6893 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 24 Dec 2024 14:11:56 -0500 Subject: [PATCH 24/25] [libc++][ranges] implement 'ranges::shift_left' --- libcxx/include/__algorithm/shift_left.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libcxx/include/__algorithm/shift_left.h b/libcxx/include/__algorithm/shift_left.h index 86f4ccea0dcc0..deb6ac920dc1e 100644 --- a/libcxx/include/__algorithm/shift_left.h +++ b/libcxx/include/__algorithm/shift_left.h @@ -13,7 +13,9 @@ #include <__algorithm/move.h> #include <__assert> #include <__config> +#include <__iterator/concepts.h> #include <__iterator/iterator_traits.h> +#include <__utility/move.h> #include <__utility/pair.h> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) From dfeaf68fd35404079caf4fdfcacbd160e6d9bed4 Mon Sep 17 00:00:00 2001 From: Xiaoyang Liu Date: Tue, 24 Dec 2024 20:12:18 -0500 Subject: [PATCH 25/25] [libc++][ranges] implement 'ranges::shift_left' --- .../ranges_robust_against_proxy_iterators.pass.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp index e5dafeef92e81..1244de04a51d9 100644 --- a/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp +++ b/libcxx/test/std/algorithms/ranges_robust_against_proxy_iterators.pass.cpp @@ -159,9 +159,6 @@ constexpr void run_tests() { test(std::ranges::remove_if, in, unary_pred); test(std::ranges::reverse, in); test_mid(std::ranges::rotate, in, mid); -#if TEST_STD_VER >= 23 - test(std::ranges::shift_left, in, count); -#endif if (!std::is_constant_evaluated()) // `shuffle` isn't `constexpr`. test(std::ranges::shuffle, in, rand_gen()); if (!std::is_constant_evaluated()) { @@ -185,7 +182,9 @@ constexpr void run_tests() { test(std::ranges::sort_heap, in); test(std::ranges::prev_permutation, in); test(std::ranges::next_permutation, in); - +#if TEST_STD_VER >= 23 + test(std::ranges::shift_left, in, count); +#endif // The algorithms that work on uninitialized memory have constraints that prevent proxy iterators from being used with // them. }