// { dg-options "-std=gnu++20" } // { dg-do compile { target c++20 } } // { dg-xfail-if "not supported" { debug_mode } } #include #include template struct Alloc : std::allocator { using std::allocator::allocator; constexpr explicit Alloc(int p) : personality(p) { } template constexpr Alloc(const Alloc& a) : personality(a.personality) { } int personality = 0; constexpr bool operator==(const Alloc& a) const noexcept { return personality == a.personality; } }; constexpr bool test_push_back() { std::vector v; int& r = v.emplace_back(7); VERIFY( r == 7 ); VERIFY( &r == &v.front() ); v.emplace_back(r); v.emplace_back(v.front()); v.emplace_back(v.back()); VERIFY( v.size() == 4 ); v.emplace_back(8); VERIFY( v.size() == 5 ); VERIFY( v.back() == 8 ); v.pop_back(); VERIFY( v.size() == 4 ); VERIFY( v.back() == 7 ); v.pop_back(); v.pop_back(); v.pop_back(); v.pop_back(); VERIFY( v.empty() ); v.push_back(99); for (std::size_t i = 0, c = v.capacity(); i <= c; ++i) v.push_back(v.front()); VERIFY( v.capacity() > v.size() ); std::vector> va; va.push_back(99); va.push_back(va.front()); VERIFY( va.size() == 2 ); return true; } static_assert( test_push_back() ); template constexpr std::false_type pop_back_empty() { return {}; } template requires (std::bool_constant<(std::vector().pop_back(), true)>::value) constexpr std::true_type pop_back_empty() { return {}; } static_assert( ! pop_back_empty() ); constexpr bool test_insert_erase() { std::vector v; // vector::emplace(const_iterator, Args&&...) auto p = v.emplace(v.begin()); VERIFY( p == v.begin() ); p = v.emplace(v.end(), 7); VERIFY( p == --v.end() ); // vector::insert(const_iterator, const T&) p = v.insert(v.begin(), *p); VERIFY( p == v.begin() ); VERIFY( *p == 7 ); VERIFY( &*p == &v.front() ); // vector::insert(const_iterator, T&&) p = v.insert(v.end(), 1); VERIFY( p == --v.end() ); v.insert(p, v.front()); v.insert(v.end(), v.back()); VERIFY( v.size() == 6 ); v.insert(v.end(), 8); VERIFY( v.size() == 7 ); VERIFY( v.back() == 8 ); // vector::insert(const_iterator, size_type, const T&) v.insert(v.begin(), 2, v.front()); v.insert(v.end(), 3, 99); VERIFY( v.size() == 12 ); struct input_iterator { using iterator_category = std::input_iterator_tag; using value_type = int; using pointer = const int*; using reference = int; using difference_type = int; constexpr input_iterator() : val(0) { } constexpr input_iterator(int i) : val(i) { } constexpr input_iterator& operator++() { --val; return *this; } constexpr input_iterator operator++(int) { return {val--}; } constexpr int operator*() const { return val; } constexpr const int* operator->() const { return &val; } constexpr bool operator==(const input_iterator&) const = default; int val; }; // vector::insert(const_iterator, Iter, Iter); v.insert(v.begin() + 2, input_iterator(), input_iterator()); VERIFY( v.size() == 12 ); v.reserve(13); auto n = v.capacity() - v.size(); v.insert(v.end() - 9, input_iterator(n), input_iterator()); // no reallocation VERIFY( v.size() == (12 + n) ); short a[] = { 84, 85 }; v.insert(v.end() - 1, a, a + 2); // reallocation needed VERIFY( v.size() == (12 + n + 2) ); v.resize(32); // vector::insert(const_iterator, initializer_list) v.insert(v.begin(), {1,2,3}); VERIFY( v.size() == 35 ); v.rbegin()[0] = 999; v.rbegin()[1] = 888; // vector::erase(const_iterator) v.erase(v.end() - 1); VERIFY( v.size() == 34 ); VERIFY( v.back() == 888 ); v.erase(v.begin()); v.erase(v.begin() + 1); v.erase(v.end() - 1); VERIFY( v.size() == 31 ); // vector::erase(const_iterator, const_iterator) v.erase(v.begin(), v.begin()); v.erase(v.end(), v.end()); v.erase(v.begin(), v.begin() + 1); VERIFY( v.size() == 30 ); v.erase(v.begin() + 2, v.end() - 2); VERIFY( v.size() == 4 ); v.erase(v.begin(), v.end()); VERIFY( v.empty() ); v.erase( v.begin(), v.begin() ); VERIFY( v.empty() ); v.insert(v.end(), 99); for (std::size_t i = 0, c = v.capacity(); i <= c; ++i) v.insert(v.end() - 1, v.front()); VERIFY( v.capacity() > v.size() ); v.insert(v.end(), 999); for (std::size_t i = 0, c = v.capacity(); i <= c; ++i) v.insert(v.begin(), v.front()); std::vector> va; va.insert(va.begin(), 99); va.insert(va.begin(), va.front()); VERIFY( va.size() == 2 ); va.erase(va.begin()); return true; } static_assert( test_insert_erase() ); constexpr bool test_clear() { std::vector v0; v0.clear(); VERIFY( v0.size() == 0 ); VERIFY( v0.capacity() == 0 ); std::vector v{1, 10, 100}; v.clear(); VERIFY( v.size() == 0 ); VERIFY( v.capacity() == 3 ); std::vector> va; va.clear(); va.push_back(1); va.clear(); va.clear(); return true; } static_assert( test_clear() ); constexpr bool test_erasure() { const char* names[] = { "Vince", "Clarke", "Andy", "Bell" }; std::vector e(std::begin(names), std::end(names)); auto n = std::erase(e, names[0]); VERIFY( n == 1 ); VERIFY( e.size() == 3 ); n = std::erase_if(e, [](auto name) { return name[4] == '\0'; }); VERIFY( n == 2 ); VERIFY( e.size() == 1 ); return true; } static_assert( test_erasure() );