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 <iterator> |
15 | #include <cassert> |
16 | |
17 | #include "asan_testing.h" |
18 | #include "min_allocator.h" |
19 | #include "MoveOnly.h" |
20 | #include "test_macros.h" |
21 | |
22 | #ifndef TEST_HAS_NO_EXCEPTIONS |
23 | struct Throws { |
24 | Throws() : v_(0) {} |
25 | Throws(int v) : v_(v) {} |
26 | Throws(const Throws& rhs) : v_(rhs.v_) { |
27 | if (sThrows) |
28 | throw 1; |
29 | } |
30 | Throws(Throws&& rhs) : v_(rhs.v_) { |
31 | if (sThrows) |
32 | throw 1; |
33 | } |
34 | Throws& operator=(const Throws& rhs) { |
35 | v_ = rhs.v_; |
36 | return *this; |
37 | } |
38 | Throws& operator=(Throws&& rhs) { |
39 | v_ = rhs.v_; |
40 | return *this; |
41 | } |
42 | int v_; |
43 | static bool sThrows; |
44 | }; |
45 | |
46 | bool Throws::sThrows = false; |
47 | #endif |
48 | |
49 | TEST_CONSTEXPR_CXX20 bool tests() { |
50 | { |
51 | int a1[] = {1, 2, 3, 4, 5}; |
52 | std::vector<int> l1(a1, a1 + 5); |
53 | l1.erase(position: l1.begin()); |
54 | assert(is_contiguous_container_asan_correct(l1)); |
55 | assert(l1 == std::vector<int>(a1 + 1, a1 + 5)); |
56 | } |
57 | { |
58 | int a1[] = {1, 2, 3, 4, 5}; |
59 | int e1[] = {1, 3, 4, 5}; |
60 | std::vector<int> l1(a1, a1 + 5); |
61 | l1.erase(position: l1.begin() + 1); |
62 | assert(is_contiguous_container_asan_correct(l1)); |
63 | assert(l1 == std::vector<int>(e1, e1 + 4)); |
64 | } |
65 | { |
66 | int a1[] = {1, 2, 3}; |
67 | std::vector<int> l1(a1, a1 + 3); |
68 | std::vector<int>::const_iterator i = l1.begin(); |
69 | assert(is_contiguous_container_asan_correct(l1)); |
70 | ++i; |
71 | std::vector<int>::iterator j = l1.erase(position: i); |
72 | assert(l1.size() == 2); |
73 | assert(std::distance(l1.begin(), l1.end()) == 2); |
74 | assert(*j == 3); |
75 | assert(*l1.begin() == 1); |
76 | assert(*std::next(l1.begin()) == 3); |
77 | assert(is_contiguous_container_asan_correct(l1)); |
78 | j = l1.erase(position: j); |
79 | assert(j == l1.end()); |
80 | assert(l1.size() == 1); |
81 | assert(std::distance(l1.begin(), l1.end()) == 1); |
82 | assert(*l1.begin() == 1); |
83 | assert(is_contiguous_container_asan_correct(l1)); |
84 | j = l1.erase(position: l1.begin()); |
85 | assert(j == l1.end()); |
86 | assert(l1.size() == 0); |
87 | assert(std::distance(l1.begin(), l1.end()) == 0); |
88 | assert(is_contiguous_container_asan_correct(l1)); |
89 | } |
90 | |
91 | // Make sure vector::erase works with move-only types |
92 | // When non-trivial |
93 | { |
94 | std::vector<MoveOnly> v; |
95 | v.emplace_back(1); |
96 | v.emplace_back(2); |
97 | v.emplace_back(3); |
98 | v.erase(v.begin()); |
99 | assert(v.size() == 2); |
100 | assert(v[0] == MoveOnly(2)); |
101 | assert(v[1] == MoveOnly(3)); |
102 | } |
103 | // When trivial |
104 | { |
105 | std::vector<TrivialMoveOnly> v; |
106 | v.emplace_back(1); |
107 | v.emplace_back(2); |
108 | v.emplace_back(3); |
109 | v.erase(v.begin()); |
110 | assert(v.size() == 2); |
111 | assert(v[0] == TrivialMoveOnly(2)); |
112 | assert(v[1] == TrivialMoveOnly(3)); |
113 | } |
114 | |
115 | #if TEST_STD_VER >= 11 |
116 | { |
117 | int a1[] = {1, 2, 3}; |
118 | std::vector<int, min_allocator<int>> l1(a1, a1 + 3); |
119 | std::vector<int, min_allocator<int>>::const_iterator i = l1.begin(); |
120 | assert(is_contiguous_container_asan_correct(l1)); |
121 | ++i; |
122 | std::vector<int, min_allocator<int>>::iterator j = l1.erase(i); |
123 | assert(l1.size() == 2); |
124 | assert(std::distance(l1.begin(), l1.end()) == 2); |
125 | assert(*j == 3); |
126 | assert(*l1.begin() == 1); |
127 | assert(*std::next(l1.begin()) == 3); |
128 | assert(is_contiguous_container_asan_correct(l1)); |
129 | j = l1.erase(j); |
130 | assert(j == l1.end()); |
131 | assert(l1.size() == 1); |
132 | assert(std::distance(l1.begin(), l1.end()) == 1); |
133 | assert(*l1.begin() == 1); |
134 | assert(is_contiguous_container_asan_correct(l1)); |
135 | j = l1.erase(l1.begin()); |
136 | assert(j == l1.end()); |
137 | assert(l1.size() == 0); |
138 | assert(std::distance(l1.begin(), l1.end()) == 0); |
139 | assert(is_contiguous_container_asan_correct(l1)); |
140 | } |
141 | #endif |
142 | |
143 | return true; |
144 | } |
145 | |
146 | int main(int, char**) { |
147 | tests(); |
148 | #if TEST_STD_VER > 17 |
149 | static_assert(tests()); |
150 | #endif |
151 | |
152 | #ifndef TEST_HAS_NO_EXCEPTIONS |
153 | // Test for LWG2853: |
154 | // Throws: Nothing unless an exception is thrown by the assignment operator or move assignment operator of T. |
155 | { |
156 | Throws arr[] = {1, 2, 3}; |
157 | std::vector<Throws> v(arr, arr + 3); |
158 | Throws::sThrows = true; |
159 | v.erase(position: v.begin()); |
160 | v.erase(position: --v.end()); |
161 | v.erase(position: v.begin()); |
162 | assert(v.size() == 0); |
163 | } |
164 | #endif |
165 | |
166 | return 0; |
167 | } |
168 | |