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,25 +56,41 @@ return std::make_pair(__first + __n, __result + __n); } -template ::type, _OutValueT>::value - && is_trivially_copy_assignable<_OutValueT>::value> > +template +using __is_trivially_copy_assignable_unwrapped = + _And<__is_cpp17_contiguous_iterator<_Iter>, is_trivially_copy_assignable<__iter_value_type<_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), int> = 0 > +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)); } @@ -82,13 +98,26 @@ template ::value && is_copy_constructible<_Sent>::value - && is_copy_constructible<_OutIter>::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) { +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/include/__iterator/iterator_traits.h b/libcxx/include/__iterator/iterator_traits.h --- a/libcxx/include/__iterator/iterator_traits.h +++ b/libcxx/include/__iterator/iterator_traits.h @@ -469,27 +469,28 @@ struct __is_cpp17_contiguous_iterator<_Up*> : true_type {}; +template +class __wrap_iter; + template struct __is_exactly_cpp17_input_iterator : public integral_constant::value && !__has_iterator_category_convertible_to<_Tp, forward_iterator_tag>::value> {}; -#if _LIBCPP_STD_VER >= 17 template using __iter_value_type = typename iterator_traits<_InputIterator>::value_type; template -using __iter_key_type = remove_const_t::value_type::first_type>; +using __iter_key_type = typename remove_const::value_type::first_type>::type; template using __iter_mapped_type = typename iterator_traits<_InputIterator>::value_type::second_type; template using __iter_to_alloc_type = pair< - add_const_t::value_type::first_type>, + typename add_const::value_type::first_type>::type, typename iterator_traits<_InputIterator>::value_type::second_type>; -#endif // _LIBCPP_STD_VER >= 17 _LIBCPP_END_NAMESPACE_STD 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,107 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// This test checks that std::copy forwards to memmove when appropriate. + +#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()); +} diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_pointer.pass.cpp @@ -38,7 +38,7 @@ } template -TEST_CONSTEXPR_CXX20 void test0() +TEST_CONSTEXPR_CXX20 bool test0() { test(S(""), 0, 0, "", S("")); test(S(""), 0, 0, "12345", S("12345")); @@ -140,10 +140,12 @@ test(S("abcdefghij"), 1, 1, "12345", S("a12345cdefghij")); test(S("abcdefghij"), 1, 1, "1234567890", S("a1234567890cdefghij")); test(S("abcdefghij"), 1, 1, "12345678901234567890", S("a12345678901234567890cdefghij")); + + return true; } template -TEST_CONSTEXPR_CXX20 void test1() +TEST_CONSTEXPR_CXX20 bool test1() { test(S("abcdefghij"), 1, 4, "", S("afghij")); test(S("abcdefghij"), 1, 4, "12345", S("a12345fghij")); @@ -245,10 +247,12 @@ test(S("abcdefghijklmnopqrst"), 10, 9, "12345", S("abcdefghij12345t")); test(S("abcdefghijklmnopqrst"), 10, 9, "1234567890", S("abcdefghij1234567890t")); test(S("abcdefghijklmnopqrst"), 10, 9, "12345678901234567890", S("abcdefghij12345678901234567890t")); + + return true; } template -TEST_CONSTEXPR_CXX20 void test2() +TEST_CONSTEXPR_CXX20 bool test2() { test(S("abcdefghijklmnopqrst"), 10, 10, "", S("abcdefghij")); test(S("abcdefghijklmnopqrst"), 10, 10, "12345", S("abcdefghij12345")); @@ -266,14 +270,36 @@ test(S("abcdefghijklmnopqrst"), 20, 0, "12345", S("abcdefghijklmnopqrst12345")); test(S("abcdefghijklmnopqrst"), 20, 0, "1234567890", S("abcdefghijklmnopqrst1234567890")); test(S("abcdefghijklmnopqrst"), 20, 0, "12345678901234567890", S("abcdefghijklmnopqrst12345678901234567890")); + + { // test replacing into self + S s_short = "123/"; + S s_long = "Lorem ipsum dolor sit amet, consectetur/"; + + s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); + assert(s_short == "123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); + assert(s_short == "123/123/123/123/"); + s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); + assert(s_short == "123/123/123/123/123/123/123/123/"); + + s_long.replace(s_long.begin(), s_long.begin(), s_long.c_str()); + assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); + } + + return true; } -TEST_CONSTEXPR_CXX20 bool test() { +TEST_CONSTEXPR_CXX20 void test() { { typedef std::string S; test0(); test1(); test2(); +#if TEST_STD_VER > 17 + static_assert(test0()); + static_assert(test1()); + static_assert(test2()); +#endif } #if TEST_STD_VER >= 11 { @@ -281,34 +307,18 @@ test0(); test1(); test2(); - } +#if TEST_STD_VER > 17 + static_assert(test0()); + static_assert(test1()); + static_assert(test2()); #endif - - { // test replacing into self - typedef std::string S; - S s_short = "123/"; - S s_long = "Lorem ipsum dolor sit amet, consectetur/"; - - s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); - assert(s_short == "123/123/"); - s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); - assert(s_short == "123/123/123/123/"); - s_short.replace(s_short.begin(), s_short.begin(), s_short.c_str()); - assert(s_short == "123/123/123/123/123/123/123/123/"); - - s_long.replace(s_long.begin(), s_long.begin(), s_long.c_str()); - assert(s_long == "Lorem ipsum dolor sit amet, consectetur/Lorem ipsum dolor sit amet, consectetur/"); } - - return true; +#endif } int main(int, char**) { test(); -#if TEST_STD_VER > 17 - static_assert(test()); -#endif return 0; } diff --git a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string_view.pass.cpp b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string_view.pass.cpp --- a/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string_view.pass.cpp +++ b/libcxx/test/std/strings/basic.string/string.modifiers/string_replace/iter_iter_string_view.pass.cpp @@ -36,7 +36,7 @@ } template -TEST_CONSTEXPR_CXX20 void test0() +TEST_CONSTEXPR_CXX20 bool test0() { test(S(""), 0, 0, SV(""), S("")); test(S(""), 0, 0, SV("12345"), S("12345")); @@ -138,10 +138,12 @@ test(S("abcdefghij"), 1, 1, SV("12345"), S("a12345cdefghij")); test(S("abcdefghij"), 1, 1, SV("1234567890"), S("a1234567890cdefghij")); test(S("abcdefghij"), 1, 1, SV("12345678901234567890"), S("a12345678901234567890cdefghij")); + + return true; } template -TEST_CONSTEXPR_CXX20 void test1() +TEST_CONSTEXPR_CXX20 bool test1() { test(S("abcdefghij"), 1, 4, SV(""), S("afghij")); test(S("abcdefghij"), 1, 4, SV("12345"), S("a12345fghij")); @@ -243,10 +245,12 @@ test(S("abcdefghijklmnopqrst"), 10, 9, SV("12345"), S("abcdefghij12345t")); test(S("abcdefghijklmnopqrst"), 10, 9, SV("1234567890"), S("abcdefghij1234567890t")); test(S("abcdefghijklmnopqrst"), 10, 9, SV("12345678901234567890"), S("abcdefghij12345678901234567890t")); + + return true; } template -TEST_CONSTEXPR_CXX20 void test2() +TEST_CONSTEXPR_CXX20 bool test2() { test(S("abcdefghijklmnopqrst"), 10, 10, SV(""), S("abcdefghij")); test(S("abcdefghijklmnopqrst"), 10, 10, SV("12345"), S("abcdefghij12345")); @@ -264,15 +268,22 @@ test(S("abcdefghijklmnopqrst"), 20, 0, SV("12345"), S("abcdefghijklmnopqrst12345")); test(S("abcdefghijklmnopqrst"), 20, 0, SV("1234567890"), S("abcdefghijklmnopqrst1234567890")); test(S("abcdefghijklmnopqrst"), 20, 0, SV("12345678901234567890"), S("abcdefghijklmnopqrst12345678901234567890")); + + return true; } -TEST_CONSTEXPR_CXX20 bool test() { +TEST_CONSTEXPR_CXX20 void test() { { typedef std::string S; typedef std::string_view SV; test0(); test1(); test2(); +#if TEST_STD_VER > 17 + static_assert(test0()); + static_assert(test1()); + static_assert(test2()); +#endif } #if TEST_STD_VER >= 11 { @@ -281,18 +292,18 @@ test0(); test1(); test2(); +#if TEST_STD_VER > 17 + static_assert(test0()); + static_assert(test1()); + static_assert(test2()); +#endif } #endif - - return true; } int main(int, char**) { test(); -#if TEST_STD_VER > 17 - static_assert(test()); -#endif return 0; }