xref: /llvm-project/libcxx/test/std/containers/sequences/vector/vector.modifiers/erase_iter.pass.cpp (revision 3a3517c5e9d45a1d1aae5320887478b228b0f8be)
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 // <vector>
10 
11 // iterator erase(const_iterator position);
12 
13 #include <vector>
14 #include <cassert>
15 #include <memory>
16 
17 #include "asan_testing.h"
18 #include "common.h"
19 #include "min_allocator.h"
20 #include "MoveOnly.h"
21 #include "test_macros.h"
22 
23 template <template <class> class Allocator, class T>
24 TEST_CONSTEXPR_CXX20 void tests() {
25   {
26     T arr[]             = {T(1), T(2), T(3), T(4), T(5)};
27     using Vector        = std::vector<T, Allocator<T> >;
28     using Iterator      = typename Vector::iterator;
29 
30     {
31       Vector v(arr, arr + 5);
32       Iterator it = v.erase(v.cbegin());
33       assert(v == Vector(arr + 1, arr + 5));
34       assert(it == v.begin());
35       assert(is_contiguous_container_asan_correct(v));
36     }
37     {
38       T expected[] = {T(1), T(3), T(4), T(5)};
39       Vector v(arr, arr + 5);
40       Iterator it = v.erase(v.cbegin() + 1);
41       assert(v == Vector(expected, expected + 4));
42       assert(it == v.begin() + 1);
43       assert(is_contiguous_container_asan_correct(v));
44     }
45     {
46       T expected[] = {T(1), T(2), T(3), T(4)};
47       Vector v(arr, arr + 5);
48       Iterator it = v.erase(v.cbegin() + 4);
49       assert(v == Vector(expected, expected + 4));
50       assert(it == v.end());
51       assert(is_contiguous_container_asan_correct(v));
52     }
53   }
54 
55   // Make sure vector::erase works with move-only types
56   {
57     // When non-trivial
58     {
59       std::vector<MoveOnly, Allocator<MoveOnly> > v;
60       v.emplace_back(1);
61       v.emplace_back(2);
62       v.emplace_back(3);
63       v.erase(v.begin());
64       assert(v.size() == 2);
65       assert(v[0] == MoveOnly(2));
66       assert(v[1] == MoveOnly(3));
67     }
68     // When trivial
69     {
70       std::vector<TrivialMoveOnly, Allocator<TrivialMoveOnly> > v;
71       v.emplace_back(1);
72       v.emplace_back(2);
73       v.emplace_back(3);
74       v.erase(v.begin());
75       assert(v.size() == 2);
76       assert(v[0] == TrivialMoveOnly(2));
77       assert(v[1] == TrivialMoveOnly(3));
78     }
79   }
80 }
81 
82 TEST_CONSTEXPR_CXX20 bool tests() {
83   tests<std::allocator, int>();
84   tests<std::allocator, NonTriviallyRelocatable>();
85   tests<min_allocator, int>();
86   tests<min_allocator, NonTriviallyRelocatable>();
87   return true;
88 }
89 
90 int main(int, char**) {
91   tests();
92 #if TEST_STD_VER > 17
93   static_assert(tests());
94 #endif
95 
96 #ifndef TEST_HAS_NO_EXCEPTIONS
97   // Test for LWG2853:
98   // Throws: Nothing unless an exception is thrown by the assignment operator or move assignment operator of T.
99   {
100     Throws arr[] = {1, 2, 3};
101     std::vector<Throws> v(arr, arr + 3);
102     Throws::sThrows = true;
103     v.erase(v.begin());
104     v.erase(--v.end());
105     v.erase(v.begin());
106     assert(v.size() == 0);
107   }
108 #endif
109 
110   // Make sure we satisfy the complexity requirement in terms of the number of times the assignment
111   // operator is called.
112   //
113   // There is currently ambiguity as to whether this is truly mandated by the Standard, so we only
114   // test it for libc++.
115 #ifdef _LIBCPP_VERSION
116   {
117     Tracker tracker;
118     std::vector<TrackedAssignment> v;
119 
120     // Set up the vector with 5 elements.
121     for (int i = 0; i != 5; ++i) {
122       v.emplace_back(&tracker);
123     }
124     assert(tracker.copy_assignments == 0);
125     assert(tracker.move_assignments == 0);
126 
127     // Erase element [1] from it. Elements [2] [3] [4] should be shifted, so we should
128     // see 3 move assignments (and nothing else).
129     v.erase(v.begin() + 1);
130     assert(v.size() == 4);
131     assert(tracker.copy_assignments == 0);
132     assert(tracker.move_assignments == 3);
133   }
134 #endif
135 
136   return 0;
137 }
138