Skip to content

Commit 931a0cb

Browse files
committed
Review comments
1 parent a4a5c3e commit 931a0cb

File tree

1 file changed

+29
-47
lines changed

1 file changed

+29
-47
lines changed

libcxx/test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -22,35 +22,15 @@
2222
#include "asan_testing.h"
2323
#include "common.h"
2424
#include "min_allocator.h"
25+
#include "MoveOnly.h"
2526
#include "test_allocator.h"
2627
#include "test_macros.h"
2728

28-
struct MoveOnly {
29-
int value;
30-
31-
TEST_CONSTEXPR_CXX14 explicit MoveOnly(int i) : value(i) {}
32-
33-
MoveOnly(MoveOnly const&) = delete;
34-
MoveOnly& operator=(MoveOnly const&) = delete;
35-
36-
TEST_CONSTEXPR_CXX14 MoveOnly(MoveOnly&& other) TEST_NOEXCEPT : value(other.value) { other.value = -1; }
37-
38-
TEST_CONSTEXPR_CXX14 MoveOnly& operator=(MoveOnly&& other) TEST_NOEXCEPT {
39-
value = other.value;
40-
other.value = -1;
41-
return *this;
42-
}
43-
44-
TEST_CONSTEXPR_CXX14 friend bool operator==(MoveOnly const& lhs, MoveOnly const& rhs) {
45-
return lhs.value == rhs.value;
46-
}
47-
};
48-
4929
template <class T>
50-
struct has_moved_from_sentinel : std::false_type {};
30+
struct has_moved_from_sentinel_value : std::false_type {};
5131

5232
template <>
53-
struct has_moved_from_sentinel<MoveOnly> : std::true_type {};
33+
struct has_moved_from_sentinel_value<MoveOnly> : std::true_type {};
5434

5535
template <template <class...> class Allocator, class T>
5636
TEST_CONSTEXPR_CXX20 void test() {
@@ -226,48 +206,48 @@ TEST_CONSTEXPR_CXX20 void test() {
226206
// When capacity must increase
227207
{
228208
Vector v;
229-
v.emplace_back(0);
230209
v.emplace_back(1);
210+
v.emplace_back(2);
231211

232212
while (v.size() < v.capacity()) {
233-
v.emplace_back(2);
213+
v.emplace_back(3);
234214
}
235215
assert(v.size() == v.capacity());
236-
// vector is {0, 1, 2...}
216+
// vector is {1, 2, 3...}
237217

238218
std::size_t old_cap = v.capacity();
239219
v.emplace(v.cbegin(), std::move(v[1]));
240220
assert(v.capacity() > old_cap); // test the test
241221

242-
// vector is {1, 0, -1, 2...}
243-
// Note that old v[1] has been set to -1 when it was moved-from
222+
// vector is {2, 1, 0, 3...}
223+
// Note that old v[1] has been set to 0 when it was moved-from
244224
assert(v.size() >= 3);
245-
assert(v[0] == T(1));
246-
assert(v[1] == T(0));
247-
if (has_moved_from_sentinel<T>::value)
248-
assert(v[2] == T(-1));
225+
assert(v[0] == T(2));
226+
assert(v[1] == T(1));
227+
if (has_moved_from_sentinel_value<T>::value)
228+
assert(v[2] == T(0));
249229
assert(is_contiguous_container_asan_correct(v));
250230
}
251231

252232
// When elements shift around
253233
{
254234
Vector v;
255-
v.emplace_back(0);
256235
v.emplace_back(1);
257-
// vector is {0, 1}
236+
v.emplace_back(2);
237+
// vector is {1, 2}
258238

259239
v.reserve(3);
260240
std::size_t old_cap = v.capacity();
261241
v.emplace(v.cbegin(), std::move(v[1]));
262242
assert(v.capacity() == old_cap); // test the test
263243

264-
// vector is {1, 0, -1}
265-
// Note that old v[1] has been set to -1 when it was moved-from
244+
// vector is {2, 1, 0}
245+
// Note that old v[1] has been set to 0 when it was moved-from
266246
assert(v.size() == 3);
267-
assert(v[0] == T(1));
268-
assert(v[1] == T(0));
269-
if (has_moved_from_sentinel<T>::value)
270-
assert(v[2] == T(-1));
247+
assert(v[0] == T(2));
248+
assert(v[1] == T(1));
249+
if (has_moved_from_sentinel_value<T>::value)
250+
assert(v[2] == T(0));
271251
assert(is_contiguous_container_asan_correct(v));
272252
}
273253
}
@@ -301,12 +281,14 @@ TEST_CONSTEXPR_CXX20 void test() {
301281
// on the stack and then moves it into its final location inside the newly allocated vector storage.
302282
//
303283
// If that were the case, and if the element happened to throw upon move construction or move assignment into its
304-
// final location, we would have invalidated iterators despite the overall emplace being required to have the
305-
// strong exception safety guarantee.
284+
// final location, we would have invalidated iterators, when a different approach would allow us to still provide
285+
// the strong exception safety guarantee.
306286
//
307-
// Instead, a conforming implementation needs to emplace the new element into its final location immediately, and
308-
// only after this has been done, then start making non-reversible changes to the vector's underlying storage.
309-
#ifndef TEST_HAS_NO_EXCEPTIONS
287+
// Instead of the naive approach, libc++ emplaces the new element into its final location immediately, and only
288+
// after this has been done do we start making non-reversible changes to the vector's underlying storage. This
289+
// test pins down that behavior, although that is something that we don't advertise widely and could potentially
290+
// change in the future.
291+
#if defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_EXCEPTIONS)
310292
{
311293
std::vector<ThrowingMove, Allocator<ThrowingMove> > v;
312294
v.emplace_back(0, /* do throw */ false);
@@ -317,15 +299,15 @@ TEST_CONSTEXPR_CXX20 void test() {
317299
}
318300
assert(v.size() == v.capacity()); // the next emplace will be forced to invalidate iterators
319301

320-
v.emplace(v.cend(), 3, /* do throw */ true); // this shouldn't throw since we shouldn't move
302+
v.emplace(v.cend(), 3, /* do throw */ true); // this shouldn't throw since we shouldn't move this element at all
321303

322304
assert(v.size() >= 3);
323305
assert(v[0] == ThrowingMove(0));
324306
assert(v[1] == ThrowingMove(1));
325307
assert(v.back() == ThrowingMove(3));
326308
assert(is_contiguous_container_asan_correct(v));
327309
}
328-
#endif // TEST_HAS_NO_EXCEPTIONS
310+
#endif // defined(_LIBCPP_VERSION) && !defined(TEST_HAS_NO_EXCEPTIONS)
329311
}
330312

331313
TEST_CONSTEXPR_CXX20 bool tests() {

0 commit comments

Comments
 (0)