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