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 | // <memory> |
12 | |
13 | // template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel> |
14 | // requires default_initializable<iter_value_t<ForwardIterator>> |
15 | // ForwardIterator ranges::uninitialized_value_construct(ForwardIterator first, Sentinel last); |
16 | // |
17 | // template <nothrow-forward-range ForwardRange> |
18 | // requires default_initializable<range_value_t<ForwardRange>> |
19 | // borrowed_iterator_t<ForwardRange> ranges::uninitialized_value_construct(ForwardRange&& range); |
20 | |
21 | #include <cassert> |
22 | #include <iterator> |
23 | #include <memory> |
24 | #include <ranges> |
25 | #include <type_traits> |
26 | |
27 | #include "../buffer.h" |
28 | #include "../counted.h" |
29 | #include "test_macros.h" |
30 | #include "test_iterators.h" |
31 | |
32 | // TODO(varconst): consolidate the ADL checks into a single file. |
33 | // Because this is a variable and not a function, it's guaranteed that ADL won't be used. However, |
34 | // implementations are allowed to use a different mechanism to achieve this effect, so this check is |
35 | // libc++-specific. |
36 | LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_value_construct)>); |
37 | |
38 | struct NotDefaultCtrable { |
39 | NotDefaultCtrable() = delete; |
40 | }; |
41 | static_assert( |
42 | !std::is_invocable_v<decltype(std::ranges::uninitialized_value_construct), NotDefaultCtrable*, NotDefaultCtrable*>); |
43 | |
44 | int main(int, char**) { |
45 | // An empty range -- no default constructors should be invoked. |
46 | { |
47 | Buffer<Counted, 1> buf; |
48 | |
49 | std::ranges::uninitialized_value_construct(buf.begin(), buf.begin()); |
50 | assert(Counted::current_objects == 0); |
51 | assert(Counted::total_objects == 0); |
52 | |
53 | std::ranges::uninitialized_value_construct(std::ranges::empty_view<Counted>()); |
54 | assert(Counted::current_objects == 0); |
55 | assert(Counted::total_objects == 0); |
56 | |
57 | forward_iterator<Counted*> it(buf.begin()); |
58 | auto range = std::ranges::subrange(it, sentinel_wrapper<forward_iterator<Counted*>>(it)); |
59 | std::ranges::uninitialized_value_construct(range.begin(), range.end()); |
60 | assert(Counted::current_objects == 0); |
61 | assert(Counted::total_objects == 0); |
62 | |
63 | std::ranges::uninitialized_value_construct(range); |
64 | assert(Counted::current_objects == 0); |
65 | assert(Counted::total_objects == 0); |
66 | } |
67 | |
68 | // A range containing several objects, (iter, sentinel) overload. |
69 | { |
70 | constexpr int N = 5; |
71 | Buffer<Counted, N> buf; |
72 | |
73 | std::ranges::uninitialized_value_construct(buf.begin(), buf.end()); |
74 | assert(Counted::current_objects == N); |
75 | assert(Counted::total_objects == N); |
76 | |
77 | std::destroy(first: buf.begin(), last: buf.end()); |
78 | Counted::reset(); |
79 | } |
80 | |
81 | // A range containing several objects, (range) overload. |
82 | { |
83 | constexpr int N = 5; |
84 | Buffer<Counted, N> buf; |
85 | |
86 | auto range = std::ranges::subrange(buf.begin(), buf.end()); |
87 | std::ranges::uninitialized_value_construct(range); |
88 | assert(Counted::current_objects == N); |
89 | assert(Counted::total_objects == N); |
90 | |
91 | std::destroy(first: buf.begin(), last: buf.end()); |
92 | Counted::reset(); |
93 | } |
94 | |
95 | // Using `counted_iterator`. |
96 | { |
97 | constexpr int N = 3; |
98 | Buffer<Counted, 5> buf; |
99 | |
100 | std::ranges::uninitialized_value_construct(std::counted_iterator(buf.begin(), N), std::default_sentinel); |
101 | assert(Counted::current_objects == N); |
102 | assert(Counted::total_objects == N); |
103 | |
104 | std::destroy(first: buf.begin(), last: buf.begin() + N); |
105 | Counted::reset(); |
106 | } |
107 | |
108 | // Using `views::counted`. |
109 | { |
110 | constexpr int N = 3; |
111 | Buffer<Counted, 5> buf; |
112 | |
113 | std::ranges::uninitialized_value_construct(std::views::counted(buf.begin(), N)); |
114 | assert(Counted::current_objects == N); |
115 | assert(Counted::total_objects == N); |
116 | |
117 | std::destroy(first: buf.begin(), last: buf.begin() + N); |
118 | Counted::reset(); |
119 | } |
120 | |
121 | // Using `reverse_view`. |
122 | { |
123 | constexpr int N = 3; |
124 | Buffer<Counted, 5> buf; |
125 | |
126 | auto range = std::ranges::subrange(buf.begin(), buf.begin() + N); |
127 | std::ranges::uninitialized_value_construct(std::ranges::reverse_view(range)); |
128 | assert(Counted::current_objects == N); |
129 | assert(Counted::total_objects == N); |
130 | |
131 | std::destroy(first: buf.begin(), last: buf.begin() + N); |
132 | Counted::reset(); |
133 | } |
134 | |
135 | // Any existing values should be overwritten by value constructors. |
136 | { |
137 | constexpr int N = 5; |
138 | int buffer[N] = {42, 42, 42, 42, 42}; |
139 | |
140 | std::ranges::uninitialized_value_construct(buffer, buffer + 1); |
141 | assert(buffer[0] == 0); |
142 | assert(buffer[1] == 42); |
143 | |
144 | std::ranges::uninitialized_value_construct(buffer, buffer + N); |
145 | assert(buffer[0] == 0); |
146 | assert(buffer[1] == 0); |
147 | assert(buffer[2] == 0); |
148 | assert(buffer[3] == 0); |
149 | assert(buffer[4] == 0); |
150 | } |
151 | |
152 | // An exception is thrown while objects are being created -- the existing objects should stay |
153 | // valid. (iterator, sentinel) overload. |
154 | #ifndef TEST_HAS_NO_EXCEPTIONS |
155 | { |
156 | Buffer<Counted, 5> buf; |
157 | |
158 | Counted::throw_on = 3; // When constructing the fourth object (counting from one). |
159 | try { |
160 | std::ranges::uninitialized_value_construct(buf.begin(), buf.end()); |
161 | } catch (...) { |
162 | } |
163 | assert(Counted::current_objects == 0); |
164 | assert(Counted::total_objects == 3); |
165 | std::destroy(first: buf.begin(), last: buf.begin() + Counted::total_objects); |
166 | Counted::reset(); |
167 | } |
168 | |
169 | // An exception is thrown while objects are being created -- the existing objects should stay |
170 | // valid. (range) overload. |
171 | { |
172 | Buffer<Counted, 5> buf; |
173 | |
174 | Counted::throw_on = 3; // When constructing the fourth object. |
175 | try { |
176 | std::ranges::uninitialized_value_construct(buf); |
177 | } catch (...) { |
178 | } |
179 | assert(Counted::current_objects == 0); |
180 | assert(Counted::total_objects == 3); |
181 | std::destroy(first: buf.begin(), last: buf.begin() + Counted::total_objects); |
182 | Counted::reset(); |
183 | } |
184 | #endif // TEST_HAS_NO_EXCEPTIONS |
185 | |
186 | // Works with const iterators, (iter, sentinel) overload. |
187 | { |
188 | constexpr int N = 5; |
189 | Buffer<Counted, N> buf; |
190 | |
191 | std::ranges::uninitialized_value_construct(buf.cbegin(), buf.cend()); |
192 | assert(Counted::current_objects == N); |
193 | assert(Counted::total_objects == N); |
194 | std::destroy(first: buf.begin(), last: buf.end()); |
195 | Counted::reset(); |
196 | } |
197 | |
198 | // Works with const iterators, (range) overload. |
199 | { |
200 | constexpr int N = 5; |
201 | Buffer<Counted, N> buf; |
202 | |
203 | auto range = std::ranges::subrange(buf.cbegin(), buf.cend()); |
204 | std::ranges::uninitialized_value_construct(range); |
205 | assert(Counted::current_objects == N); |
206 | assert(Counted::total_objects == N); |
207 | std::destroy(first: buf.begin(), last: buf.end()); |
208 | Counted::reset(); |
209 | } |
210 | |
211 | return 0; |
212 | } |
213 | |