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 @@ -56,39 +56,73 @@ return std::make_pair(__first + __n, __result + __n); } -template ::type, _OutValueT>::value - && is_trivially_copy_assignable<_OutValueT>::value> > +template +struct __is_trivially_copy_assignable_unwrapped_impl : false_type {}; + +template +struct __is_trivially_copy_assignable_unwrapped_impl<_Type*> : is_trivially_copy_assignable<_Type> {}; + +template +struct __is_trivially_copy_assignable_unwrapped + : __is_trivially_copy_assignable_unwrapped_impl(std::declval<_Iter>()))> {}; + +template ::value_type>::type, + typename iterator_traits<_OutIter>::value_type>::value + && __is_trivially_copy_assignable_unwrapped<_InIter>::value + && __is_trivially_copy_assignable_unwrapped<_OutIter>::value> > inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 -pair, reverse_iterator<_OutValueT*> > -__copy_impl(reverse_iterator<_InValueT*> __first, - reverse_iterator<_InValueT*> __last, - reverse_iterator<_OutValueT*> __result) { - auto __first_base = __first.base(); - auto __last_base = __last.base(); - auto __result_base = __result.base(); +pair, reverse_iterator<_OutIter> > +__copy_impl(reverse_iterator<_InIter> __first, + reverse_iterator<_InIter> __last, + reverse_iterator<_OutIter> __result) { + auto __first_base = std::__unwrap_iter(__first.base()); + auto __last_base = std::__unwrap_iter(__last.base()); + auto __result_base = std::__unwrap_iter(__result.base()); auto __result_first = __result_base - (__first_base - __last_base); std::__copy_impl(__last_base, __first_base, __result_first); - return std::make_pair(__last, reverse_iterator<_OutValueT*>(__result_first)); + 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 + || !is_copy_constructible<_OutIter>::value> > +inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) { return std::__copy_impl(std::move(__first), std::move(__last), std::move(__result)); } -template ::value - && is_copy_constructible<_Sent>::value - && is_copy_constructible<_OutIter>::value> > +template inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX11 -pair<_InIter, _OutIter> __copy(_InIter __first, _Sent __last, _OutIter __result) { +__enable_if_t::value + && is_copy_constructible<_Sent>::value + && is_copy_constructible<_OutIter>::value, 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)); } +// __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/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/algorithms/alg.modifying.operations/copy.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++17 +// UNSUPPORTED: debug_level=1 + +// + +#include +#include +#include + +struct S { + int i; + constexpr S(int i_) : i(i_) {} + S(const S&) = default; + S(S&&) = delete; + constexpr S& operator=(const S&) = default; + S& operator=(S&&) = delete; + constexpr bool operator==(const S&) const = default; +}; + +static_assert(std::is_trivially_copyable_v); + +template +struct NotIncrementableIt { + T* i; + using iterator_category = std::contiguous_iterator_tag; + using iterator_concept = std::contiguous_iterator_tag; + using value_type = T; + using difference_type = ptrdiff_t; + using pointer = T*; + using reference = T&; + + constexpr NotIncrementableIt(T* i_) : i(i_) {} + + friend constexpr bool operator==(const NotIncrementableIt& lhs, const NotIncrementableIt& rhs) { + return lhs.i == rhs.i; + } + + constexpr T& operator*() { return *i; } + constexpr T* operator->() { return i; } + constexpr T* operator->() const { return i; } + + constexpr NotIncrementableIt& operator++() { + assert(false); + return *this; + } + + constexpr NotIncrementableIt& operator--() { + assert(false); + return *this; + } + + friend constexpr NotIncrementableIt operator+(const NotIncrementableIt& it, ptrdiff_t size) { return it.i + size; } +}; + +static_assert(std::__is_cpp17_contiguous_iterator>::value); + +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)); +} + +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))); +} + +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)))); +} + +constexpr bool test() { + test_normal(); + test_normal>(); + test_reverse(); + test_reverse>(); + test_reverse_reverse(); + test_reverse_reverse>(); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); +}