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