aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikolas Klauser <nikolasklauser@berlin.de>2022-07-27 23:52:45 +0200
committerTom Stellard <tstellar@redhat.com>2022-08-02 21:48:48 -0700
commit9e126d6fd2628b187ee356e66694df686817e125 (patch)
tree92b2663ff19f9e9860481f98f9c93f76a270ba11
parente38b9de601b36b26754854fda60b11817fd54b17 (diff)
[libc++] Fix unwrapping ranges with different iterators and sentinels
Reviewed By: ldionne, huixie90, #libc Spies: arichardson, sstefan1, libcxx-commits, mgorny Differential Revision: https://reviews.llvm.org/D129040 (cherry picked from commit e01b4fe956dd038fed71cf3c552d3383905d022a)
-rw-r--r--libcxx/include/CMakeLists.txt1
-rw-r--r--libcxx/include/__algorithm/copy.h10
-rw-r--r--libcxx/include/__algorithm/unwrap_range.h97
-rw-r--r--libcxx/include/module.modulemap.in1
-rw-r--r--libcxx/test/libcxx/private_headers.verify.cpp1
-rw-r--r--libcxx/test/std/algorithms/alg.modifying.operations/alg.copy/ranges.copy.pass.cpp15
6 files changed, 117 insertions, 8 deletions
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 371f0c0cf223..36eb70d39d76 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 5428baa68859..f7535a81547a 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 <class _InIter, class _Sent, class _OutIter,
&& is_copy_constructible<_Sent>::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 <class _InputIterator, class _OutputIterator>
diff --git a/libcxx/include/__algorithm/unwrap_range.h b/libcxx/include/__algorithm/unwrap_range.h
new file mode 100644
index 000000000000..745906a96e15
--- /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 <class _Iter, class _Sent>
+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 <class _Iter>
+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 <class _Iter, class _Sent>
+_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 <class _Iter, class _Unwrapped = decltype(std::__unwrap_iter(std::declval<_Iter>()))>
+_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 <class _Iter, class _Unwrapped = decltype(std::__unwrap_iter(std::declval<_Iter>()))>
+_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 1cfd4ae3bfef..88f4d152063b 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 5b3e65be251d..516991b2ac26 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 390bafed7aa5..cc58dd2732c4 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 <class In, class Out>
+constexpr void test_sentinels() {
+ test_iterators<In, Out>();
+ test_iterators<In, Out, sized_sentinel<In>>();
+ test_iterators<In, Out, sentinel_wrapper<In>>();
+}
+
template <class Out>
constexpr void test_in_iterators() {
test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
- test_iterators<forward_iterator<int*>, Out>();
- test_iterators<bidirectional_iterator<int*>, Out>();
- test_iterators<random_access_iterator<int*>, Out>();
- test_iterators<contiguous_iterator<int*>, Out>();
+ test_sentinels<forward_iterator<int*>, Out>();
+ test_sentinels<bidirectional_iterator<int*>, Out>();
+ test_sentinels<random_access_iterator<int*>, Out>();
+ test_sentinels<contiguous_iterator<int*>, Out>();
}
template <class Out>