Skip to content

Commit 1a99937

Browse files
committed
Update libcxx/vector
1 parent 6b6a921 commit 1a99937

File tree

3 files changed

+324
-1
lines changed

3 files changed

+324
-1
lines changed

test/sources/libcxx/VectorTests.h

+6
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,12 @@ LIBCXX_TEST_BEGIN(capacity_reserve)
136136
#include "vector/vector.capacity/reserve.pass.cpp"
137137
LIBCXX_TEST_END
138138

139+
#ifndef LIBCXX_TEST_SEGMENTED_ARRAY
140+
LIBCXX_TEST_BEGIN(capacity_reserve_exceptions)
141+
#include "vector/vector.capacity/reserve_exceptions.pass.cpp"
142+
LIBCXX_TEST_END
143+
#endif
144+
139145
LIBCXX_TEST_BEGIN(capacity_resize_size)
140146
#include "vector/vector.capacity/resize_size.pass.cpp"
141147
LIBCXX_TEST_END

test/sources/libcxx/vector/common.h

+9-1
Original file line numberDiff line numberDiff line change
@@ -176,15 +176,23 @@ struct throwing_iterator {
176176
using pointer = T*;
177177

178178
int i_;
179-
mutable T v_;
179+
T v_;
180180

181181
explicit throwing_iterator(int i = 0, const T& v = T()) : i_(i), v_(v) {}
182182

183+
#if MOMO_VERSION_MAJOR > 3
183184
reference operator*() const {
185+
if (i_ == 1)
186+
throw 1;
187+
return const_cast<reference>(v_);
188+
}
189+
#else
190+
reference operator*() {
184191
if (i_ == 1)
185192
throw 1;
186193
return v_;
187194
}
195+
#endif
188196

189197
friend bool operator==(const throwing_iterator& lhs, const throwing_iterator& rhs) { return lhs.i_ == rhs.i_; }
190198
friend bool operator!=(const throwing_iterator& lhs, const throwing_iterator& rhs) { return lhs.i_ != rhs.i_; }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,309 @@
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+
// Modified for https://github.com/morzhovets/momo project.
10+
//
11+
//===----------------------------------------------------------------------===//
12+
13+
// UNSUPPORTED: no-exceptions
14+
15+
// This test file validates that std::vector<T>::reserve provides the strong exception guarantee if T is
16+
// Cpp17MoveInsertable and no exception is thrown by the move constructor of T during the reserve call.
17+
// It also checks that if T's move constructor is not noexcept, reserve provides only the basic exception
18+
// guarantee.
19+
20+
#include "../common.h"
21+
22+
template <typename T, typename Alloc>
23+
void test_allocation_exception_for_strong_guarantee(
24+
std::vector<T, Alloc>& v, const std::vector<T>& values, std::size_t new_cap) {
25+
assert(v.size() == values.size());
26+
T* old_data = v.data();
27+
std::size_t old_size = v.size();
28+
std::size_t old_cap = v.capacity();
29+
30+
try {
31+
v.reserve(new_cap);
32+
} catch (...) { // std::length_error, std::bad_alloc
33+
assert(v.data() == old_data);
34+
assert(v.size() == old_size);
35+
assert(v.capacity() == old_cap);
36+
for (std::size_t i = 0; i < v.size(); ++i)
37+
assert(v[i] == values[i]);
38+
return;
39+
}
40+
assert(false);
41+
}
42+
43+
template <typename T, typename Alloc>
44+
void test_copy_ctor_exception_for_strong_guarantee(std::vector<throwing_data<T>, Alloc>& v,
45+
const std::vector<T>& values) {
46+
assert(v.empty() && !values.empty());
47+
int throw_after = static_cast<int>(values.size() + values.size() / 2); // Trigger an exception halfway through reallocation
48+
v.reserve(values.size());
49+
for (std::size_t i = 0; i < values.size(); ++i)
50+
v.emplace_back(values[i], throw_after);
51+
52+
#ifndef LIBCXX_TEST_SEGMENTED_ARRAY
53+
throwing_data<T>* old_data = v.data();
54+
#endif
55+
std::size_t old_size = v.size();
56+
std::size_t old_cap = v.capacity();
57+
std::size_t new_cap = 2 * old_cap;
58+
59+
try {
60+
v.reserve(new_cap);
61+
} catch (...) {
62+
assert(v.data() == old_data);
63+
assert(v.size() == old_size);
64+
assert(v.capacity() == old_cap);
65+
for (std::size_t i = 0; i < v.size(); ++i)
66+
assert(v[i].data_ == values[i]);
67+
return;
68+
}
69+
assert(false);
70+
}
71+
72+
#if TEST_STD_VER >= 11
73+
74+
template <typename T, typename Alloc>
75+
void test_move_ctor_exception_for_basic_guarantee(std::vector<move_only_throwing_t<T>, Alloc>& v,
76+
const std::vector<T>& values) {
77+
assert(v.empty() && !values.empty());
78+
int throw_after = static_cast<int>(values.size() + values.size() / 2); // Trigger an exception halfway through reallocation
79+
v.reserve(values.size());
80+
for (std::size_t i = 0; i < values.size(); ++i)
81+
v.emplace_back(values[i], throw_after);
82+
83+
try {
84+
v.reserve(2 * v.capacity());
85+
} catch (...) {
86+
use_unspecified_but_valid_state_vector(v);
87+
return;
88+
}
89+
assert(false);
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, ULLONG_MAX/*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+
#ifdef LIBCPP_HAS_BAD_NEWS_FOR_MOMO
305+
test_move_ctor_exceptions();
306+
#endif
307+
#endif
308+
return 0;
309+
}

0 commit comments

Comments
 (0)