1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 11 // <algorithm> 12 13 // These tests checks that `std::copy` and `std::move` (including their variations like `copy_n`) can unwrap multiple 14 // layers of reverse iterators. 15 16 #include <algorithm> 17 #include <cassert> 18 #include <cstddef> 19 #include <cstdint> 20 #include <iterator> 21 #include <type_traits> 22 23 #include "test_iterators.h" 24 25 template <std::size_t N, class Iter> 26 requires (N == 0) 27 constexpr auto wrap_n_times(Iter i) { 28 return i; 29 } 30 31 template <std::size_t N, class Iter> 32 requires (N != 0) 33 constexpr auto wrap_n_times(Iter i) { 34 return std::make_reverse_iterator(wrap_n_times<N - 1>(i)); 35 } 36 37 static_assert(std::is_same_v<decltype(wrap_n_times<2>(std::declval<int*>())), 38 std::reverse_iterator<std::reverse_iterator<int*>>>); 39 40 template <class InIter, template <class> class SentWrapper, class OutIter, std::size_t W1, size_t W2, class Func> 41 constexpr void test_one(Func func) { 42 using From = std::iter_value_t<InIter>; 43 using To = std::iter_value_t<OutIter>; 44 45 const std::size_t N = 4; 46 47 From input[N] = {{1}, {2}, {3}, {4}}; 48 To output[N]; 49 50 auto in = wrap_n_times<W1>(InIter(input)); 51 auto in_end = wrap_n_times<W1>(InIter(input + N)); 52 auto sent = SentWrapper<decltype(in_end)>(in_end); 53 auto out = wrap_n_times<W2>(OutIter(output)); 54 55 func(in, sent, out, N); 56 57 assert(std::equal(input, input + N, output, [](const From& lhs, const To& rhs) { 58 // Prevents warnings/errors due to mismatched signed-ness. 59 return lhs == static_cast<From>(rhs); 60 })); 61 } 62 63 template <class InIter, template <class> class SentWrapper, class OutIter, std::size_t W1, size_t W2> 64 constexpr void test_copy_and_move() { 65 // Classic. 66 if constexpr (std::same_as<InIter, SentWrapper<InIter>>) { 67 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) { 68 std::copy(first, last, out); 69 }); 70 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) { 71 std::copy_backward(first, last, out + n); 72 }); 73 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, std::size_t n) { 74 std::copy_n(first, n, out); 75 }); 76 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) { 77 std::move(first, last, out); 78 }); 79 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) { 80 std::move_backward(first, last, out + n); 81 }); 82 } 83 84 // Ranges. 85 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) { 86 std::ranges::copy(first, last, out); 87 }); 88 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) { 89 std::ranges::copy_backward(first, last, out + n); 90 }); 91 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto, auto out, std::size_t n) { 92 std::ranges::copy_n(first, n, out); 93 }); 94 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t) { 95 std::ranges::move(first, last, out); 96 }); 97 test_one<InIter, SentWrapper, OutIter, W1, W2>([](auto first, auto last, auto out, std::size_t n) { 98 std::ranges::move_backward(first, last, out + n); 99 }); 100 } 101 102 template <std::size_t W1, size_t W2, class From, class To, template <class> class SentWrapper> 103 constexpr void test_all_permutations_with_counts_from_to_sent() { 104 test_copy_and_move<From*, SentWrapper, To*, W1, W2>(); 105 test_copy_and_move<contiguous_iterator<From*>, SentWrapper, To*, W1, W2>(); 106 test_copy_and_move<From*, SentWrapper, contiguous_iterator<To*>, W1, W2>(); 107 test_copy_and_move<contiguous_iterator<From*>, SentWrapper, contiguous_iterator<To*>, W1, W2>(); 108 109 if (!std::same_as<From, To>) { 110 test_copy_and_move<To*, SentWrapper, From*, W1, W2>(); 111 test_copy_and_move<contiguous_iterator<To*>, SentWrapper, From*, W1, W2>(); 112 test_copy_and_move<To*, SentWrapper, contiguous_iterator<From*>, W1, W2>(); 113 test_copy_and_move<contiguous_iterator<To*>, SentWrapper, contiguous_iterator<From*>, W1, W2>(); 114 } 115 } 116 117 template <std::size_t W1, size_t W2> 118 constexpr void test_all_permutations_with_counts() { 119 test_all_permutations_with_counts_from_to_sent<W1, W2, int, int, std::type_identity_t>(); 120 test_all_permutations_with_counts_from_to_sent<W1, W2, int, int, sized_sentinel>(); 121 test_all_permutations_with_counts_from_to_sent<W1, W2, std::int32_t, std::uint32_t, std::type_identity_t>(); 122 test_all_permutations_with_counts_from_to_sent<W1, W2, std::int32_t, std::uint32_t, sized_sentinel>(); 123 } 124 125 constexpr bool test() { 126 test_all_permutations_with_counts<0, 0>(); 127 test_all_permutations_with_counts<0, 2>(); 128 test_all_permutations_with_counts<2, 0>(); 129 test_all_permutations_with_counts<2, 2>(); 130 test_all_permutations_with_counts<2, 4>(); 131 test_all_permutations_with_counts<4, 4>(); 132 133 return true; 134 } 135 136 int main(int, char**) { 137 test(); 138 static_assert(test()); 139 140 return 0; 141 } 142