1111// iterator erase(const_iterator position);
1212
1313#include < vector>
14- #include < iterator>
1514#include < cassert>
15+ #include < memory>
1616
1717#include " asan_testing.h"
18+ #include " common.h"
1819#include " min_allocator.h"
1920#include " MoveOnly.h"
2021#include " test_macros.h"
2122
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 (l1.begin ());
54- assert (is_contiguous_container_asan_correct (l1));
55- assert (l1 == std::vector<int >(a1 + 1 , a1 + 5 ));
56- }
23+ template <template <class > class Allocator , class T >
24+ TEST_CONSTEXPR_CXX20 void tests () {
5725 {
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 (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 (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 (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 (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- }
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+ using ConstIterator = typename Vector::const_iterator;
9030
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 ));
31+ {
32+ Vector v (arr, arr + 5 );
33+ Iterator it = v.erase (v.cbegin ());
34+ assert (v == Vector (arr + 1 , arr + 5 ));
35+ assert (it == v.begin ());
36+ assert (is_contiguous_container_asan_correct (v));
37+ }
38+ {
39+ T expected[] = {T (1 ), T (3 ), T (4 ), T (5 )};
40+ Vector v (arr, arr + 5 );
41+ Iterator it = v.erase (v.cbegin () + 1 );
42+ assert (v == Vector (expected, expected + 4 ));
43+ assert (it == v.begin () + 1 );
44+ assert (is_contiguous_container_asan_correct (v));
45+ }
46+ {
47+ T expected[] = {T (1 ), T (2 ), T (3 ), T (4 )};
48+ Vector v (arr, arr + 5 );
49+ Iterator it = v.erase (v.cbegin () + 4 );
50+ assert (v == Vector (expected, expected + 4 ));
51+ assert (it == v.end ());
52+ assert (is_contiguous_container_asan_correct (v));
53+ }
11354 }
11455
115- # if TEST_STD_VER >= 11
56+ // Make sure vector::erase works with move-only types
11657 {
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));
58+ // When non-trivial
59+ {
60+ std::vector<MoveOnly, Allocator<MoveOnly> > v;
61+ v.emplace_back (1 );
62+ v.emplace_back (2 );
63+ v.emplace_back (3 );
64+ v.erase (v.begin ());
65+ assert (v.size () == 2 );
66+ assert (v[0 ] == MoveOnly (2 ));
67+ assert (v[1 ] == MoveOnly (3 ));
68+ }
69+ // When trivial
70+ {
71+ std::vector<TrivialMoveOnly, Allocator<TrivialMoveOnly> > v;
72+ v.emplace_back (1 );
73+ v.emplace_back (2 );
74+ v.emplace_back (3 );
75+ v.erase (v.begin ());
76+ assert (v.size () == 2 );
77+ assert (v[0 ] == TrivialMoveOnly (2 ));
78+ assert (v[1 ] == TrivialMoveOnly (3 ));
79+ }
14080 }
141- # endif
81+ }
14282
83+ TEST_CONSTEXPR_CXX20 bool tests () {
84+ tests<std::allocator, int >();
85+ tests<std::allocator, NonTriviallyRelocatable>();
86+ tests<min_allocator, int >();
87+ tests<min_allocator, NonTriviallyRelocatable>();
14388 return true ;
14489}
14590
@@ -163,5 +108,26 @@ int main(int, char**) {
163108 }
164109#endif
165110
111+ // Make sure we satisfy the complexity requirement in terms of the number of times the assignment
112+ // operator is called.
113+ {
114+ Tracker tracker;
115+ std::vector<TrackedAssignment> v;
116+
117+ // Set up the vector with 5 elements.
118+ for (int i = 0 ; i != 5 ; ++i) {
119+ v.emplace_back (&tracker);
120+ }
121+ assert (tracker.copy_assignments == 0 );
122+ assert (tracker.move_assignments == 0 );
123+
124+ // Erase element [1] from it. Elements [2] [3] [4] should be shifted, so we should
125+ // see 3 move assignments (and nothing else).
126+ v.erase (v.begin () + 1 );
127+ assert (v.size () == 4 );
128+ assert (tracker.copy_assignments == 0 );
129+ assert (tracker.move_assignments == 3 );
130+ }
131+
166132 return 0 ;
167133}
0 commit comments