[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)
This commit is contained in:
parent
e38b9de601
commit
9e126d6fd2
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
97
libcxx/include/__algorithm/unwrap_range.h
Normal file
97
libcxx/include/__algorithm/unwrap_range.h
Normal file
|
@ -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
|
|
@ -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" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'}}
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Reference in a new issue