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#ifndef SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
10#define SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
11
12#include <algorithm>
13#include <cassert>
14#include <concepts>
15#include <cstddef>
16#include <initializer_list>
17#include <ranges>
18#include <type_traits>
19#include <vector>
20
21#include "../exception_safety_helpers.h"
22#include "../from_range_helpers.h"
23#include "../insert_range_helpers.h"
24#include "MoveOnly.h"
25#include "almost_satisfies_types.h"
26#include "count_new.h"
27#include "min_allocator.h"
28#include "test_allocator.h"
29#include "test_iterators.h"
30#include "test_macros.h"
31#include "type_algorithms.h"
32
33template <class Container, class Range>
34concept HasInsertRange = requires (Container& c, Range&& range) {
35 c.insert_range(c.end(), range);
36};
37
38template <template <class...> class Container, class T, class U>
39constexpr bool test_constraints_insert_range() {
40 // Input range with the same value type.
41 static_assert(HasInsertRange<Container<T>, InputRange<T>>);
42 // Input range with a convertible value type.
43 static_assert(HasInsertRange<Container<T>, InputRange<U>>);
44 // Input range with a non-convertible value type.
45 static_assert(!HasInsertRange<Container<T>, InputRange<Empty>>);
46 // Not an input range.
47 static_assert(!HasInsertRange<Container<T>, InputRangeNotDerivedFrom>);
48 static_assert(!HasInsertRange<Container<T>, InputRangeNotIndirectlyReadable>);
49 static_assert(!HasInsertRange<Container<T>, InputRangeNotInputOrOutputIterator>);
50
51 return true;
52}
53
54template <class Container, class Range>
55concept HasAppendRange = requires (Container& c, Range&& range) {
56 c.append_range(range);
57};
58
59template <template <class...> class Container, class T, class U>
60constexpr bool test_constraints_append_range() {
61 // Input range with the same value type.
62 static_assert(HasAppendRange<Container<T>, InputRange<T>>);
63 // Input range with a convertible value type.
64 static_assert(HasAppendRange<Container<T>, InputRange<U>>);
65 // Input range with a non-convertible value type.
66 static_assert(!HasAppendRange<Container<T>, InputRange<Empty>>);
67 // Not an input range.
68 static_assert(!HasAppendRange<Container<T>, InputRangeNotDerivedFrom>);
69 static_assert(!HasAppendRange<Container<T>, InputRangeNotIndirectlyReadable>);
70 static_assert(!HasAppendRange<Container<T>, InputRangeNotInputOrOutputIterator>);
71
72 return true;
73}
74
75template <class Container, class Range>
76concept HasPrependRange = requires (Container& c, Range&& range) {
77 c.prepend_range(range);
78};
79
80template <template <class...> class Container, class T, class U>
81constexpr bool test_constraints_prepend_range() {
82 // Input range with the same value type.
83 static_assert(HasPrependRange<Container<T>, InputRange<T>>);
84 // Input range with a convertible value type.
85 static_assert(HasPrependRange<Container<T>, InputRange<U>>);
86 // Input range with a non-convertible value type.
87 static_assert(!HasPrependRange<Container<T>, InputRange<Empty>>);
88 // Not an input range.
89 static_assert(!HasPrependRange<Container<T>, InputRangeNotDerivedFrom>);
90 static_assert(!HasPrependRange<Container<T>, InputRangeNotIndirectlyReadable>);
91 static_assert(!HasPrependRange<Container<T>, InputRangeNotInputOrOutputIterator>);
92
93 return true;
94}
95
96template <class Container, class Range>
97concept HasAssignRange = requires (Container& c, Range&& range) {
98 c.assign_range(range);
99};
100
101template <template <class...> class Container, class T, class U>
102constexpr bool test_constraints_assign_range() {
103 // Input range with the same value type.
104 static_assert(HasAssignRange<Container<T>, InputRange<T>>);
105 // Input range with a convertible value type.
106 static_assert(HasAssignRange<Container<T>, InputRange<U>>);
107 // Input range with a non-convertible value type.
108 static_assert(!HasAssignRange<Container<T>, InputRange<Empty>>);
109 // Not an input range.
110 static_assert(!HasAssignRange<Container<T>, InputRangeNotDerivedFrom>);
111 static_assert(!HasAssignRange<Container<T>, InputRangeNotIndirectlyReadable>);
112 static_assert(!HasAssignRange<Container<T>, InputRangeNotInputOrOutputIterator>);
113
114 return true;
115}
116
117// Empty container.
118
119template <class T>
120TestCase<T> constexpr EmptyContainer_EmptyRange {
121 .initial = {}, .index = 0, .input = {}, .expected = {}
122};
123// Note: specializations for `bool` still use `vector<int>` for inputs. This is to avoid dealing with `vector<bool>` and
124// its iterators over proxy types.
125template <> constexpr TestCase<int> EmptyContainer_EmptyRange<bool> {
126 .initial = {}, .index = 0, .input = {}, .expected = {}
127};
128
129template <class T> constexpr TestCase<T> EmptyContainer_OneElementRange;
130template <> constexpr TestCase<int> EmptyContainer_OneElementRange<int> {
131 .initial = {}, .index = 0, .input = {5}, .expected = {5}
132};
133template <> constexpr TestCase<char> EmptyContainer_OneElementRange<char> {
134 .initial = {}, .index = 0, .input = "a", .expected = "a"
135};
136template <> constexpr TestCase<int> EmptyContainer_OneElementRange<bool> {
137 .initial = {}, .index = 0, .input = {true}, .expected = {true}
138};
139
140template <class T> constexpr TestCase<T> EmptyContainer_MidRange;
141template <> constexpr TestCase<int> EmptyContainer_MidRange<int> {
142 .initial = {}, .index = 0, .input = {5, 3, 1, 7, 9}, .expected = {5, 3, 1, 7, 9}
143};
144template <> constexpr TestCase<char> EmptyContainer_MidRange<char> {
145 .initial = {}, .index = 0, .input = "aeiou", .expected = "aeiou"
146};
147template <> constexpr TestCase<int> EmptyContainer_MidRange<bool> {
148 .initial = {}, .index = 0, .input = {1, 1, 0, 1, 1}, .expected = {1, 1, 0, 1, 1}
149};
150
151// One-element container.
152
153template <class T> constexpr TestCase<T> OneElementContainer_Begin_EmptyRange;
154template <> constexpr TestCase<int> OneElementContainer_Begin_EmptyRange<int> {
155 .initial = {3}, .index = 0, .input = {}, .expected = {3}
156};
157template <> constexpr TestCase<char> OneElementContainer_Begin_EmptyRange<char> {
158 .initial = "B", .index = 0, .input = {}, .expected = "B"
159};
160template <> constexpr TestCase<int> OneElementContainer_Begin_EmptyRange<bool> {
161 .initial = {0}, .index = 0, .input = {}, .expected = {0}
162};
163
164template <class T> constexpr TestCase<T> OneElementContainer_End_EmptyRange;
165template <> constexpr TestCase<int> OneElementContainer_End_EmptyRange<int> {
166 .initial = {3}, .index = 1, .input = {}, .expected = {3}
167};
168template <> constexpr TestCase<char> OneElementContainer_End_EmptyRange<char> {
169 .initial = "B", .index = 1, .input = {}, .expected = "B"
170};
171template <> constexpr TestCase<int> OneElementContainer_End_EmptyRange<bool> {
172 .initial = {0}, .index = 1, .input = {}, .expected = {0}
173};
174
175template <class T> constexpr TestCase<T> OneElementContainer_Begin_OneElementRange;
176template <> constexpr TestCase<int> OneElementContainer_Begin_OneElementRange<int> {
177 .initial = {3}, .index = 0, .input = {-5}, .expected = {-5, 3}
178};
179template <> constexpr TestCase<char> OneElementContainer_Begin_OneElementRange<char> {
180 .initial = "B", .index = 0, .input = "a", .expected = "aB"
181};
182template <> constexpr TestCase<int> OneElementContainer_Begin_OneElementRange<bool> {
183 .initial = {0}, .index = 0, .input = {1}, .expected = {1, 0}
184};
185
186template <class T> constexpr TestCase<T> OneElementContainer_End_OneElementRange;
187template <> constexpr TestCase<int> OneElementContainer_End_OneElementRange<int> {
188 .initial = {3}, .index = 1, .input = {-5}, .expected = {3, -5}
189};
190template <> constexpr TestCase<char> OneElementContainer_End_OneElementRange<char> {
191 .initial = "B", .index = 1, .input = "a", .expected = "Ba"
192};
193template <> constexpr TestCase<int> OneElementContainer_End_OneElementRange<bool> {
194 .initial = {0}, .index = 1, .input = {1}, .expected = {0, 1}
195};
196
197template <class T> constexpr TestCase<T> OneElementContainer_Begin_MidRange;
198template <> constexpr TestCase<int> OneElementContainer_Begin_MidRange<int> {
199 .initial = {3}, .index = 0, .input = {-5, -3, -1, -7, -9}, .expected = {-5, -3, -1, -7, -9, 3}
200};
201template <> constexpr TestCase<char> OneElementContainer_Begin_MidRange<char> {
202 .initial = "B", .index = 0, .input = "aeiou", .expected = "aeiouB"
203};
204template <> constexpr TestCase<int> OneElementContainer_Begin_MidRange<bool> {
205 .initial = {0}, .index = 0, .input = {1, 1, 0, 1, 1}, .expected = {1, 1, 0, 1, 1, 0}
206};
207
208template <class T> constexpr TestCase<T> OneElementContainer_End_MidRange;
209template <> constexpr TestCase<int> OneElementContainer_End_MidRange<int> {
210 .initial = {3}, .index = 1, .input = {-5, -3, -1, -7, -9}, .expected = {3, -5, -3, -1, -7, -9}
211};
212template <> constexpr TestCase<char> OneElementContainer_End_MidRange<char> {
213 .initial = "B", .index = 1, .input = "aeiou", .expected = "Baeiou"
214};
215template <> constexpr TestCase<int> OneElementContainer_End_MidRange<bool> {
216 .initial = {0}, .index = 1, .input = {1, 1, 0, 1, 1}, .expected = {0, 1, 1, 0, 1, 1}
217};
218
219// Full container / empty range.
220
221template <class T> constexpr TestCase<T> FullContainer_Begin_EmptyRange;
222template <> constexpr TestCase<int> FullContainer_Begin_EmptyRange<int> {
223 .initial = {11, 29, 35, 14, 84}, .index = 0, .input = {}, .expected = {11, 29, 35, 14, 84}
224};
225template <> constexpr TestCase<char> FullContainer_Begin_EmptyRange<char> {
226 .initial = "_BCD_", .index = 0, .input = {}, .expected = "_BCD_"
227};
228template <> constexpr TestCase<int> FullContainer_Begin_EmptyRange<bool> {
229 .initial = {0, 0, 1, 0, 0}, .index = 0, .input = {}, .expected = {0, 0, 1, 0, 0}
230};
231
232template <class T> constexpr TestCase<T> FullContainer_Mid_EmptyRange;
233template <> constexpr TestCase<int> FullContainer_Mid_EmptyRange<int> {
234 .initial = {11, 29, 35, 14, 84}, .index = 2, .input = {}, .expected = {11, 29, 35, 14, 84}
235};
236template <> constexpr TestCase<char> FullContainer_Mid_EmptyRange<char> {
237 .initial = "_BCD_", .index = 2, .input = {}, .expected = "_BCD_"
238};
239template <> constexpr TestCase<int> FullContainer_Mid_EmptyRange<bool> {
240 .initial = {0, 0, 1, 0, 0}, .index = 2, .input = {}, .expected = {0, 0, 1, 0, 0}
241};
242
243template <class T> constexpr TestCase<T> FullContainer_End_EmptyRange;
244template <> constexpr TestCase<int> FullContainer_End_EmptyRange<int> {
245 .initial = {11, 29, 35, 14, 84}, .index = 5, .input = {}, .expected = {11, 29, 35, 14, 84}
246};
247template <> constexpr TestCase<char> FullContainer_End_EmptyRange<char> {
248 .initial = "_BCD_", .index = 5, .input = {}, .expected = "_BCD_"
249};
250template <> constexpr TestCase<int> FullContainer_End_EmptyRange<bool> {
251 .initial = {0, 0, 1, 0, 0}, .index = 5, .input = {}, .expected = {0, 0, 1, 0, 0}
252};
253
254// Full container / one-element range.
255
256template <class T> constexpr TestCase<T> FullContainer_Begin_OneElementRange;
257template <> constexpr TestCase<int> FullContainer_Begin_OneElementRange<int> {
258 .initial = {11, 29, 35, 14, 84}, .index = 0, .input = {-5}, .expected = {-5, 11, 29, 35, 14, 84}
259};
260template <> constexpr TestCase<char> FullContainer_Begin_OneElementRange<char> {
261 .initial = "_BCD_", .index = 0, .input = "a", .expected = "a_BCD_"
262};
263template <> constexpr TestCase<int> FullContainer_Begin_OneElementRange<bool> {
264 .initial = {0, 0, 1, 0, 0}, .index = 0, .input = {1}, .expected = {1, 0, 0, 1, 0, 0}
265};
266
267template <class T> constexpr TestCase<T> FullContainer_Mid_OneElementRange;
268template <> constexpr TestCase<int> FullContainer_Mid_OneElementRange<int> {
269 .initial = {11, 29, 35, 14, 84}, .index = 2, .input = {-5}, .expected = {11, 29, -5, 35, 14, 84}
270};
271template <> constexpr TestCase<char> FullContainer_Mid_OneElementRange<char> {
272 .initial = "_BCD_", .index = 2, .input = "a", .expected = "_BaCD_"
273};
274template <> constexpr TestCase<int> FullContainer_Mid_OneElementRange<bool> {
275 .initial = {0, 0, 1, 0, 0}, .index = 2, .input = {1}, .expected = {0, 0, 1, 1, 0, 0}
276};
277
278template <class T> constexpr TestCase<T> FullContainer_End_OneElementRange;
279template <> constexpr TestCase<int> FullContainer_End_OneElementRange<int> {
280 .initial = {11, 29, 35, 14, 84}, .index = 5, .input = {-5}, .expected = {11, 29, 35, 14, 84, -5}
281};
282template <> constexpr TestCase<char> FullContainer_End_OneElementRange<char> {
283 .initial = "_BCD_", .index = 5, .input = "a", .expected = "_BCD_a"
284};
285template <> constexpr TestCase<int> FullContainer_End_OneElementRange<bool> {
286 .initial = {0, 0, 1, 0, 0}, .index = 5, .input = {1}, .expected = {0, 0, 1, 0, 0, 1}
287};
288
289// Full container / mid-sized range.
290
291template <class T> constexpr TestCase<T> FullContainer_Begin_MidRange;
292template <> constexpr TestCase<int> FullContainer_Begin_MidRange<int> {
293 .initial = {11, 29, 35, 14, 84},
294 .index = 0,
295 .input = {-5, -3, -1, -7, -9},
296 .expected = {-5, -3, -1, -7, -9, 11, 29, 35, 14, 84}
297};
298template <> constexpr TestCase<char> FullContainer_Begin_MidRange<char> {
299 .initial = "_BCD_",
300 .index = 0,
301 .input = "aeiou",
302 .expected = "aeiou_BCD_"
303};
304template <> constexpr TestCase<int> FullContainer_Begin_MidRange<bool> {
305 .initial = {0, 0, 1, 0, 1},
306 .index = 0,
307 .input = {1, 1, 0, 1, 1},
308 .expected = {1, 1, 0, 1, 1, 0, 0, 1, 0, 1}
309};
310
311template <class T> constexpr TestCase<T> FullContainer_Mid_MidRange;
312template <> constexpr TestCase<int> FullContainer_Mid_MidRange<int> {
313 .initial = {11, 29, 35, 14, 84},
314 .index = 2,
315 .input = {-5, -3, -1, -7, -9},
316 .expected = {11, 29, -5, -3, -1, -7, -9, 35, 14, 84}
317};
318template <> constexpr TestCase<char> FullContainer_Mid_MidRange<char> {
319 .initial = "_BCD_",
320 .index = 2,
321 .input = "aeiou",
322 .expected = "_BaeiouCD_"
323};
324template <> constexpr TestCase<int> FullContainer_Mid_MidRange<bool> {
325 .initial = {0, 0, 1, 0, 1},
326 .index = 2,
327 .input = {1, 1, 0, 1, 1},
328 .expected = {0, 0, 1, 1, 0, 1, 1, 1, 0, 1}
329};
330
331template <class T> constexpr TestCase<T> FullContainer_End_MidRange;
332template <> constexpr TestCase<int> FullContainer_End_MidRange<int> {
333 .initial = {11, 29, 35, 14, 84},
334 .index = 5,
335 .input = {-5, -3, -1, -7, -9},
336 .expected = {11, 29, 35, 14, 84, -5, -3, -1, -7, -9}
337};
338template <> constexpr TestCase<char> FullContainer_End_MidRange<char> {
339 .initial = "_BCD_",
340 .index = 5,
341 .input = "aeiou",
342 .expected = "_BCD_aeiou"
343};
344template <> constexpr TestCase<int> FullContainer_End_MidRange<bool> {
345 .initial = {0, 0, 1, 0, 1},
346 .index = 5,
347 .input = {1, 1, 0, 1, 1},
348 .expected = {0, 0, 1, 0, 1, 1, 1, 0, 1, 1}
349};
350
351// Full container / long range.
352
353template <class T> constexpr TestCase<T> FullContainer_Begin_LongRange;
354template <> constexpr TestCase<int> FullContainer_Begin_LongRange<int> {
355 .initial = {11, 29, 35, 14, 84},
356 .index = 0,
357 .input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
358 .expected = {
359 -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48, 11, 29, 35, 14, 84
360 }
361};
362template <> constexpr TestCase<char> FullContainer_Begin_LongRange<char> {
363 .initial = "_BCD_",
364 .index = 0,
365 .input = "aeiouqwxyz5781964203",
366 .expected = "aeiouqwxyz5781964203_BCD_"
367};
368template <> constexpr TestCase<int> FullContainer_Begin_LongRange<bool> {
369 .initial = {0, 0, 1, 0, 0},
370 .index = 0,
371 .input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
372 .expected = {
373 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0
374 }
375};
376
377template <class T> constexpr TestCase<T> FullContainer_Mid_LongRange;
378template <> constexpr TestCase<int> FullContainer_Mid_LongRange<int> {
379 .initial = {11, 29, 35, 14, 84},
380 .index = 2,
381 .input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
382 .expected = {
383 11, 29, -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48, 35, 14, 84
384 }
385};
386template <> constexpr TestCase<char> FullContainer_Mid_LongRange<char> {
387 .initial = "_BCD_",
388 .index = 2,
389 .input = "aeiouqwxyz5781964203",
390 .expected = "_Baeiouqwxyz5781964203CD_"
391};
392template <> constexpr TestCase<int> FullContainer_Mid_LongRange<bool> {
393 .initial = {0, 0, 1, 0, 0},
394 .index = 2,
395 .input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
396 .expected = {
397 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 0, 0
398 }
399};
400
401template <class T> constexpr TestCase<T> FullContainer_End_LongRange;
402template <> constexpr TestCase<int> FullContainer_End_LongRange<int> {
403 .initial = {11, 29, 35, 14, 84},
404 .index = 5,
405 .input = {-5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48},
406 .expected = {
407 11, 29, 35, 14, 84, -5, -3, -1, -7, -9, -19, -48, -56, -13, -14, -29, -88, -17, -1, -5, -11, -89, -21, -33, -48
408 }
409};
410template <> constexpr TestCase<char> FullContainer_End_LongRange<char> {
411 .initial = "_BCD_",
412 .index = 5,
413 .input = "aeiouqwxyz5781964203",
414 .expected = "_BCD_aeiouqwxyz5781964203"
415};
416template <> constexpr TestCase<int> FullContainer_End_LongRange<bool> {
417 .initial = {0, 0, 1, 0, 1},
418 .index = 5,
419 .input = {1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0},
420 .expected = {
421 0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0
422 }
423};
424
425// Sequence containers tests.
426
427template <class Container, class Iter, class Sent, class Validate>
428constexpr void test_sequence_insert_range(Validate validate) {
429 using T = typename Container::value_type;
430 using D = typename Container::difference_type;
431 auto get_pos = [](auto& c, auto& test_case) { return std::ranges::next(c.begin(), static_cast<D>(test_case.index)); };
432
433 auto test = [&](auto& test_case) {
434 Container c(test_case.initial.begin(), test_case.initial.end());
435 auto in = wrap_input<Iter, Sent>(test_case.input);
436 auto pos = get_pos(c, test_case);
437
438 auto result = c.insert_range(pos, in);
439 assert(result == get_pos(c, test_case));
440 validate(c);
441 return std::ranges::equal(c, test_case.expected);
442 };
443
444 { // Empty container.
445 // empty_c.insert_range(end, empty_range)
446 assert(test(EmptyContainer_EmptyRange<T>));
447 // empty_c.insert_range(end, one_element_range)
448 assert(test(EmptyContainer_OneElementRange<T>));
449 // empty_c.insert_range(end, mid_range)
450 assert(test(EmptyContainer_MidRange<T>));
451 }
452
453 { // One-element container.
454 // one_element_c.insert_range(begin, empty_range)
455 assert(test(OneElementContainer_Begin_EmptyRange<T>));
456 // one_element_c.insert_range(end, empty_range)
457 assert(test(OneElementContainer_End_EmptyRange<T>));
458 // one_element_c.insert_range(begin, one_element_range)
459 assert(test(OneElementContainer_Begin_OneElementRange<T>));
460 // one_element_c.insert_range(end, one_element_range)
461 assert(test(OneElementContainer_End_OneElementRange<T>));
462 // one_element_c.insert_range(begin, mid_range)
463 assert(test(OneElementContainer_Begin_MidRange<T>));
464 // one_element_c.insert_range(end, mid_range)
465 assert(test(OneElementContainer_End_MidRange<T>));
466 }
467
468 { // Full container.
469 // full_container.insert_range(begin, empty_range)
470 assert(test(FullContainer_Begin_EmptyRange<T>));
471 // full_container.insert_range(mid, empty_range)
472 assert(test(FullContainer_Mid_EmptyRange<T>));
473 // full_container.insert_range(end, empty_range)
474 assert(test(FullContainer_End_EmptyRange<T>));
475 // full_container.insert_range(begin, one_element_range)
476 assert(test(FullContainer_Begin_OneElementRange<T>));
477 // full_container.insert_range(end, one_element_range)
478 assert(test(FullContainer_Mid_OneElementRange<T>));
479 // full_container.insert_range(end, one_element_range)
480 assert(test(FullContainer_End_OneElementRange<T>));
481 // full_container.insert_range(begin, mid_range)
482 assert(test(FullContainer_Begin_MidRange<T>));
483 // full_container.insert_range(mid, mid_range)
484 assert(test(FullContainer_Mid_MidRange<T>));
485 // full_container.insert_range(end, mid_range)
486 assert(test(FullContainer_End_MidRange<T>));
487 // full_container.insert_range(begin, long_range)
488 assert(test(FullContainer_Begin_LongRange<T>));
489 // full_container.insert_range(mid, long_range)
490 assert(test(FullContainer_Mid_LongRange<T>));
491 // full_container.insert_range(end, long_range)
492 assert(test(FullContainer_End_LongRange<T>));
493 }
494}
495
496template <class Container, class Iter, class Sent, class Validate>
497constexpr void test_sequence_prepend_range(Validate validate) {
498 using T = typename Container::value_type;
499
500 auto test = [&](auto& test_case) {
501 Container c(test_case.initial.begin(), test_case.initial.end());
502 auto in = wrap_input<Iter, Sent>(test_case.input);
503
504 c.prepend_range(in);
505 validate(c);
506 return std::ranges::equal(c, test_case.expected);
507 };
508
509 { // Empty container.
510 // empty_c.prepend_range(empty_range)
511 assert(test(EmptyContainer_EmptyRange<T>));
512 // empty_c.prepend_range(one_element_range)
513 assert(test(EmptyContainer_OneElementRange<T>));
514 // empty_c.prepend_range(mid_range)
515 assert(test(EmptyContainer_MidRange<T>));
516 }
517
518 { // One-element container.
519 // one_element_c.prepend_range(empty_range)
520 assert(test(OneElementContainer_Begin_EmptyRange<T>));
521 // one_element_c.prepend_range(one_element_range)
522 assert(test(OneElementContainer_Begin_OneElementRange<T>));
523 // one_element_c.prepend_range(mid_range)
524 assert(test(OneElementContainer_Begin_MidRange<T>));
525 }
526
527 { // Full container.
528 // full_container.prepend_range(empty_range)
529 assert(test(FullContainer_Begin_EmptyRange<T>));
530 // full_container.prepend_range(one_element_range)
531 assert(test(FullContainer_Begin_OneElementRange<T>));
532 // full_container.prepend_range(mid_range)
533 assert(test(FullContainer_Begin_MidRange<T>));
534 // full_container.prepend_range(long_range)
535 assert(test(FullContainer_Begin_LongRange<T>));
536 }
537}
538
539template <class Container, class Iter, class Sent, class Validate>
540constexpr void test_sequence_append_range(Validate validate) {
541 using T = typename Container::value_type;
542
543 auto test = [&](auto& test_case) {
544 Container c(test_case.initial.begin(), test_case.initial.end());
545 auto in = wrap_input<Iter, Sent>(test_case.input);
546
547 c.append_range(in);
548 validate(c);
549 return std::ranges::equal(c, test_case.expected);
550 };
551
552 { // Empty container.
553 // empty_c.append_range(empty_range)
554 assert(test(EmptyContainer_EmptyRange<T>));
555 // empty_c.append_range(one_element_range)
556 assert(test(EmptyContainer_OneElementRange<T>));
557 // empty_c.append_range(mid_range)
558 assert(test(EmptyContainer_MidRange<T>));
559 }
560
561 { // One-element container.
562 // one_element_c.append_range(empty_range)
563 assert(test(OneElementContainer_End_EmptyRange<T>));
564 // one_element_c.append_range(one_element_range)
565 assert(test(OneElementContainer_End_OneElementRange<T>));
566 // one_element_c.append_range(mid_range)
567 assert(test(OneElementContainer_End_MidRange<T>));
568 }
569
570 { // Full container.
571 // full_container.append_range(empty_range)
572 assert(test(FullContainer_End_EmptyRange<T>));
573 // full_container.append_range(one_element_range)
574 assert(test(FullContainer_End_OneElementRange<T>));
575 // full_container.append_range(mid_range)
576 assert(test(FullContainer_End_MidRange<T>));
577 // full_container.append_range(long_range)
578 assert(test(FullContainer_End_LongRange<T>));
579 }
580}
581
582template <class Container, class Iter, class Sent, class Validate>
583constexpr void test_sequence_assign_range(Validate validate) {
584 using T = typename Container::value_type;
585
586 auto& initial_empty = EmptyContainer_EmptyRange<T>.initial;
587 auto& initial_one_element = OneElementContainer_Begin_EmptyRange<T>.initial;
588 auto& initial_full = FullContainer_Begin_EmptyRange<T>.initial;
589 auto& input_empty = FullContainer_Begin_EmptyRange<T>.input;
590 auto& input_one_element = FullContainer_Begin_OneElementRange<T>.input;
591 auto& input_mid_range = FullContainer_Begin_MidRange<T>.input;
592 auto& input_long_range = FullContainer_Begin_LongRange<T>.input;
593
594 auto test = [&](auto& initial, auto& input) {
595 Container c(initial.begin(), initial.end());
596 auto in = wrap_input<Iter, Sent>(input);
597
598 c.assign_range(in);
599 validate(c);
600 return std::ranges::equal(c, input);
601 };
602
603 { // Empty container.
604 // empty_container.assign_range(empty_range)
605 assert(test(initial_empty, input_empty));
606 // empty_container.assign_range(one_element_range)
607 assert(test(initial_empty, input_one_element));
608 // empty_container.assign_range(mid_range)
609 assert(test(initial_empty, input_mid_range));
610 // empty_container.assign_range(long_range)
611 assert(test(initial_empty, input_long_range));
612 }
613
614 { // One-element container.
615 // one_element_container.assign_range(empty_range)
616 assert(test(initial_one_element, input_empty));
617 // one_element_container.assign_range(one_element_range)
618 assert(test(initial_one_element, input_one_element));
619 // one_element_container.assign_range(mid_range)
620 assert(test(initial_one_element, input_mid_range));
621 // one_element_container.assign_range(long_range)
622 assert(test(initial_one_element, input_long_range));
623 }
624
625 { // Full container.
626 // full_container.assign_range(empty_range)
627 assert(test(initial_full, input_empty));
628 // full_container.assign_range(one_element_range)
629 assert(test(initial_full, input_one_element));
630 // full_container.assign_range(mid_range)
631 assert(test(initial_full, input_mid_range));
632 // full_container.assign_range(long_range)
633 assert(test(initial_full, input_long_range));
634 }
635}
636
637// Move-only types.
638
639template <template <class ...> class Container>
640constexpr void test_sequence_insert_range_move_only() {
641 MoveOnly input[5];
642 std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
643
644 Container<MoveOnly> c;
645 c.insert_range(c.end(), in);
646}
647
648template <template <class ...> class Container>
649constexpr void test_sequence_prepend_range_move_only() {
650 MoveOnly input[5];
651 std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
652
653 Container<MoveOnly> c;
654 c.prepend_range(in);
655}
656
657template <template <class ...> class Container>
658constexpr void test_sequence_append_range_move_only() {
659 MoveOnly input[5];
660 std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
661
662 Container<MoveOnly> c;
663 c.append_range(in);
664}
665
666template <template <class ...> class Container>
667constexpr void test_sequence_assign_range_move_only() {
668 MoveOnly input[5];
669 std::ranges::subrange in(std::move_iterator{input}, std::move_iterator{input + 5});
670
671 Container<MoveOnly> c;
672 c.assign_range(in);
673}
674
675// Exception safety.
676
677template <template <class ...> class Container>
678void test_insert_range_exception_safety_throwing_copy() {
679#if !defined(TEST_HAS_NO_EXCEPTIONS)
680 constexpr int ThrowOn = 3;
681 using T = ThrowingCopy<ThrowOn>;
682 test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
683 Container<T> c;
684 c.insert_range(c.end(), std::ranges::subrange(from, to));
685 });
686#endif
687}
688
689template <template <class ...> class Container, class T>
690void test_insert_range_exception_safety_throwing_allocator() {
691#if !defined(TEST_HAS_NO_EXCEPTIONS)
692 T in[] = {0, 1};
693
694 try {
695 ThrowingAllocator<T> alloc;
696
697 globalMemCounter.reset();
698 Container<T, ThrowingAllocator<T>> c(alloc);
699 c.insert_range(c.end(), in);
700 assert(false); // The function call above should throw.
701
702 } catch (int) {
703 assert(globalMemCounter.new_called == globalMemCounter.delete_called);
704 }
705#endif
706}
707
708template <template <class ...> class Container>
709void test_prepend_range_exception_safety_throwing_copy() {
710#if !defined(TEST_HAS_NO_EXCEPTIONS)
711 constexpr int ThrowOn = 3;
712 using T = ThrowingCopy<ThrowOn>;
713 test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
714 Container<T> c;
715 c.prepend_range(std::ranges::subrange(from, to));
716 });
717#endif
718}
719
720template <template <class ...> class Container, class T>
721void test_prepend_range_exception_safety_throwing_allocator() {
722#if !defined(TEST_HAS_NO_EXCEPTIONS)
723 T in[] = {0, 1};
724
725 try {
726 ThrowingAllocator<T> alloc;
727
728 globalMemCounter.reset();
729 Container<T, ThrowingAllocator<T>> c(alloc);
730 c.prepend_range(in);
731 assert(false); // The function call above should throw.
732
733 } catch (int) {
734 assert(globalMemCounter.new_called == globalMemCounter.delete_called);
735 }
736#endif
737}
738
739template <template <class ...> class Container>
740void test_append_range_exception_safety_throwing_copy() {
741#if !defined(TEST_HAS_NO_EXCEPTIONS)
742 constexpr int ThrowOn = 3;
743 using T = ThrowingCopy<ThrowOn>;
744 test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
745 Container<T> c;
746 c.append_range(std::ranges::subrange(from, to));
747 });
748#endif
749}
750
751template <template <class ...> class Container, class T>
752void test_append_range_exception_safety_throwing_allocator() {
753#if !defined(TEST_HAS_NO_EXCEPTIONS)
754 T in[] = {0, 1};
755
756 try {
757 ThrowingAllocator<T> alloc;
758
759 globalMemCounter.reset();
760 Container<T, ThrowingAllocator<T>> c(alloc);
761 c.append_range(in);
762 assert(false); // The function call above should throw.
763
764 } catch (int) {
765 assert(globalMemCounter.new_called == globalMemCounter.delete_called);
766 }
767#endif
768}
769
770template <template <class ...> class Container>
771void test_assign_range_exception_safety_throwing_copy() {
772#if !defined(TEST_HAS_NO_EXCEPTIONS)
773 constexpr int ThrowOn = 3;
774 using T = ThrowingCopy<ThrowOn>;
775 test_exception_safety_throwing_copy<ThrowOn, /*Size=*/5>([](T* from, T* to) {
776 Container<T> c;
777 c.assign_range(std::ranges::subrange(from, to));
778 });
779#endif
780}
781
782template <template <class ...> class Container, class T>
783void test_assign_range_exception_safety_throwing_allocator() {
784#if !defined(TEST_HAS_NO_EXCEPTIONS)
785 T in[] = {0, 1};
786
787 try {
788 ThrowingAllocator<T> alloc;
789
790 globalMemCounter.reset();
791 Container<T, ThrowingAllocator<T>> c(alloc);
792 c.assign_range(in);
793 assert(false); // The function call above should throw.
794
795 } catch (int) {
796 assert(globalMemCounter.new_called == globalMemCounter.delete_called);
797 }
798#endif
799}
800
801#endif // SUPPORT_INSERT_RANGE_SEQUENCE_CONTAINERS_H
802

source code of libcxx/test/std/containers/sequences/insert_range_sequence_containers.h