1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: no-exceptions
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
18 #include <type_traits>
21 #include "../common.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"
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();
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
]);
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
);
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
;
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
]);
74 #if TEST_STD_VER >= 11
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
);
86 v
.reserve(2 * v
.capacity());
88 use_unspecified_but_valid_state_vector(v
);
94 // Check the strong exception guarantee during reallocation failures
95 void test_allocation_exceptions() {
97 // Tests for std::length_error during reallocation failures
101 test_allocation_exception_for_strong_guarantee(v
, std::vector
<int>(), v
.max_size() + 1);
103 check_new_delete_called();
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);
111 check_new_delete_called();
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);
119 check_new_delete_called();
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);
127 check_new_delete_called();
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);
135 check_new_delete_called();
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);
142 check_new_delete_called();
144 #if TEST_STD_VER >= 23
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);
150 check_new_delete_called();
154 // Tests for std::bad_alloc during reallocation failures
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);
161 check_new_delete_called();
164 std::vector
<int> in(10, 42);
165 std::vector
<int, limited_allocator
<int, 100> > v(in
.begin(), in
.end());
167 test_allocation_exception_for_strong_guarantee(v
, in
, 61);
169 check_new_delete_called();
171 #if TEST_STD_VER >= 11
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);
177 check_new_delete_called();
180 std::vector
<MoveOnly
> in(10);
181 in
.insert(in
.cbegin() + 5, MoveOnly(42));
182 std::vector
<MoveOnly
, limited_allocator
<MoveOnly
, 100> > v(10);
184 v
.insert(v
.cbegin() + 5, MoveOnly(42));
185 test_allocation_exception_for_strong_guarantee(v
, in
, 61);
187 check_new_delete_called();
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);
195 check_new_delete_called();
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);
202 check_new_delete_called();
205 // Check the strong exception guarantee during copy-constructor failures
206 void test_copy_ctor_exceptions() {
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
);
213 check_new_delete_called();
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
);
221 check_new_delete_called();
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
);
228 check_new_delete_called();
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
);
235 check_new_delete_called();
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
);
242 check_new_delete_called();
244 #if TEST_STD_VER >= 23
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
);
250 check_new_delete_called();
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
);
258 check_new_delete_called();
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
);
265 check_new_delete_called();
268 #if TEST_STD_VER >= 11
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() {
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
);
278 check_new_delete_called();
280 # if TEST_STD_VER >= 23
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
);
286 check_new_delete_called();
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
);
295 check_new_delete_called();
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();