xref: /llvm-project/libcxx/test/std/containers/sequences/vector/vector.capacity/reserve_exceptions.pass.cpp (revision 550d32f205202b73f21903b29df04fe2e89ae648)
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: no-exceptions
10 
11 // This test file validates that std::vector<T>::reserve provides the strong exception guarantee if T is
12 // Cpp17MoveInsertable and no exception is thrown by the move constructor of T during the reserve call.
13 // It also checks that if T's move constructor is not noexcept, reserve provides only the basic exception
14 // guarantee.
15 
16 #include <cstddef>
17 #include <memory>
18 #include <type_traits>
19 #include <vector>
20 
21 #include "../common.h"
22 #include "MoveOnly.h"
23 #include "count_new.h"
24 #include "increasing_allocator.h"
25 #include "min_allocator.h"
26 #include "test_allocator.h"
27 #include "test_iterators.h"
28 #include "test_macros.h"
29 
30 template <typename T, typename Alloc>
31 void test_allocation_exception_for_strong_guarantee(
32     std::vector<T, Alloc>& v, const std::vector<T>& values, std::size_t new_cap) {
33   assert(v.size() == values.size());
34   T* old_data          = v.data();
35   std::size_t old_size = v.size();
36   std::size_t old_cap  = v.capacity();
37 
38   try {
39     v.reserve(new_cap);
40   } catch (...) { // std::length_error, std::bad_alloc
41     assert(v.data() == old_data);
42     assert(v.size() == old_size);
43     assert(v.capacity() == old_cap);
44     for (std::size_t i = 0; i < v.size(); ++i)
45       assert(v[i] == values[i]);
46   }
47 }
48 
49 template <typename T, typename Alloc>
50 void test_copy_ctor_exception_for_strong_guarantee(std::vector<throwing_data<T>, Alloc>& v,
51                                                    const std::vector<T>& values) {
52   assert(v.empty() && !values.empty());
53   int throw_after = values.size() + values.size() / 2; // Trigger an exception halfway through reallocation
54   v.reserve(values.size());
55   for (std::size_t i = 0; i < values.size(); ++i)
56     v.emplace_back(values[i], throw_after);
57 
58   throwing_data<T>* old_data = v.data();
59   std::size_t old_size       = v.size();
60   std::size_t old_cap        = v.capacity();
61   std::size_t new_cap        = 2 * old_cap;
62 
63   try {
64     v.reserve(new_cap);
65   } catch (...) {
66     assert(v.data() == old_data);
67     assert(v.size() == old_size);
68     assert(v.capacity() == old_cap);
69     for (std::size_t i = 0; i < v.size(); ++i)
70       assert(v[i].data_ == values[i]);
71   }
72 }
73 
74 #if TEST_STD_VER >= 11
75 
76 template <typename T, typename Alloc>
77 void test_move_ctor_exception_for_basic_guarantee(std::vector<move_only_throwing_t<T>, Alloc>& v,
78                                                   const std::vector<T>& values) {
79   assert(v.empty() && !values.empty());
80   int throw_after = values.size() + values.size() / 2; // Trigger an exception halfway through reallocation
81   v.reserve(values.size());
82   for (std::size_t i = 0; i < values.size(); ++i)
83     v.emplace_back(values[i], throw_after);
84 
85   try {
86     v.reserve(2 * v.capacity());
87   } catch (...) {
88     use_unspecified_but_valid_state_vector(v);
89   }
90 }
91 
92 #endif
93 
94 // Check the strong exception guarantee during reallocation failures
95 void test_allocation_exceptions() {
96   //
97   // Tests for std::length_error during reallocation failures
98   //
99   {
100     std::vector<int> v;
101     test_allocation_exception_for_strong_guarantee(v, std::vector<int>(), v.max_size() + 1);
102   }
103   check_new_delete_called();
104 
105   {
106     int a[] = {1, 2, 3, 4, 5};
107     std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
108     std::vector<int> v(in.begin(), in.end());
109     test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
110   }
111   check_new_delete_called();
112 
113   {
114     int a[] = {1, 2, 3, 4, 5};
115     std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
116     std::vector<int, min_allocator<int> > v(in.begin(), in.end());
117     test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
118   }
119   check_new_delete_called();
120 
121   {
122     int a[] = {1, 2, 3, 4, 5};
123     std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
124     std::vector<int, safe_allocator<int> > v(in.begin(), in.end());
125     test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
126   }
127   check_new_delete_called();
128 
129   {
130     int a[] = {1, 2, 3, 4, 5};
131     std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
132     std::vector<int, test_allocator<int> > v(in.begin(), in.end());
133     test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
134   }
135   check_new_delete_called();
136 
137   {
138     std::vector<int> in(10, 42);
139     std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end());
140     test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
141   }
142   check_new_delete_called();
143 
144 #if TEST_STD_VER >= 23
145   {
146     std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
147     std::vector<int, increasing_allocator<int>> v(in.begin(), in.end());
148     test_allocation_exception_for_strong_guarantee(v, in, v.max_size() + 1);
149   }
150   check_new_delete_called();
151 #endif
152 
153   //
154   // Tests for std::bad_alloc during reallocation failures
155   //
156   {
157     std::vector<int> in(10, 42);
158     std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end());
159     test_allocation_exception_for_strong_guarantee(v, in, 91);
160   }
161   check_new_delete_called();
162 
163   {
164     std::vector<int> in(10, 42);
165     std::vector<int, limited_allocator<int, 100> > v(in.begin(), in.end());
166     v.reserve(30);
167     test_allocation_exception_for_strong_guarantee(v, in, 61);
168   }
169   check_new_delete_called();
170 
171 #if TEST_STD_VER >= 11
172   {
173     std::vector<MoveOnly> in(10);
174     std::vector<MoveOnly, limited_allocator<MoveOnly, 100> > v(10);
175     test_allocation_exception_for_strong_guarantee(v, in, 91);
176   }
177   check_new_delete_called();
178 
179   {
180     std::vector<MoveOnly> in(10);
181     in.insert(in.cbegin() + 5, MoveOnly(42));
182     std::vector<MoveOnly, limited_allocator<MoveOnly, 100> > v(10);
183     v.reserve(30);
184     v.insert(v.cbegin() + 5, MoveOnly(42));
185     test_allocation_exception_for_strong_guarantee(v, in, 61);
186   }
187   check_new_delete_called();
188 #endif
189 
190   { // Practical example: Testing with 100 integers.
191     auto in = getIntegerInputs(100);
192     std::vector<int, limited_allocator<int, 299> > v(in.begin(), in.end());
193     test_allocation_exception_for_strong_guarantee(v, in, 200);
194   }
195   check_new_delete_called();
196 
197   { // Practical example: Testing with 100 strings, each 256 characters long.
198     std::vector<std::string> in = getStringInputsWithLength(100, 256);
199     std::vector<std::string, limited_allocator<std::string, 299> > v(in.begin(), in.end());
200     test_allocation_exception_for_strong_guarantee(v, in, 200);
201   }
202   check_new_delete_called();
203 }
204 
205 // Check the strong exception guarantee during copy-constructor failures
206 void test_copy_ctor_exceptions() {
207   {
208     int a[] = {1, 2, 3, 4, 5};
209     std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
210     std::vector<throwing_data<int> > v;
211     test_copy_ctor_exception_for_strong_guarantee(v, in);
212   }
213   check_new_delete_called();
214 
215   {
216     int a[] = {1, 2, 3, 4, 5};
217     std::vector<int> in(a, a + sizeof(a) / sizeof(a[0]));
218     std::vector<throwing_data<int>, min_allocator<throwing_data<int> > > v;
219     test_copy_ctor_exception_for_strong_guarantee(v, in);
220   }
221   check_new_delete_called();
222 
223   {
224     std::vector<int> in(10, 42);
225     std::vector<throwing_data<int>, safe_allocator<throwing_data<int> > > v;
226     test_copy_ctor_exception_for_strong_guarantee(v, in);
227   }
228   check_new_delete_called();
229 
230   {
231     std::vector<int> in(10, 42);
232     std::vector<throwing_data<int>, test_allocator<throwing_data<int> > > v;
233     test_copy_ctor_exception_for_strong_guarantee(v, in);
234   }
235   check_new_delete_called();
236 
237   {
238     std::vector<int> in(10, 42);
239     std::vector<throwing_data<int>, limited_allocator<throwing_data<int>, 100> > v;
240     test_copy_ctor_exception_for_strong_guarantee(v, in);
241   }
242   check_new_delete_called();
243 
244 #if TEST_STD_VER >= 23
245   {
246     std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
247     std::vector<throwing_data<int>, increasing_allocator<throwing_data<int>>> v;
248     test_copy_ctor_exception_for_strong_guarantee(v, in);
249   }
250   check_new_delete_called();
251 #endif
252 
253   { // Practical example: Testing with 100 integers.
254     auto in = getIntegerInputs(100);
255     std::vector<throwing_data<int> > v;
256     test_copy_ctor_exception_for_strong_guarantee(v, in);
257   }
258   check_new_delete_called();
259 
260   { // Practical example: Testing with 100 strings, each 256 characters long.
261     std::vector<std::string> in = getStringInputsWithLength(100, 256);
262     std::vector<throwing_data<std::string> > v;
263     test_copy_ctor_exception_for_strong_guarantee(v, in);
264   }
265   check_new_delete_called();
266 }
267 
268 #if TEST_STD_VER >= 11
269 
270 // Check that if T is Cpp17MoveInsertible && !Cpp17CopyInsertible, and T's move-ctor is not noexcept, then
271 // std::vector::reserve only provides basic guarantee.
272 void test_move_ctor_exceptions() {
273   {
274     std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
275     std::vector<move_only_throwing_t<int>> v;
276     test_move_ctor_exception_for_basic_guarantee(v, in);
277   }
278   check_new_delete_called();
279 
280 #  if TEST_STD_VER >= 23
281   {
282     std::vector<int> in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
283     std::vector<move_only_throwing_t<int>, increasing_allocator<move_only_throwing_t<int>>> v;
284     test_move_ctor_exception_for_basic_guarantee(v, in);
285   }
286   check_new_delete_called();
287 #  endif
288 
289   {
290     // Practical example: Testing with 100 strings, each 256 characters long.
291     std::vector<std::string> in = getStringInputsWithLength(100, 256);
292     std::vector<move_only_throwing_t<std::string> > v;
293     test_move_ctor_exception_for_basic_guarantee(v, in);
294   }
295   check_new_delete_called();
296 }
297 
298 #endif
299 
300 int main(int, char**) {
301   test_allocation_exceptions();
302   test_copy_ctor_exceptions();
303 #if TEST_STD_VER >= 11
304   test_move_ctor_exceptions();
305 #endif
306 }
307