diff --git a/libcxx/benchmarks/CMakeLists.txt b/libcxx/benchmarks/CMakeLists.txt --- a/libcxx/benchmarks/CMakeLists.txt +++ b/libcxx/benchmarks/CMakeLists.txt @@ -176,6 +176,7 @@ algorithms/stable_sort.bench.cpp allocation.bench.cpp deque.bench.cpp + deque_iterator.bench.cpp filesystem.bench.cpp format_to_n.bench.cpp format_to.bench.cpp diff --git a/libcxx/benchmarks/deque_iterator.bench.cpp b/libcxx/benchmarks/deque_iterator.bench.cpp new file mode 100644 --- /dev/null +++ b/libcxx/benchmarks/deque_iterator.bench.cpp @@ -0,0 +1,232 @@ +//===----------------------------------------------------------------------===// +// +// 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 "benchmark/benchmark.h" + +namespace { +void run_sizes(auto benchmark) { + benchmark->Arg(0) + ->Arg(1) + ->Arg(2) + ->Arg(64) + ->Arg(512) + ->Arg(1024) + ->Arg(4000) + ->Arg(4096) + ->Arg(5500) + ->Arg(64000) + ->Arg(65536) + ->Arg(70000); +} + +template +void benchmark_containers(benchmark::State& state, FromContainer& d, ToContainer& v, Func&& func) { + for (auto _ : state) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(d); + func(d.begin(), d.end(), v.begin()); + } +} + +template +void benchmark_deque_vector(benchmark::State& state, Func&& func) { + auto size = state.range(0); + std::deque d; + d.resize(size); + std::ranges::fill(d, 10); + std::vector v; + v.resize(size); + benchmark_containers(state, d, v, func); +} + +template +void benchmark_deque_deque(benchmark::State& state, Func&& func) { + auto size = state.range(0); + std::deque d; + d.resize(size); + std::ranges::fill(d, 10); + std::deque v; + v.resize(size); + benchmark_containers(state, d, v, func); +} + +template +void benchmark_vector_deque(benchmark::State& state, Func&& func) { + auto size = state.range(0); + std::vector d; + d.resize(size); + std::ranges::fill(d, 10); + std::deque v; + v.resize(size); + benchmark_containers(state, d, v, func); +} + +template +void benchmark_containers_backward(benchmark::State& state, FromContainer& d, ToContainer& v, Func&& func) { + for (auto _ : state) { + benchmark::DoNotOptimize(v); + benchmark::DoNotOptimize(d); + func(d.begin(), d.end(), v.end()); + } +} + +template +void benchmark_deque_vector_backward(benchmark::State& state, Func&& func) { + auto size = state.range(0); + std::deque d; + d.resize(size); + std::ranges::fill(d, 10); + std::vector v; + v.resize(size); + benchmark_containers_backward(state, d, v, func); +} + +template +void benchmark_deque_deque_backward(benchmark::State& state, Func&& func) { + auto size = state.range(0); + std::deque d; + d.resize(size); + std::ranges::fill(d, 10); + std::deque v; + v.resize(size); + benchmark_containers_backward(state, d, v, func); +} + +template +void benchmark_vector_deque_backward(benchmark::State& state, Func&& func) { + auto size = state.range(0); + std::vector d; + d.resize(size); + std::ranges::fill(d, 10); + std::deque v; + v.resize(size); + benchmark_containers_backward(state, d, v, func); +} + +struct CopyFunctor { + template + auto operator()(Args... args) const { + std::copy(std::forward(args)...); + } +} copy; + +struct MoveFunctor { + template + auto operator()(Args... args) const { + std::move(std::forward(args)...); + } +} move; + +struct CopyBackwardFunctor { + template + auto operator()(Args... args) const { + std::copy_backward(std::forward(args)...); + } +} copy_backward; + +struct MoveBackwardFunctor { + template + auto operator()(Args... args) const { + std::move_backward(std::forward(args)...); + } +} move_backward; + +// copy +void BM_deque_vector_copy(benchmark::State& state) { benchmark_deque_vector(state, copy); } +BENCHMARK(BM_deque_vector_copy)->Apply(run_sizes); + +void BM_deque_vector_ranges_copy(benchmark::State& state) { benchmark_deque_vector(state, std::ranges::copy); } +BENCHMARK(BM_deque_vector_ranges_copy)->Apply(run_sizes); + +void BM_deque_deque_copy(benchmark::State& state) { benchmark_deque_deque(state, copy); } +BENCHMARK(BM_deque_deque_copy)->Apply(run_sizes); + +void BM_deque_deque_ranges_copy(benchmark::State& state) { benchmark_deque_deque(state, std::ranges::copy); } +BENCHMARK(BM_deque_deque_ranges_copy)->Apply(run_sizes); + +void BM_vector_deque_copy(benchmark::State& state) { benchmark_vector_deque(state, copy); } +BENCHMARK(BM_vector_deque_copy)->Apply(run_sizes); + +void BM_vector_deque_ranges_copy(benchmark::State& state) { benchmark_vector_deque(state, std::ranges::copy); } +BENCHMARK(BM_vector_deque_ranges_copy)->Apply(run_sizes); + +// move +void BM_deque_vector_move(benchmark::State& state) { benchmark_deque_vector(state, move); } +BENCHMARK(BM_deque_vector_move)->Apply(run_sizes); + +void BM_deque_vector_ranges_move(benchmark::State& state) { benchmark_deque_vector(state, std::ranges::move); } +BENCHMARK(BM_deque_vector_ranges_move)->Apply(run_sizes); + +void BM_deque_deque_move(benchmark::State& state) { benchmark_deque_deque(state, move); } +BENCHMARK(BM_deque_deque_move)->Apply(run_sizes); + +void BM_deque_deque_ranges_move(benchmark::State& state) { benchmark_deque_deque(state, std::ranges::move); } +BENCHMARK(BM_deque_deque_ranges_move)->Apply(run_sizes); + +void BM_vector_deque_move(benchmark::State& state) { benchmark_vector_deque(state, move); } +BENCHMARK(BM_vector_deque_move)->Apply(run_sizes); + +void BM_vector_deque_ranges_move(benchmark::State& state) { benchmark_vector_deque(state, std::ranges::move); } +BENCHMARK(BM_vector_deque_ranges_move)->Apply(run_sizes); + +// copy_backward +void BM_deque_vector_copy_backward(benchmark::State& state) { benchmark_deque_vector_backward(state, copy_backward); } +BENCHMARK(BM_deque_vector_copy_backward)->Apply(run_sizes); + +void BM_deque_vector_ranges_copy_backward(benchmark::State& state) { + benchmark_deque_vector_backward(state, std::ranges::copy_backward); +} +BENCHMARK(BM_deque_vector_ranges_copy_backward)->Apply(run_sizes); + +void BM_deque_deque_copy_backward(benchmark::State& state) { benchmark_deque_deque_backward(state, copy_backward); } +BENCHMARK(BM_deque_deque_copy_backward)->Apply(run_sizes); + +void BM_deque_deque_ranges_copy_backward(benchmark::State& state) { + benchmark_deque_deque_backward(state, std::ranges::copy_backward); +} +BENCHMARK(BM_deque_deque_ranges_copy_backward)->Apply(run_sizes); + +void BM_vector_deque_copy_backward(benchmark::State& state) { benchmark_vector_deque_backward(state, copy_backward); } +BENCHMARK(BM_vector_deque_copy_backward)->Apply(run_sizes); + +void BM_vector_deque_ranges_copy_backward(benchmark::State& state) { + benchmark_vector_deque_backward(state, std::ranges::copy_backward); +} +BENCHMARK(BM_vector_deque_ranges_copy_backward)->Apply(run_sizes); + +// move_backward +void BM_deque_vector_move_backward(benchmark::State& state) { benchmark_deque_vector_backward(state, move_backward); } +BENCHMARK(BM_deque_vector_move_backward)->Apply(run_sizes); + +void BM_deque_vector_ranges_move_backward(benchmark::State& state) { + benchmark_deque_vector_backward(state, std::ranges::move_backward); +} +BENCHMARK(BM_deque_vector_ranges_move_backward)->Apply(run_sizes); + +void BM_deque_deque_move_backward(benchmark::State& state) { benchmark_deque_deque_backward(state, move_backward); } +BENCHMARK(BM_deque_deque_move_backward)->Apply(run_sizes); + +void BM_deque_deque_ranges_move_backward(benchmark::State& state) { + benchmark_deque_deque_backward(state, std::ranges::move_backward); +} +BENCHMARK(BM_deque_deque_ranges_move_backward)->Apply(run_sizes); + +void BM_vector_deque_move_backward(benchmark::State& state) { benchmark_vector_deque_backward(state, move_backward); } +BENCHMARK(BM_vector_deque_move_backward)->Apply(run_sizes); + +void BM_vector_deque_ranges_move_backward(benchmark::State& state) { + benchmark_vector_deque_backward(state, std::ranges::move_backward); +} +BENCHMARK(BM_vector_deque_ranges_move_backward)->Apply(run_sizes); + +} // namespace + +BENCHMARK_MAIN(); diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -376,6 +376,7 @@ __iterator/readable_traits.h __iterator/reverse_access.h __iterator/reverse_iterator.h + __iterator/segmented_iterator.h __iterator/size.h __iterator/sortable.h __iterator/unreachable_sentinel.h diff --git a/libcxx/include/__algorithm/copy.h b/libcxx/include/__algorithm/copy.h --- a/libcxx/include/__algorithm/copy.h +++ b/libcxx/include/__algorithm/copy.h @@ -11,7 +11,9 @@ #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> #include <__config> +#include <__iterator/segmented_iterator.h> #include <__utility/move.h> #include <__utility/pair.h> @@ -21,6 +23,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> __copy(_InIter, _Sent, _OutIter); + +template struct __copy_loop { template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> @@ -33,19 +39,62 @@ return std::make_pair(std::move(__first), std::move(__result)); } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_InIter>; + auto __first_segment = _Traits::__segment(__first); + auto __last_segment = _Traits::__segment(__last); + if (__first_segment == __last_segment) { + auto __iters = std::__copy<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); + return std::make_pair(__last, std::move(__iters.second)); + } + + __result = + std::__copy<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__first_segment), std::move(__result)).second; + ++__first_segment; + while (__first_segment != __last_segment) { + __result = std::__copy<_AlgPolicy>( + _Traits::__begin(__first_segment), _Traits::__end(__first_segment), std::move(__result)) + .second; + ++__first_segment; + } + __result = std::__copy<_AlgPolicy>(_Traits::__begin(__first_segment), _Traits::__local(__last), std::move(__result)) + .second; + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) { + using _Traits = __segmented_iterator_traits<_OutIter>; + while (true) { + if (__first == __last) + return std::make_pair(__first, __result); + + auto __local_iterator = _Traits::__local(__result); + auto __size = std::min, __iter_diff_t<_OutIter>>::type>( + _Traits::__end(_Traits::__segment(__result)) - __local_iterator, __last - __first); + __first = std::__copy<_AlgPolicy>(__first, __first + __size, __local_iterator).first; + __result += __size; + } + } }; template -pair<_InIter, _OutIter> -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 +pair<_InIter, _OutIter> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __copy(_InIter __first, _Sent __last, _OutIter __result) { - return std::__dispatch_copy_or_move<_AlgPolicy, __copy_loop, __copy_trivial>( + return std::__dispatch_copy_or_move<_AlgPolicy, __copy_loop<_AlgPolicy>, __copy_trivial>( std::move(__first), std::move(__last), std::move(__result)); } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 -_OutputIterator +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator copy(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { return std::__copy<_ClassicAlgPolicy>(__first, __last, __result).second; } diff --git a/libcxx/include/__algorithm/copy_backward.h b/libcxx/include/__algorithm/copy_backward.h --- a/libcxx/include/__algorithm/copy_backward.h +++ b/libcxx/include/__algorithm/copy_backward.h @@ -11,7 +11,9 @@ #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> #include <__config> +#include <__iterator/segmented_iterator.h> #include <__utility/move.h> #include <__utility/pair.h> @@ -21,6 +23,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_InIter, _OutIter> +__copy_backward(_InIter __first, _Sent __last, _OutIter __result); + template struct __copy_backward_loop { template @@ -35,24 +41,92 @@ return std::make_pair(std::move(__original_last_iter), std::move(__result)); } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_InIter>; + auto __first_segment = _Traits::__segment(__first); + auto __last_segment = _Traits::__segment(__last); + if (__first_segment == __last_segment) { + auto __iters = + std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); + return std::make_pair(__last, __iters.second); + } + + __result = std::__copy_backward<_AlgPolicy>( + _Traits::__begin(__last_segment), _Traits::__local(__last), std::move(__result)) + .second; + --__last_segment; + while (__first_segment != __last_segment) { + __result = std::__copy_backward<_AlgPolicy>( + _Traits::__begin(__last_segment), _Traits::__end(__last_segment), std::move(__result)) + .second; + --__last_segment; + } + __result = + std::__copy_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__last_segment), std::move(__result)) + .second; + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) { + using _Traits = __segmented_iterator_traits<_OutIter>; + auto __orig_last = __last; + auto __segment_iterator = _Traits::__segment(__result); + + // When the range contains no elements __result might not be a vaid iterator + if (__first == __last) + return std::make_pair(__first, __result); + + { // iterate the last segment + auto __local_first = _Traits::__begin(__segment_iterator); + auto __local_last = _Traits::__local(__result); + auto __size = std::min, __iter_diff_t<_OutIter> >::type>( + __local_last - __local_first, __last - __first); + auto __iters = std::__copy_backward<_AlgPolicy>(__last - __size, __last, __local_last); + __last -= __size; + + if (__first == __last) + return std::make_pair( + std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iters).second)); + + --__segment_iterator; + } + + while (true) { + auto __local_first = _Traits::__begin(__segment_iterator); + auto __local_last = _Traits::__end(__segment_iterator); + auto __size = std::min, __iter_diff_t<_OutIter> >::type>( + __local_last - __local_first, __last - __first); + auto __iters = std::__copy_backward<_AlgPolicy>(__last - __size, __last, __local_last); + __last -= __size; + + if (__first == __last) + return std::make_pair( + std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iters).second)); + --__segment_iterator; + } + } }; template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 -pair<_BidirectionalIterator1, _BidirectionalIterator2> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator1, _BidirectionalIterator2> __copy_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) { return std::__dispatch_copy_or_move<_AlgPolicy, __copy_backward_loop<_AlgPolicy>, __copy_backward_trivial>( std::move(__first), std::move(__last), std::move(__result)); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 -_BidirectionalIterator2 -copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, - _BidirectionalIterator2 __result) -{ - return std::__copy_backward<_ClassicAlgPolicy>( - std::move(__first), std::move(__last), std::move(__result)).second; +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator2 +copy_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) { + return std::__copy_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)).second; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/move.h b/libcxx/include/__algorithm/move.h --- a/libcxx/include/__algorithm/move.h +++ b/libcxx/include/__algorithm/move.h @@ -11,7 +11,9 @@ #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> #include <__config> +#include <__iterator/segmented_iterator.h> #include <__utility/move.h> #include <__utility/pair.h> @@ -21,6 +23,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> +__move(_InIter __first, _Sent __last, _OutIter __result); + template struct __move_loop { template @@ -33,24 +39,67 @@ } return std::make_pair(std::move(__first), std::move(__result)); } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_InIter>; + auto __first_segment = _Traits::__segment(__first); + auto __last_segment = _Traits::__segment(__last); + if (__first_segment == __last_segment) { + auto __iters = std::__move<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); + return std::make_pair(__last, std::move(__iters.second)); + } + + __result = + std::__move<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__first_segment), std::move(__result)).second; + ++__first_segment; + while (__first_segment != __last_segment) { + __result = std::__move<_AlgPolicy>( + _Traits::__begin(__first_segment), _Traits::__end(__first_segment), std::move(__result)) + .second; + ++__first_segment; + } + __result = std::__move<_AlgPolicy>(_Traits::__begin(__first_segment), _Traits::__local(__last), std::move(__result)) + .second; + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) { + using _Traits = __segmented_iterator_traits<_OutIter>; + while (true) { + if (__first == __last) + return std::make_pair(__first, __result); + + auto __local_iterator = _Traits::__local(__result); + auto __size = std::min, __iter_diff_t<_OutIter>>::type>( + _Traits::__end(_Traits::__segment(__result)) - __local_iterator, __last - __first); + __first = std::__move<_AlgPolicy>(__first, __first + __size, __local_iterator).first; + __result += __size; + } + } }; template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 -pair<_InIter, _OutIter> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> __move(_InIter __first, _Sent __last, _OutIter __result) { return std::__dispatch_copy_or_move<_AlgPolicy, __move_loop<_AlgPolicy>, __move_trivial>( std::move(__first), std::move(__last), std::move(__result)); } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 -_OutputIterator move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _OutputIterator +move(_InputIterator __first, _InputIterator __last, _OutputIterator __result) { static_assert(is_copy_constructible<_InputIterator>::value, "Iterators has to be copy constructible."); static_assert(is_copy_constructible<_OutputIterator>::value, "The output iterator has to be copy constructible."); - return std::__move<_ClassicAlgPolicy>( - std::move(__first), std::move(__last), std::move(__result)).second; + return std::__move<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)).second; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__algorithm/move_backward.h b/libcxx/include/__algorithm/move_backward.h --- a/libcxx/include/__algorithm/move_backward.h +++ b/libcxx/include/__algorithm/move_backward.h @@ -11,7 +11,9 @@ #include <__algorithm/copy_move_common.h> #include <__algorithm/iterator_operations.h> +#include <__algorithm/min.h> #include <__config> +#include <__iterator/segmented_iterator.h> #include <__utility/move.h> #include <__utility/pair.h> @@ -21,6 +23,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD +template +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator1, _BidirectionalIterator2> +__move_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result); + template struct __move_backward_loop { template @@ -35,24 +41,92 @@ return std::make_pair(std::move(__original_last_iter), std::move(__result)); } + + template ::value, int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) const { + using _Traits = __segmented_iterator_traits<_InIter>; + auto __first_segment = _Traits::__segment(__first); + auto __last_segment = _Traits::__segment(__last); + if (__first_segment == __last_segment) { + auto __iters = + std::__move_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__local(__last), std::move(__result)); + return std::make_pair(__last, __iters.second); + } + + __result = std::__move_backward<_AlgPolicy>( + _Traits::__begin(__last_segment), _Traits::__local(__last), std::move(__result)) + .second; + --__last_segment; + while (__first_segment != __last_segment) { + __result = std::__move_backward<_AlgPolicy>( + _Traits::__begin(__last_segment), _Traits::__end(__last_segment), std::move(__result)) + .second; + --__last_segment; + } + __result = + std::__move_backward<_AlgPolicy>(_Traits::__local(__first), _Traits::__end(__last_segment), std::move(__result)) + .second; + return std::make_pair(__last, std::move(__result)); + } + + template ::value && + !__is_segmented_iterator<_InIter>::value && __is_segmented_iterator<_OutIter>::value, + int> = 0> + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_InIter, _OutIter> + operator()(_InIter __first, _InIter __last, _OutIter __result) { + using _Traits = __segmented_iterator_traits<_OutIter>; + auto __orig_last = __last; + auto __segment_iterator = _Traits::__segment(__result); + + // When the range contains no elements __result might not be a vaid iterator + if (__first == __last) + return std::make_pair(__first, __result); + + { // iterate the last segment + auto __local_first = _Traits::__begin(__segment_iterator); + auto __local_last = _Traits::__local(__result); + auto __size = std::min, __iter_diff_t<_OutIter> >::type>( + __local_last - __local_first, __last - __first); + auto __iters = std::__move_backward<_AlgPolicy>(__last - __size, __last, __local_last); + __last -= __size; + + if (__first == __last) + return std::make_pair( + std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iters).second)); + + --__segment_iterator; + } + + while (true) { + auto __local_first = _Traits::__begin(__segment_iterator); + auto __local_last = _Traits::__end(__segment_iterator); + auto __size = std::min, __iter_diff_t<_OutIter> >::type>( + __local_last - __local_first, __last - __first); + auto __iters = std::__move_backward<_AlgPolicy>(__last - __size, __last, __local_last); + __last -= __size; + + if (__first == __last) + return std::make_pair( + std::move(__orig_last), _Traits::__compose(__segment_iterator, std::move(__iters).second)); + --__segment_iterator; + } + } }; template -_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 -pair<_BidirectionalIterator1, _BidirectionalIterator2> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_BidirectionalIterator1, _BidirectionalIterator2> __move_backward(_BidirectionalIterator1 __first, _Sentinel __last, _BidirectionalIterator2 __result) { return std::__dispatch_copy_or_move<_AlgPolicy, __move_backward_loop<_AlgPolicy>, __move_backward_trivial>( std::move(__first), std::move(__last), std::move(__result)); } template -inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 -_BidirectionalIterator2 -move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, - _BidirectionalIterator2 __result) -{ - return std::__move_backward<_ClassicAlgPolicy>( - std::move(__first), std::move(__last), std::move(__result)).second; +inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_SINCE_CXX20 _BidirectionalIterator2 +move_backward(_BidirectionalIterator1 __first, _BidirectionalIterator1 __last, _BidirectionalIterator2 __result) { + return std::__move_backward<_ClassicAlgPolicy>(std::move(__first), std::move(__last), std::move(__result)).second; } _LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/include/__iterator/reverse_iterator.h b/libcxx/include/__iterator/reverse_iterator.h --- a/libcxx/include/__iterator/reverse_iterator.h +++ b/libcxx/include/__iterator/reverse_iterator.h @@ -25,6 +25,7 @@ #include <__iterator/next.h> #include <__iterator/prev.h> #include <__iterator/readable_traits.h> +#include <__iterator/segmented_iterator.h> #include <__memory/addressof.h> #include <__ranges/access.h> #include <__ranges/concepts.h> diff --git a/libcxx/include/__iterator/segmented_iterator.h b/libcxx/include/__iterator/segmented_iterator.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__iterator/segmented_iterator.h @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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___SEGMENTED_ITERATOR_H +#define _LIBCPP___SEGMENTED_ITERATOR_H + +// Segmented iterators are iterators over (not necessarily contiguous) sub-ranges. +// +// For example, std::deque stores its data into multiple blocks of contiguous memory, +// which are not stored contiguously themselves. The concept of segmented iterators +// allows algorithms to operate over these multi-level iterators natively, opening the +// door to various optimizations. See http://lafstern.org/matt/segmented.pdf for details. +// +// Given Traits = __segmented_iterator_traits, if Traits::__is_segmented_iterator::value +// is true, the following functions and associated types must be provided: +// - Traits::__local_iterator +// The type of iterators used to iterate inside a segment. +// +// - Traits::__segment_iterator +// The type of iterators used to iterate over segments. +// Segment iterators can be forward iterators or bidirectional iterators, depending on the +// underlying data structure. +// +// - static __segment_iterator Traits::__segment(It __it) +// Returns an iterator to the segment that the provided iterator is in. +// +// - static __local_iterator Traits::__local(It __it) +// Returns the local iterator pointing to the element that the provided iterator points to. +// +// - static __local_iterator Traits::__begin(__segment_iterator __it) +// Returns the local iterator to the beginning of the segment that the provided iterator is pointing into. +// +// - static __local_iterator Traits::__end(__segment_iterator __it) +// Returns the one-past-the-end local iterator to the segment that the provided iterator is pointing into. +// +// - static It Traits::__compose(__segment_iterator, __local_iterator) +// Returns the iterator composed of the segment iterator and local iterator. + +#include <__config> +#include <__type_traits/integral_constant.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +template +struct __segmented_iterator_traits { + using __is_segmented_iterator = false_type; + using __segment_iterator = void*; + using __local_iterator = void*; + + static __segment_iterator __segment(_Iterator) = delete; + static __local_iterator __local(_Iterator) = delete; + static __local_iterator __begin(__segment_iterator) = delete; + static __local_iterator __end(__segment_iterator) = delete; + static _Iterator __compose(__segment_iterator, __local_iterator) = delete; +}; + +template +using __is_segmented_iterator = typename __segmented_iterator_traits<_Iterator>::__is_segmented_iterator; + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___SEGMENTED_ITERATOR_H diff --git a/libcxx/include/deque b/libcxx/include/deque --- a/libcxx/include/deque +++ b/libcxx/include/deque @@ -176,6 +176,7 @@ #include <__iterator/next.h> #include <__iterator/prev.h> #include <__iterator/reverse_iterator.h> +#include <__iterator/segmented_iterator.h> #include <__memory/pointer_traits.h> #include <__memory/temp_value.h> #include <__memory/unique_ptr.h> @@ -214,98 +215,6 @@ template > class _LIBCPP_TEMPLATE_VIS deque; -template -class _LIBCPP_TEMPLATE_VIS __deque_iterator; - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type* = 0); - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -copy(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy_backward(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type* = 0); - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -copy_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type* = 0); - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -move(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move_backward(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type* = 0); - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -move_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - template struct __deque_block_size { static const _DiffType value = sizeof(_ValueType) < 256 ? 4096 / sizeof(_ValueType) : 16; @@ -476,105 +385,28 @@ template friend class _LIBCPP_TEMPLATE_VIS __deque_iterator; - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - copy(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*); - - template - friend - _OutputIterator - copy(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - copy(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - copy_backward(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*); - - template - friend - _OutputIterator - copy_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - copy_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - move(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*); - - template - friend - _OutputIterator - move(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - move(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - move_backward(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*); - - template - friend - _OutputIterator - move_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r); - - template - friend - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> - move_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r); + template + friend struct __segmented_iterator_traits; +}; + +template +struct __segmented_iterator_traits< + __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize> > { +private: + using _Iterator = __deque_iterator<_ValueType, _Pointer, _Reference, _MapPointer, _DiffType, _BlockSize>; + +public: + using __is_segmented_iterator = true_type; + using __segment_iterator = _MapPointer; + using __local_iterator = _Pointer; + + static _LIBCPP_HIDE_FROM_ABI __segment_iterator __segment(_Iterator __iter) { return __iter.__m_iter_; } + static _LIBCPP_HIDE_FROM_ABI __local_iterator __local(_Iterator __iter) { return __iter.__ptr_; } + static _LIBCPP_HIDE_FROM_ABI __local_iterator __begin(__segment_iterator __iter) { return *__iter; } + static _LIBCPP_HIDE_FROM_ABI __local_iterator __end(__segment_iterator __iter) { return *__iter + _BlockSize; } + static _LIBCPP_HIDE_FROM_ABI _Iterator __compose(__segment_iterator __segment, __local_iterator __local) { + return _Iterator(__segment, __local); + } }; template ::__block_size = __deque_block_size<_ValueType, _DiffType>::value; -// copy - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*) -{ - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::difference_type difference_type; - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::pointer pointer; - const difference_type __block_size = __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::__block_size; - while (__f != __l) - { - pointer __rb = __r.__ptr_; - pointer __re = *__r.__m_iter_ + __block_size; - difference_type __bs = __re - __rb; - difference_type __n = __l - __f; - _RAIter __m = __l; - if (__n > __bs) - { - __n = __bs; - __m = __f + __n; - } - _VSTD::copy(__f, __m, __rb); - __f = __m; - __r += __n; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -copy(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - const difference_type __block_size = __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::__block_size; - difference_type __n = __l - __f; - while (__n > 0) - { - pointer __fb = __f.__ptr_; - pointer __fe = *__f.__m_iter_ + __block_size; - difference_type __bs = __fe - __fb; - if (__bs > __n) - { - __bs = __n; - __fe = __fb + __bs; - } - __r = _VSTD::copy(__fb, __fe, __r); - __n -= __bs; - __f += __bs; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - const difference_type __block_size = __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::__block_size; - difference_type __n = __l - __f; - while (__n > 0) - { - pointer __fb = __f.__ptr_; - pointer __fe = *__f.__m_iter_ + __block_size; - difference_type __bs = __fe - __fb; - if (__bs > __n) - { - __bs = __n; - __fe = __fb + __bs; - } - __r = _VSTD::copy(__fb, __fe, __r); - __n -= __bs; - __f += __bs; - } - return __r; -} - -// copy_backward - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy_backward(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*) -{ - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::difference_type difference_type; - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::pointer pointer; - while (__f != __l) - { - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __rp = _VSTD::prev(__r); - pointer __rb = *__rp.__m_iter_; - pointer __re = __rp.__ptr_ + 1; - difference_type __bs = __re - __rb; - difference_type __n = __l - __f; - _RAIter __m = __f; - if (__n > __bs) - { - __n = __bs; - __m = __l - __n; - } - _VSTD::copy_backward(__m, __l, __re); - __l = __m; - __r -= __n; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -copy_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - difference_type __n = __l - __f; - while (__n > 0) - { - --__l; - pointer __lb = *__l.__m_iter_; - pointer __le = __l.__ptr_ + 1; - difference_type __bs = __le - __lb; - if (__bs > __n) - { - __bs = __n; - __lb = __le - __bs; - } - __r = _VSTD::copy_backward(__lb, __le, __r); - __n -= __bs; - __l -= __bs - 1; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -copy_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - difference_type __n = __l - __f; - while (__n > 0) - { - --__l; - pointer __lb = *__l.__m_iter_; - pointer __le = __l.__ptr_ + 1; - difference_type __bs = __le - __lb; - if (__bs > __n) - { - __bs = __n; - __lb = __le - __bs; - } - __r = _VSTD::copy_backward(__lb, __le, __r); - __n -= __bs; - __l -= __bs - 1; - } - return __r; -} - -// move - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*) -{ - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::difference_type difference_type; - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::pointer pointer; - const difference_type __block_size = __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::__block_size; - while (__f != __l) - { - pointer __rb = __r.__ptr_; - pointer __re = *__r.__m_iter_ + __block_size; - difference_type __bs = __re - __rb; - difference_type __n = __l - __f; - _RAIter __m = __l; - if (__n > __bs) - { - __n = __bs; - __m = __f + __n; - } - _VSTD::move(__f, __m, __rb); - __f = __m; - __r += __n; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -move(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - const difference_type __block_size = __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::__block_size; - difference_type __n = __l - __f; - while (__n > 0) - { - pointer __fb = __f.__ptr_; - pointer __fe = *__f.__m_iter_ + __block_size; - difference_type __bs = __fe - __fb; - if (__bs > __n) - { - __bs = __n; - __fe = __fb + __bs; - } - __r = _VSTD::move(__fb, __fe, __r); - __n -= __bs; - __f += __bs; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - const difference_type __block_size = __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::__block_size; - difference_type __n = __l - __f; - while (__n > 0) - { - pointer __fb = __f.__ptr_; - pointer __fe = *__f.__m_iter_ + __block_size; - difference_type __bs = __fe - __fb; - if (__bs > __n) - { - __bs = __n; - __fe = __fb + __bs; - } - __r = _VSTD::move(__fb, __fe, __r); - __n -= __bs; - __f += __bs; - } - return __r; -} - -// move_backward - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move_backward(_RAIter __f, - _RAIter __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r, - typename enable_if<__is_cpp17_random_access_iterator<_RAIter>::value>::type*) -{ - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::difference_type difference_type; - typedef typename __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2>::pointer pointer; - while (__f != __l) - { - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __rp = _VSTD::prev(__r); - pointer __rb = *__rp.__m_iter_; - pointer __re = __rp.__ptr_ + 1; - difference_type __bs = __re - __rb; - difference_type __n = __l - __f; - _RAIter __m = __f; - if (__n > __bs) - { - __n = __bs; - __m = __l - __n; - } - _VSTD::move_backward(__m, __l, __re); - __l = __m; - __r -= __n; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI _OutputIterator -move_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - _OutputIterator __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - difference_type __n = __l - __f; - while (__n > 0) - { - --__l; - pointer __lb = *__l.__m_iter_; - pointer __le = __l.__ptr_ + 1; - difference_type __bs = __le - __lb; - if (__bs > __n) - { - __bs = __n; - __lb = __le - __bs; - } - __r = _VSTD::move_backward(__lb, __le, __r); - __n -= __bs; - __l -= __bs - 1; - } - return __r; -} - -template -_LIBCPP_HIDE_FROM_ABI __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> -move_backward(__deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __f, - __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1> __l, - __deque_iterator<_V2, _P2, _R2, _M2, _D2, _B2> __r) -{ - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::difference_type difference_type; - typedef typename __deque_iterator<_V1, _P1, _R1, _M1, _D1, _B1>::pointer pointer; - difference_type __n = __l - __f; - while (__n > 0) - { - --__l; - pointer __lb = *__l.__m_iter_; - pointer __le = __l.__ptr_ + 1; - difference_type __bs = __le - __lb; - if (__bs > __n) - { - __bs = __n; - __lb = __le - __bs; - } - __r = _VSTD::move_backward(__lb, __le, __r); - __n -= __bs; - __l -= __bs - 1; - } - return __r; -} - template */> class _LIBCPP_TEMPLATE_VIS deque { diff --git a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp --- a/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp +++ b/libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp @@ -20,7 +20,9 @@ #include #include #include +#include #include +#include #include "almost_satisfies_types.h" #include "test_iterators.h" @@ -54,66 +56,111 @@ template constexpr void test_iterators() { - { // simple test - { - std::array in {1, 2, 3, 4}; - std::array out; - std::same_as> auto ret = - std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); - assert(in == out); - assert(base(ret.in) == in.data() + in.size()); - assert(base(ret.out) == out.data() + out.size()); - } - { - std::array in {1, 2, 3, 4}; - std::array out; - auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - std::same_as> auto ret = std::ranges::copy(range, Out(out.data())); - assert(in == out); - assert(base(ret.in) == in.data() + in.size()); - assert(base(ret.out) == out.data() + out.size()); - } + {// simple test + {std::array in{1, 2, 3, 4}; + std::array out; + std::same_as> auto ret = + std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); +} +{ + std::array in{1, 2, 3, 4}; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + std::same_as> auto ret = std::ranges::copy(range, Out(out.data())); + assert(in == out); + assert(base(ret.in) == in.data() + in.size()); + assert(base(ret.out) == out.data() + out.size()); +} +} + +{ // check that an empty range works + { + std::array in; + std::array out; + auto ret = std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); + } + { + std::array in; + std::array out; + auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); + auto ret = std::ranges::copy(range, Out(out.data())); + assert(base(ret.in) == in.data()); + assert(base(ret.out) == out.data()); } +} +} - { // check that an empty range works - { - std::array in; - std::array out; - auto ret = std::ranges::copy(In(in.data()), Sent(In(in.data() + in.size())), Out(out.data())); - assert(base(ret.in) == in.data()); - assert(base(ret.out) == out.data()); - } - { - std::array in; - std::array out; - auto range = std::ranges::subrange(In(in.data()), Sent(In(in.data() + in.size()))); - auto ret = std::ranges::copy(range, Out(out.data())); - assert(base(ret.in) == in.data()); - assert(base(ret.out) == out.data()); - } +template +constexpr void test_containers() { + { + InContainer in{1, 2, 3, 4}; + OutContainer out(4); + std::same_as> auto ret = + std::ranges::copy(In(in.begin()), Sent(In(in.end())), Out(out.begin())); + assert(std::ranges::equal(in, out)); + assert(base(ret.in) == in.end()); + assert(base(ret.out) == out.end()); + } + { + InContainer in{1, 2, 3, 4}; + OutContainer out(4); + auto range = std::ranges::subrange(In(in.begin()), Sent(In(in.end()))); + std::same_as> auto ret = std::ranges::copy(range, Out(out.begin())); + assert(std::ranges::equal(in, out)); + assert(base(ret.in) == in.end()); + assert(base(ret.out) == out.end()); } } -template +template