diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 371f0c0cf223b..36eb70d39d769 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -181,6 +181,7 @@ set(files __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 index 5428baa688592..f7535a81547a8 100644 --- 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> @@ -88,10 +89,11 @@ template ::value && is_copy_constructible<_OutIter>::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 -pair<_InIter, _OutIter> -__copy(_InIter __first, _Sent __last, _OutIter __result) { - auto __ret = std::__copy_impl(std::__unwrap_iter(__first), std::__unwrap_iter(__last), std::__unwrap_iter(__result)); - return std::make_pair(std::__rewrap_iter(__first, __ret.first), std::__rewrap_iter(__result, __ret.second)); +pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) { + auto __range = std::__unwrap_range(__first, __last); + auto __ret = std::__copy_impl(std::move(__range.first), std::move(__range.second), std::__unwrap_iter(__result)); + return std::make_pair( + std::__rewrap_range<_Sent>(__first, __ret.first), std::__rewrap_iter(__result, __ret.second)); } template diff --git a/libcxx/include/__algorithm/unwrap_range.h b/libcxx/include/__algorithm/unwrap_range.h new file mode 100644 index 0000000000000..745906a96e15b --- /dev/null +++ b/libcxx/include/__algorithm/unwrap_range.h @@ -0,0 +1,97 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// __unwrap_range and __rewrap_range are used to unwrap ranges which may have different iterator and sentinel types. +// __unwrap_iter and __rewrap_iter don't work for this, because they assume that the iterator and sentinel have +// the same type. __unwrap_range tries to get two iterators and then forward to __unwrap_iter. + +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES) +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))}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Sent __last) { + return pair{std::move(__first), std::move(__last)}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __rewrap(_Iter __orig_iter, decltype(std::__unwrap_iter(__orig_iter)) __iter) + requires random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter> + { + return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter)); + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto __rewrap(const _Iter&, _Iter __iter) + requires (!(random_access_iterator<_Iter> && sized_sentinel_for<_Sent, _Iter>)) + { + return __iter; + } +}; + +template +struct __unwrap_range_impl<_Iter, _Iter> { + _LIBCPP_HIDE_FROM_ABI static constexpr auto __unwrap(_Iter __first, _Iter __last) { + return pair{std::__unwrap_iter(std::move(__first)), std::__unwrap_iter(std::move(__last))}; + } + + _LIBCPP_HIDE_FROM_ABI static constexpr auto + __rewrap(_Iter __orig_iter, decltype(std::__unwrap_iter(__orig_iter)) __iter) { + return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter)); + } +}; + +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)); +} + +template < + class _Sent, + class _Iter, + class _Unwrapped = decltype(std::__unwrap_range(std::declval<_Iter>(), std::declval<_Sent>()))> +_LIBCPP_HIDE_FROM_ABI constexpr _Iter __rewrap_range(_Iter __orig_iter, _Unwrapped __iter) { + return __unwrap_range_impl<_Iter, _Sent>::__rewrap(std::move(__orig_iter), std::move(__iter)); +} +#else // _LIBCPP_STD_VER > 17 +template ()))> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR pair<_Unwrapped, _Unwrapped> __unwrap_range(_Iter __first, _Iter __last) { + return std::make_pair(std::__unwrap_iter(std::move(__first)), std::__unwrap_iter(std::move(__last))); +} + +template ()))> +_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _Iter __rewrap_range(_Iter __orig_iter, _Unwrapped __iter) { + return std::__rewrap_iter(std::move(__orig_iter), std::move(__iter)); +} +#endif // _LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___ALGORITHM_UNWRAP_RANGE_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index 1cfd4ae3bfef4..88f4d152063b6 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -420,6 +420,7 @@ module std [system] { module unique { private header "__algorithm/unique.h" } module unique_copy { private header "__algorithm/unique_copy.h" } module unwrap_iter { private header "__algorithm/unwrap_iter.h" } + module unwrap_range { private header "__algorithm/unwrap_range.h" } module upper_bound { private header "__algorithm/upper_bound.h" } } } diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp index 5b3e65be251d9..516991b2ac262 100644 --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -218,6 +218,7 @@ END-SCRIPT #include <__algorithm/unique.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unique.h'}} #include <__algorithm/unique_copy.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unique_copy.h'}} #include <__algorithm/unwrap_iter.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unwrap_iter.h'}} +#include <__algorithm/unwrap_range.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/unwrap_range.h'}} #include <__algorithm/upper_bound.h> // expected-error@*:* {{use of private header from outside its module: '__algorithm/upper_bound.h'}} #include <__availability> // expected-error@*:* {{use of private header from outside its module: '__availability'}} #include <__bit/bit_cast.h> // expected-error@*:* {{use of private header from outside its module: '__bit/bit_cast.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 index 390bafed7aa54..cc58dd2732c49 100644 --- 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 @@ constexpr void test_iterators() { } } +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>(); } template