diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -141,6 +141,7 @@ __algorithm/unique.h __algorithm/unique_copy.h __algorithm/unwrap_iter.h + __algorithm/unwrap_range.h __algorithm/upper_bound.h __assert __availability 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 @@ -10,6 +10,7 @@ #define _LIBCPP___ALGORITHM_COPY_H #include <__algorithm/unwrap_iter.h> +#include <__algorithm/unwrap_range.h> #include <__config> #include <__iterator/iterator_traits.h> #include <__iterator/reverse_iterator.h> @@ -66,9 +67,10 @@ __copy_impl(reverse_iterator<_InIter> __first, reverse_iterator<_InIter> __last, reverse_iterator<_OutIter> __result) { - auto __first_base = std::__unwrap_iter(__first.base()).first; - auto __last_base = std::__unwrap_iter(__last.base()).first; - auto __result_un = std::__unwrap_iter(__result.base()); + auto __unwrapped_range = std::__unwrap_range(std::move(__first).base(), std::move(__last).base()); + auto __first_base = __unwrapped_range.first.first; + auto __last_base = __unwrapped_range.second; + auto __result_un = std::__unwrap_iter(std::move(__result).base()); auto __result_base = __result_un.first; @@ -78,13 +80,13 @@ } template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 -pair<_InIter, _OutIter> +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) { - auto __first_un = std::__unwrap_iter(std::move(__first)); - auto __result_un = std::__unwrap_iter(std::move(__result)); + auto __unwrapped_range = std::__unwrap_range(std::move(__first), std::move(__last)); + auto __first_un = std::move(__unwrapped_range.first); + auto __result_un = std::__unwrap_iter(std::move(__result)); auto __ret = - std::__copy_impl(std::move(__first_un.first), std::__unwrap_iter(__last).first, std::move(__result_un.first)); + std::__copy_impl(std::move(__first_un.first), std::move(__unwrapped_range.second), std::move(__result_un.first)); return std::make_pair( std::__rewrap_iter(__first_un.second, std::move(__ret.first)), std::__rewrap_iter(__result_un.second, std::move(__ret.second))); diff --git a/libcxx/include/__algorithm/unwrap_range.h b/libcxx/include/__algorithm/unwrap_range.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__algorithm/unwrap_range.h @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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_UNWRAP_RANGE_H +#define _LIBCPP___ALGORITHM_UNWRAP_RANGE_H + +#include <__algorithm/unwrap_iter.h> +#include <__concepts/constructible.h> +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/next.h> +#include <__utility/declval.h> +#include <__utility/move.h> +#include <__utility/pair.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 +template +struct __unwrap_range_impl { + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Sent __sent) + requires random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter> + { + auto __last = ranges::next(__first, __sent); + return pair{std::__unwrap_iter(std::move(__first)), std::__unwrap_iter(std::move(__last)).first}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Sent __last) { + return pair{pair{std::move(__first), __move_only_iterator_tag{}}, std::move(__last)}; + } +}; +#endif + +template ()))> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair<_Unwrapped, decltype(_Unwrapped::first)> +__unwrap_range(_Iter __first, _Iter __last) { + return std::make_pair(std::__unwrap_iter(__first), std::__unwrap_iter(__last).first); +} + +#if _LIBCPP_STD_VER > 17 +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __unwrap_range(_Iter __first, _Sent __last) { + return __unwrap_range_impl<_Iter, _Sent>::__unwrap(std::move(__first), std::move(__last)); +} +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_UNWRAP_RANGE_H 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 @@ -95,13 +95,20 @@ } } +template +constexpr void test_sentinels() { + test_iterators(); + test_iterators>(); + test_iterators>(); +} + template constexpr void test_in_iterators() { test_iterators, Out, sentinel_wrapper>>(); - test_iterators, Out>(); - test_iterators, Out>(); - test_iterators, Out>(); - test_iterators, Out>(); + test_sentinels, Out>(); + test_sentinels, Out>(); + test_sentinels, Out>(); + test_sentinels, Out>(); } constexpr bool test() {