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 && !stdlib=libc++ |
10 | // ADDITIONAL_COMPILE_FLAGS(has-fconstexpr-steps): -fconstexpr-steps=2000000 |
11 | |
12 | // <algorithm> |
13 | |
14 | // template<InputIterator InIter, typename OutIter> |
15 | // requires OutputIterator<OutIter, RvalueOf<InIter::reference>::type> |
16 | // OutIter |
17 | // move(InIter first, InIter last, OutIter result); |
18 | |
19 | #include <algorithm> |
20 | #include <cassert> |
21 | #include <iterator> |
22 | #include <memory> |
23 | |
24 | #include "MoveOnly.h" |
25 | #include "test_iterators.h" |
26 | #include "test_macros.h" |
27 | |
28 | class PaddedBase { |
29 | public: |
30 | TEST_CONSTEXPR PaddedBase(std::int16_t a, std::int8_t b) : a_(a), b_(b) {} |
31 | |
32 | std::int16_t a_; |
33 | std::int8_t b_; |
34 | }; |
35 | |
36 | class Derived : public PaddedBase { |
37 | public: |
38 | TEST_CONSTEXPR Derived(std::int16_t a, std::int8_t b, std::int8_t c) : PaddedBase(a, b), c_(c) {} |
39 | |
40 | std::int8_t c_; |
41 | }; |
42 | |
43 | template <class InIter> |
44 | struct Test { |
45 | template <class OutIter> |
46 | TEST_CONSTEXPR_CXX20 void operator()() { |
47 | const unsigned N = 1000; |
48 | int ia[N] = {}; |
49 | for (unsigned i = 0; i < N; ++i) |
50 | ia[i] = i; |
51 | int ib[N] = {0}; |
52 | |
53 | OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); |
54 | assert(base(r) == ib+N); |
55 | for (unsigned i = 0; i < N; ++i) |
56 | assert(ia[i] == ib[i]); |
57 | } |
58 | }; |
59 | |
60 | struct TestOutIters { |
61 | template <class InIter> |
62 | TEST_CONSTEXPR_CXX20 void operator()() { |
63 | types::for_each( |
64 | types::concatenate_t<types::cpp17_input_iterator_list<int*>, types::type_list<cpp17_output_iterator<int*> > >(), |
65 | Test<InIter>()); |
66 | } |
67 | }; |
68 | |
69 | template <class InIter> |
70 | struct Test1 { |
71 | template <class OutIter> |
72 | TEST_CONSTEXPR_CXX23 void operator()() { |
73 | const unsigned N = 100; |
74 | std::unique_ptr<int> ia[N]; |
75 | for (unsigned i = 0; i < N; ++i) |
76 | ia[i].reset(p: new int(i)); |
77 | std::unique_ptr<int> ib[N]; |
78 | |
79 | OutIter r = std::move(InIter(ia), InIter(ia+N), OutIter(ib)); |
80 | assert(base(r) == ib+N); |
81 | for (unsigned i = 0; i < N; ++i) |
82 | assert(*ib[i] == static_cast<int>(i)); |
83 | } |
84 | }; |
85 | |
86 | struct Test1OutIters { |
87 | template <class InIter> |
88 | TEST_CONSTEXPR_CXX23 void operator()() { |
89 | types::for_each(types::concatenate_t<types::cpp17_input_iterator_list<std::unique_ptr<int>*>, |
90 | types::type_list<cpp17_output_iterator<std::unique_ptr<int>*> > >(), |
91 | Test1<InIter>()); |
92 | } |
93 | }; |
94 | |
95 | TEST_CONSTEXPR_CXX20 bool test() { |
96 | types::for_each(types::cpp17_input_iterator_list<int*>(), TestOutIters()); |
97 | if (TEST_STD_AT_LEAST_23_OR_RUNTIME_EVALUATED) |
98 | types::for_each(types::cpp17_input_iterator_list<std::unique_ptr<int>*>(), Test1OutIters()); |
99 | |
100 | { // Make sure that padding bits aren't copied |
101 | Derived src(1, 2, 3); |
102 | Derived dst(4, 5, 6); |
103 | std::move(first: static_cast<PaddedBase*>(&src), last: static_cast<PaddedBase*>(&src) + 1, result: static_cast<PaddedBase*>(&dst)); |
104 | assert(dst.a_ == 1); |
105 | assert(dst.b_ == 2); |
106 | assert(dst.c_ == 6); |
107 | } |
108 | |
109 | { // Make sure that overlapping ranges can be copied |
110 | int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
111 | std::move(first: a + 3, last: a + 10, result: a); |
112 | int expected[] = {4, 5, 6, 7, 8, 9, 10, 8, 9, 10}; |
113 | assert(std::equal(a, a + 10, expected)); |
114 | } |
115 | |
116 | // Make sure that the algorithm works with move-only types |
117 | { |
118 | // When non-trivial |
119 | { |
120 | MoveOnly from[3] = {1, 2, 3}; |
121 | MoveOnly to[3] = {}; |
122 | std::move(std::begin(from), std::end(from), std::begin(to)); |
123 | assert(to[0] == MoveOnly(1)); |
124 | assert(to[1] == MoveOnly(2)); |
125 | assert(to[2] == MoveOnly(3)); |
126 | } |
127 | // When trivial |
128 | { |
129 | TrivialMoveOnly from[3] = {1, 2, 3}; |
130 | TrivialMoveOnly to[3] = {}; |
131 | std::move(std::begin(from), std::end(from), std::begin(to)); |
132 | assert(to[0] == TrivialMoveOnly(1)); |
133 | assert(to[1] == TrivialMoveOnly(2)); |
134 | assert(to[2] == TrivialMoveOnly(3)); |
135 | } |
136 | } |
137 | |
138 | return true; |
139 | } |
140 | |
141 | int main(int, char**) { |
142 | test(); |
143 | #if TEST_STD_VER >= 20 |
144 | static_assert(test()); |
145 | #endif |
146 | |
147 | return 0; |
148 | } |
149 | |