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 @@ -79,13 +79,6 @@ return std::make_pair(__last, reverse_iterator<_OutIter>(std::__rewrap_iter(__result.base(), __result_first))); } -template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 -pair >, reverse_iterator > > -__copy_impl(reverse_iterator > __first, - reverse_iterator > __last, - reverse_iterator > __result); - template ::value && is_copy_constructible<_Sent>::value @@ -106,18 +99,6 @@ return std::make_pair(std::__rewrap_iter(__first, __ret.first), std::__rewrap_iter(__result, __ret.second)); } -// __unwrap_iter can't unwrap random_access_iterators, so we need to unwrap two reverse_iterators manually -template -inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 -pair >, reverse_iterator > > -__copy_impl(reverse_iterator > __first, - reverse_iterator > __last, - reverse_iterator > __result) { - auto __ret = std::__copy(__first.base().base(), __last.base().base(), __result.base().base()); - return std::make_pair(reverse_iterator >(reverse_iterator<_InIter>(__ret.first)), - reverse_iterator >(reverse_iterator<_OutIter>(__ret.second))); -} - template inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 _OutputIterator diff --git a/libcxx/include/__algorithm/unwrap_iter.h b/libcxx/include/__algorithm/unwrap_iter.h --- a/libcxx/include/__algorithm/unwrap_iter.h +++ b/libcxx/include/__algorithm/unwrap_iter.h @@ -63,6 +63,14 @@ return _Impl::__apply(__i); } +#ifndef _LIBCPP_CXX03_LANG +template +inline _LIBCPP_HIDE_FROM_ABI constexpr +auto __unwrap_iter(reverse_iterator> __iter) noexcept { + return std::__unwrap_iter(__iter.base().base()); +} +#endif // _LIBCPP_CXX03_LANG + template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR _OrigIter __rewrap_iter(_OrigIter, _OrigIter __result) @@ -79,6 +87,31 @@ return __first + (__result - _VSTD::__unwrap_iter(__first)); } +#ifndef _LIBCPP_CXX03_LANG + +template +using _ReverseWrapper = reverse_iterator>; + +template +struct _ReverseWrapperCount { static constexpr size_t value = 0; }; + +template +struct _ReverseWrapperCount<_ReverseWrapper<_Iter>> { + static constexpr size_t value = 1 + _ReverseWrapperCount<_Iter>::value; +}; + +template ::value, + class = __enable_if_t<_RewrapCount != 0>> +_LIBCPP_HIDE_FROM_ABI constexpr +_OrigIter __rewrap_iter(_ReverseWrapper<_OrigIter> __iter1, _UnwrappedIter __iter2) { + return std::__rewrap_iter<_OrigIter, _ReverseWrapper<_UnwrappedIter>, _RewrapCount - 1>( + __iter1, _ReverseWrapper<_UnwrappedIter>(reverse_iterator<_UnwrappedIter>(__iter2))); +} + +#endif // _LIBCPP_CXX03_LANG + _LIBCPP_END_NAMESPACE_STD #endif // _LIBCPP___ALGORITHM_UNWRAP_ITER_H diff --git a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp --- a/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp +++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp @@ -15,6 +15,7 @@ #include #include +#include #include struct S { @@ -39,6 +40,7 @@ using pointer = T*; using reference = T&; + constexpr NotIncrementableIt() = default; constexpr NotIncrementableIt(T* i_) : i(i_) {} friend constexpr bool operator==(const NotIncrementableIt& lhs, const NotIncrementableIt& rhs) { @@ -46,6 +48,7 @@ } constexpr T& operator*() { return *i; } + constexpr T& operator*() const { return *i; } constexpr T* operator->() { return i; } constexpr T* operator->() const { return i; } @@ -54,6 +57,11 @@ return *this; } + constexpr NotIncrementableIt& operator++(int) { + assert(false); + return *this; + } + constexpr NotIncrementableIt& operator--() { assert(false); return *this; @@ -66,28 +74,136 @@ template constexpr void test_normal() { - S a[] = {1, 2, 3, 4}; - S b[] = {0, 0, 0, 0}; - std::copy(Iter(a), Iter(a + 4), Iter(b)); - assert(std::equal(a, a + 4, b)); + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::copy(Iter(a), Iter(a + 4), Iter(b)); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::ranges::copy(Iter(a), Iter(a + 4), Iter(b)); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + auto range = std::ranges::subrange(Iter(a), Iter(a + 4)); + std::ranges::copy(range, Iter(b)); + assert(std::equal(a, a + 4, b)); + } } template constexpr void test_reverse() { - S a[] = {1, 2, 3, 4}; - S b[] = {0, 0, 0, 0}; - std::copy(std::make_reverse_iterator(Iter(a + 4)), - std::make_reverse_iterator(Iter(a)), - std::make_reverse_iterator(Iter(b + 4))); + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::copy(std::make_reverse_iterator(Iter(a + 4)), + std::make_reverse_iterator(Iter(a)), + std::make_reverse_iterator(Iter(b + 4))); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::ranges::copy(std::make_reverse_iterator(Iter(a + 4)), + std::make_reverse_iterator(Iter(a)), + std::make_reverse_iterator(Iter(b + 4))); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + auto range = std::ranges::subrange(std::make_reverse_iterator(Iter(a + 4)), + std::make_reverse_iterator(Iter(a))); + std::ranges::copy(range, std::make_reverse_iterator(Iter(b + 4))); + assert(std::equal(a, a + 4, b)); + } } template constexpr void test_reverse_reverse() { - S a[] = {1, 2, 3, 4}; - S b[] = {0, 0, 0, 0}; - std::copy(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), - std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4))), - std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::copy(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::ranges::copy(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + auto range = std::ranges::subrange(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4)))); + std::ranges::copy(range, std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + assert(std::equal(a, a + 4, b)); + } +} + +template +constexpr void test_reverse_reverse_input() { + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::copy(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4))), + Iter(b)); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::ranges::copy(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4))), + Iter(b)); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + auto range = std::ranges::subrange(std::make_reverse_iterator(std::make_reverse_iterator(Iter(a))), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(a + 4)))); + std::ranges::copy(range, Iter(b)); + assert(std::equal(a, a + 4, b)); + } +} + +template +constexpr void test_reverse_reverse_output() { + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::copy(Iter(a), + Iter(a + 4), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + std::ranges::copy(Iter(a), + Iter(a + 4), + std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + assert(std::equal(a, a + 4, b)); + } + { + S a[] = {1, 2, 3, 4}; + S b[] = {0, 0, 0, 0}; + auto range = std::ranges::subrange(Iter(a), Iter(a + 4)); + std::ranges::copy(range, std::make_reverse_iterator(std::make_reverse_iterator(Iter(b)))); + assert(std::equal(a, a + 4, b)); + } } constexpr bool test() { @@ -97,6 +213,10 @@ test_reverse>(); test_reverse_reverse(); test_reverse_reverse>(); + test_reverse_reverse_input(); + test_reverse_reverse_input>(); + test_reverse_reverse_output(); + test_reverse_reverse_output>(); return true; } diff --git a/libcxx/test/libcxx/algorithms/unwrap_iter.compile.pass.cpp b/libcxx/test/libcxx/algorithms/unwrap_iter.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/algorithms/unwrap_iter.compile.pass.cpp @@ -0,0 +1,37 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 + +// check that std::__unwrap_iter() returns the correct type + +#include +#include + +#include "test_iterators.h" + +template +using UnwrapT = decltype(std::__unwrap_iter(std::declval())); + +template +using rev_iter = std::reverse_iterator; + +template +using rev_rev_iter = rev_iter>; + +static_assert(std::is_same_v, int*>); +static_assert(std::is_same_v>, int*>); +static_assert(std::is_same_v>, std::reverse_iterator>); +static_assert(std::is_same_v>, int*>); +static_assert(std::is_same_v>>, int*>); +static_assert(std::is_same_v>>>, rev_iter>>); + +static_assert(std::is_same_v>, random_access_iterator>); +static_assert(std::is_same_v>>, rev_iter>>); +static_assert(std::is_same_v>>, random_access_iterator>); +static_assert(std::is_same_v>>>, rev_iter>>);