diff options
author | Jonathan Wakely <jwakely@redhat.com> | 2021-11-11 14:05:35 +0000 |
---|---|---|
committer | Jonathan Wakely <jwakely@redhat.com> | 2021-11-12 00:42:39 +0000 |
commit | 1ae8edf5f73ca5c3bf132cc52825dc1f709499dd (patch) | |
tree | 8bc8ecc241cb38121c561086139b9f08c44e022c /libstdc++-v3/testsuite | |
parent | b39265d4fe13e3e8ce5021642e5092e74effb643 (diff) | |
download | gcc-1ae8edf5f73ca5c3bf132cc52825dc1f709499dd.zip gcc-1ae8edf5f73ca5c3bf132cc52825dc1f709499dd.tar.gz gcc-1ae8edf5f73ca5c3bf132cc52825dc1f709499dd.tar.bz2 |
libstdc++: Implement constexpr std::vector for C++20
This implements P1004R2 ("Making std::vector constexpr") for C++20.
For now, debug mode vectors are not supported in constant expressions.
To make that work we might need to disable all attaching/detaching of
safe iterators. That can be fixed later.
Co-authored-by: Josh Marshall <joshua.r.marshall.1991@gmail.com>
libstdc++-v3/ChangeLog:
* include/bits/alloc_traits.h (_Destroy): Make constexpr for
C++20 mode.
* include/bits/allocator.h (__shrink_to_fit::_S_do_it):
Likewise.
* include/bits/stl_algobase.h (__fill_a1): Declare _Bit_iterator
overload constexpr for C++20.
* include/bits/stl_bvector.h (_Bit_type, _S_word_bit): Move out
of inline namespace.
(_Bit_reference, _Bit_iterator_base, _Bit_iterator)
(_Bit_const_iterator, _Bvector_impl_data, _Bvector_base)
(vector<bool, A>>): Add constexpr to every member function.
(_Bvector_base::_M_allocate): Initialize storage during constant
evaluation.
(vector<bool, A>::_M_initialize_value): Use __fill_bvector_n
instead of memset.
(__fill_bvector_n): New helper function to replace memset during
constant evaluation.
* include/bits/stl_uninitialized.h (__uninitialized_copy<false>):
Move logic to ...
(__do_uninit_copy): New function.
(__uninitialized_fill<false>): Move logic to ...
(__do_uninit_fill): New function.
(__uninitialized_fill_n<false>): Move logic to ...
(__do_uninit_fill_n): New function.
(__uninitialized_copy_a): Add constexpr. Use __do_uninit_copy.
(__uninitialized_move_a, __uninitialized_move_if_noexcept_a):
Add constexpr.
(__uninitialized_fill_a): Add constexpr. Use __do_uninit_fill.
(__uninitialized_fill_n_a): Add constexpr. Use
__do_uninit_fill_n.
(__uninitialized_default_n, __uninitialized_default_n_a)
(__relocate_a_1, __relocate_a): Add constexpr.
* include/bits/stl_vector.h (_Vector_impl_data, _Vector_impl)
(_Vector_base, vector): Add constexpr to every member function.
(_Vector_impl::_S_adjust): Disable ASan annotation during
constant evaluation.
(_Vector_base::_S_use_relocate): Disable bitwise-relocation
during constant evaluation.
(vector::_Temporary_value): Use a union for storage.
* include/bits/vector.tcc (vector, vector<bool>): Add constexpr
to every member function.
* include/std/vector (erase_if, erase): Add constexpr.
* testsuite/23_containers/headers/vector/synopsis.cc: Add
constexpr for C++20 mode.
* testsuite/23_containers/vector/bool/cmp_c++20.cc: Change to
compile-only test using constant expressions.
* testsuite/23_containers/vector/bool/capacity/29134.cc: Adjust
namespace for _S_word_bit.
* testsuite/23_containers/vector/bool/modifiers/insert/31370.cc:
Likewise.
* testsuite/23_containers/vector/cmp_c++20.cc: Likewise.
* testsuite/23_containers/vector/cons/89164.cc: Adjust errors
for C++20 and move C++17 test to ...
* testsuite/23_containers/vector/cons/89164_c++17.cc: ... here.
* testsuite/23_containers/vector/bool/capacity/constexpr.cc: New test.
* testsuite/23_containers/vector/bool/cons/constexpr.cc: New test.
* testsuite/23_containers/vector/bool/element_access/constexpr.cc: New test.
* testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc: New test.
* testsuite/23_containers/vector/bool/modifiers/constexpr.cc: New test.
* testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc: New test.
* testsuite/23_containers/vector/capacity/constexpr.cc: New test.
* testsuite/23_containers/vector/cons/constexpr.cc: New test.
* testsuite/23_containers/vector/data_access/constexpr.cc: New test.
* testsuite/23_containers/vector/element_access/constexpr.cc: New test.
* testsuite/23_containers/vector/modifiers/assign/constexpr.cc: New test.
* testsuite/23_containers/vector/modifiers/constexpr.cc: New test.
* testsuite/23_containers/vector/modifiers/swap/constexpr.cc: New test.
Diffstat (limited to 'libstdc++-v3/testsuite')
20 files changed, 2107 insertions, 49 deletions
diff --git a/libstdc++-v3/testsuite/23_containers/headers/vector/synopsis.cc b/libstdc++-v3/testsuite/23_containers/headers/vector/synopsis.cc index 0fc46fe..f02659f 100644 --- a/libstdc++-v3/testsuite/23_containers/headers/vector/synopsis.cc +++ b/libstdc++-v3/testsuite/23_containers/headers/vector/synopsis.cc @@ -27,13 +27,21 @@ # define NOTHROW(X) #endif +#if __cplusplus >= 202002L +# define CONSTEXPR constexpr +#else +# define CONSTEXPR +#endif + namespace std { template <class T, class Allocator> class vector; template <class T, class Allocator> + CONSTEXPR bool operator==(const vector<T,Allocator>& x, const vector<T,Allocator>& y); +#if __cplusplus < 202002L template <class T, class Allocator> bool operator< (const vector<T,Allocator>& x, const vector<T,Allocator>& y); @@ -53,17 +61,21 @@ namespace std { template <class T, class Allocator> bool operator<=(const vector<T,Allocator>& x, const vector<T,Allocator>& y); +#endif template <class T, class Allocator> + CONSTEXPR void swap(vector<T,Allocator>& x, vector<T,Allocator>& y) NOTHROW(noexcept(x.swap(y))); template <class Allocator> class vector<bool,Allocator>; template <class Allocator> + CONSTEXPR bool operator==(const vector<bool,Allocator>& x, const vector<bool,Allocator>& y); +#if __cplusplus < 202002L template <class Allocator> bool operator< (const vector<bool,Allocator>& x, const vector<bool,Allocator>& y); @@ -83,7 +95,9 @@ namespace std { template <class Allocator> bool operator<=(const vector<bool,Allocator>& x, const vector<bool,Allocator>& y); +#endif template <class Allocator> + CONSTEXPR void swap(vector<bool,Allocator>& x, vector<bool,Allocator>& y); } diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/29134.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/29134.cc index 43f3343..da5e6b4 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/29134.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/29134.cc @@ -26,12 +26,7 @@ void test01() { using std::vector; using std::numeric_limits; - -#ifdef _GLIBCXX_DEBUG - using std::_GLIBCXX_STD_C::_S_word_bit; -#else using std::_S_word_bit; -#endif // Actually, vector<bool> is special, see libstdc++/31370. vector<bool> vb; diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc new file mode 100644 index 0000000..52b10b6 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc @@ -0,0 +1,115 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +constexpr std::size_t +capacity_for(std::size_t n) +{ + std::size_t N = std::vector<bool>(1).capacity(); + if (auto r = n % N) + return n - r + N; + return n; +} + +constexpr bool +test_empty() +{ + std::vector<bool> v; + VERIFY( v.empty() ); + v = {1}; + VERIFY( !v.empty() ); + + return true; +} + +static_assert( test_empty() ); + +constexpr bool +test_size() +{ + std::vector<bool> v; + VERIFY( v.size() == 0 ); + v = {1}; + VERIFY( v.size() == 1 ); + + VERIFY( v.max_size() != 0 ); + + return true; +} + +static_assert( test_size() ); + +constexpr bool +test_capacity() +{ + std::vector<bool> v; + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == v.size() ); + v = {false, false, false}; + VERIFY( v.size() == 3 ); + VERIFY( v.capacity() >= v.size() ); + + return true; +} + +static_assert( test_capacity() ); + +constexpr bool +test_resize() +{ + std::vector<bool> v; + v.reserve(9); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == capacity_for(9) ); + v.resize(5); + VERIFY( v.size() == 5 ); + VERIFY( v.capacity() == capacity_for(9) ); + v.resize(900, true); + VERIFY( v.size() == 900 ); + VERIFY( v.capacity() == capacity_for(900) ); + VERIFY( v[10] == true ); + + return true; +} + +static_assert( test_resize() ); + +constexpr bool +test_reserve() +{ + std::vector<bool> v; + v.reserve(9); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == capacity_for(9) ); + v.resize(2); + VERIFY( v.size() == 2 ); + VERIFY( v.capacity() == capacity_for(9) ); + v.resize(300); + v.resize(100); + VERIFY( v.size() == 100 ); + VERIFY( v.capacity() == capacity_for(300) ); + + return true; +} + +static_assert( test_reserve() ); + +constexpr bool +test_shrink_to_fit() +{ + std::vector<bool> v; + v.reserve(9); + v.shrink_to_fit(); + VERIFY( v.capacity() == 0 ); + v.reserve(9); + v.resize(5); + v.shrink_to_fit(); + VERIFY( v.capacity() == capacity_for(v.size()) ); + + return true; +} + +static_assert( test_shrink_to_fit() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc index 7a730df..ae2bd03 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cmp_c++20.cc @@ -16,12 +16,13 @@ // <http://www.gnu.org/licenses/>. // { dg-options "-std=gnu++2a" } -// { dg-do run { target c++2a } } +// { dg-do compile { target c++2a } } +// { dg-xfail-if "not supported" { debug-mode } } #include <vector> #include <testsuite_hooks.h> -void +constexpr bool test01() { std::vector<bool> c1{ 1, 0, 1 }, c2{ 1, 0, 1, 0 }, c3{ 1, 1, 1 }; @@ -38,9 +39,11 @@ test01() static_assert( std::three_way_comparable<std::vector<bool>, std::strong_ordering> ); + + return true; } -void +constexpr bool test05() { // vector<bool> iterators are random access, so should support <=> @@ -63,11 +66,9 @@ test05() static_assert( std::same_as<decltype(c.begin() <=> c.begin()), std::strong_ordering> ); -} -int -main() -{ - test01(); - test05(); + return true; } + +static_assert( test01() ); +static_assert( test05() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc new file mode 100644 index 0000000..edd5060 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc @@ -0,0 +1,280 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +template<typename T> +struct Alloc : std::allocator<T> +{ + using std::allocator<T>::allocator; + + constexpr explicit Alloc(int p) : personality(p) { } + + template<typename U> + constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { } + + int personality = 0; + + constexpr Alloc select_on_container_copy_construction() const + { return Alloc(-1); } + + constexpr bool operator==(const Alloc& a) const noexcept + { return personality == a.personality; } +}; + +namespace default_constructor_global_scope +{ + constexpr std::vector<bool> v1; + static_assert(v1.size() == 0); + static_assert(v1.capacity() == 0); + + constexpr std::allocator<bool> a; + constexpr std::vector<bool> v2(a); + static_assert(v2.size() == 0); + static_assert(v2.capacity() == 0); + + constexpr Alloc<bool> aa(10); + constexpr std::vector<bool, Alloc<bool>> v3(aa); + static_assert(v3.size() == 0); + static_assert(v3.capacity() == 0); + static_assert(v3.get_allocator() == aa); +} + +constexpr bool +default_constructor_function_scope() +{ + // vector() + + std::vector<bool> v1; + VERIFY(v1.size() == 0); + VERIFY(v1.capacity() == 0); + + // vector(const Allocator&) + + const std::allocator<bool> a; + std::vector<bool> v2(a); + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + const Alloc<bool> aa(10); + std::vector<bool, Alloc<bool>> v3(aa); + VERIFY(v3.size() == 0); + VERIFY(v3.capacity() == 0); + VERIFY(v3.get_allocator() == aa); + + return true; +} + +static_assert( default_constructor_function_scope() ); + +constexpr bool +sequence_constructors() +{ + // vector(size_type, const Allocator& = Allocator()) + + std::vector<bool> v0(0); + VERIFY(v0.size() == 0); + + std::vector<bool> v1(1); + VERIFY(v1.size() == 1); + + std::vector<bool> v2(2); + VERIFY(v2.size() == 2); + + std::vector<bool> v50(50); + VERIFY(v50.size() == 50); + + const std::allocator<bool> a; + std::vector<bool> a0(0, a); + VERIFY(a0.size() == 0); + + std::vector<bool> a1(1, a); + VERIFY(a1.size() == 1); + + std::vector<bool> a2(2, a); + VERIFY(a2.size() == 2); + + std::vector<bool> a50(50, a); + VERIFY(a50.size() == 50); + + const Alloc<bool> la(10); + std::vector<bool, Alloc<bool>> l0(0, la); + VERIFY(l0.size() == 0); + VERIFY(l0.get_allocator() == la); + + std::vector<bool, Alloc<bool>> l1(1, la); + VERIFY(l1.size() == 1); + VERIFY(l1.get_allocator() == la); + + std::vector<bool, Alloc<bool>> l2(2, la); + VERIFY(l2.size() == 2); + VERIFY(l2.get_allocator() == la); + + std::vector<bool, Alloc<bool>> l50(50, la); + VERIFY(l50.size() == 50); + VERIFY(l50.get_allocator() == la); + + // vector(size_type, const T&, const Allocator& = Allocator()) + + std::vector<bool> v3(3, true); + VERIFY(v3.size() == 3); + VERIFY(v3[0] == true && v3[2] == true); + + std::vector<bool> a3(3, false, a); + VERIFY(a3.size() == 3); + VERIFY(a3[0] == false && a3[2] == false); + + std::vector<bool, Alloc<bool>> l3(3, true, la); + VERIFY(l3.size() == 3); + VERIFY(l3[0] == true && l3[2] == true); + VERIFY(l3.get_allocator() == la); + + return true; +} + +static_assert(sequence_constructors()); + +constexpr bool +iterator_range_constructor() +{ + // vector(InputIterator, InputIterator, const Allocator& = Allocator()) + + short range[3] = { true, false, true }; + + std::vector<bool> v0(std::begin(range), std::end(range)); + VERIFY(v0.size() == std::size(range)); + VERIFY(v0[0] == true && v0[1] == false && v0[2] == true); + + const Alloc<bool> a(5); + std::vector<bool, Alloc<bool>> l0(std::begin(range), std::end(range), a); + VERIFY(l0.size() == std::size(range)); + VERIFY(l0.get_allocator() == a); + VERIFY(l0[0] == true && l0[1] == false && l0[2] == true); + + struct input_iterator + { + using iterator_category = std::input_iterator_tag; + using value_type = bool; + using pointer = const bool*; + using reference = bool; + 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 bool operator*() const { return val % 2; } + constexpr const bool* operator->() const { return nullptr; } + + constexpr bool operator==(const input_iterator&) const = default; + + int val; + }; + + std::vector<bool> v1(input_iterator(3), input_iterator()); + VERIFY(v1.size() == 3); + VERIFY(v1[0] == true && v1[1] == false && v1[2] == true); + + std::vector<bool, Alloc<bool>> l1(input_iterator(2), input_iterator(), a); + VERIFY(l1.size() == 2); + VERIFY(l1.get_allocator() == a); + VERIFY(l1[0] == false && l1[1] == true); + + return true; +} + +static_assert(iterator_range_constructor()); + +constexpr bool +initializer_list_constructor() +{ + // vector(initializer_list<T>, const Allocator& = Allocator()) + + std::vector<bool> v0({ false, true, false }); + VERIFY(v0.size() == 3); + VERIFY(v0[0] == false && v0[1] == true && v0[2] == false); + + const Alloc<bool> a(5); + std::vector<bool, Alloc<bool>> l0({ true, false, false }, a); + VERIFY(l0.size() == 3); + VERIFY(l0.get_allocator() == a); + VERIFY(l0[0] == true && l0[1] == false && l0[2] == false); + + return true; +} + +static_assert(initializer_list_constructor()); + +constexpr bool +copy_constructor() +{ + const std::vector<bool> v0({ 1, 0, 0, 1, 0, 1, 1, 0 }); + const std::vector<bool, Alloc<bool>> l0({ 0, 0, 1, 1, 0, 1, 0, 1, 1, 1 }); + + // vector(const vector&) + + std::vector<bool> v1(v0); + VERIFY( v1.size() == v0.size() ); + VERIFY( v1[0] == v0[0] && v1[1] == v0[1] && v1[2] == v0[2] ); + VERIFY( v1.get_allocator() == v0.get_allocator() ); + + const Alloc<bool> as(6); + std::vector<bool, Alloc<bool>> s1(3, true, as); + std::vector<bool, Alloc<bool>> s2(s1); + VERIFY( s2.size() == s1.size() ); + VERIFY( s2.get_allocator().personality == -1 ); + + // vector(const vector&, const Allocator&) + + const Alloc<bool> a(6); + std::vector<bool, Alloc<bool>> l1(l0, a); + VERIFY( l1.size() == l0.size() ); + VERIFY( l1[0] == l0[0] && l1[1] == l0[1] && l1[2] == l0[2] ); + VERIFY( l1.get_allocator() == a ); + VERIFY( l1.get_allocator() != l0.get_allocator() ); + + return true; +} + +static_assert(copy_constructor()); + +constexpr bool +move_constructor() +{ + const std::vector<bool> v0({ 1, 0, 0, 1, 0, 1, 1, 0 }); + const std::vector<bool, Alloc<bool>> l0({ 0, 0, 1, 1, 0, 1, 0, 1, 1, 1 }); + + // vector(const vector&) + + std::vector<bool> v1(v0); + std::vector<bool> v2(std::move(v1)); + VERIFY( v2.size() == v0.size() ); + VERIFY( v1.empty() ); + VERIFY( v2[0] == v0[0] && v2[1] == v0[1] && v2[2] == v0[2] ); + VERIFY( v2.get_allocator() == v0.get_allocator() ); + + // vector(const vector&, const Allocator&) + + const Alloc<bool> a(6); + std::vector<bool, Alloc<bool>> l1(l0); + std::vector<bool, Alloc<bool>> l2(std::move(l1), a); + VERIFY( l2.size() == l0.size() ); + VERIFY( l2[0] == l0[0] && l2[1] == l0[1] && l2[2] == l0[2] ); + VERIFY( l2.get_allocator() == a ); + VERIFY( l2.get_allocator() != l0.get_allocator() ); + + std::vector<bool, Alloc<bool>> l3(std::move(l2), a); + VERIFY( l3.size() == l0.size() ); + VERIFY( l3[0] == l0[0] && l3[1] == l0[1] && l3[2] == l0[2] ); + VERIFY( l3.get_allocator() == a ); + VERIFY( l3.get_allocator() == l2.get_allocator() ); + + return true; +} + +static_assert(move_constructor()); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc new file mode 100644 index 0000000..6fa8758 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc @@ -0,0 +1,102 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +constexpr bool +test_iterators() +{ + std::vector<bool> v; + VERIFY( v.begin() == v.end() ); + v.reserve(1); + VERIFY( v.begin() == v.end() ); + v.resize(2); + VERIFY( v.begin() != v.end() ); + VERIFY( v.cbegin() == v.begin() ); + VERIFY( v.crbegin() == v.rbegin() ); + VERIFY( v.cend() == v.end() ); + VERIFY( v.crend() == v.rend() ); + + auto it = v.begin(); + VERIFY( *it == v.front() ); + VERIFY( it++ == v.begin() ); + VERIFY( ++it == v.end() ); + VERIFY( (it - 2) == v.begin() ); + it -= 2; + it += 1; + VERIFY( (it + 1) == v.end() ); + + auto rit = v.rbegin(); + VERIFY( *rit == v.back() ); + VERIFY( rit++ == v.rbegin() ); + VERIFY( ++rit == v.rend() ); + VERIFY( (rit - 2) == v.rbegin() ); + rit -= 2; + rit += 1; + VERIFY( (rit + 1) == v.rend() ); + + return true; +} + +static_assert(test_iterators()); + +constexpr bool +test_access() +{ + std::vector<bool> v{1, 1, 0, 0, 1, 0, 1, 0, 1}; + std::vector<bool>::reference r1 = v.at(1); + VERIFY( r1 ); + std::vector<bool>::reference r2 = v[2]; + VERIFY( ! r2 ); + r1 = r2; + VERIFY( ! r1 ); + VERIFY( ! v[1] ); + r2 = true; + VERIFY( r2 ); + VERIFY( v[2] ); + + const auto& vc = v; + VERIFY( vc.at(1) == false ); + VERIFY( vc.at(1) == v.at(1) ); + VERIFY( vc.at(1) == vc[1] ); + VERIFY( vc.front() == vc[0] ); + VERIFY( vc.back() == vc[2] ); + + return true; +} + +static_assert(test_access()); + +template<typename T = bool> + constexpr std::false_type + access_empty() { return {}; } + +template<typename T = bool> + requires (std::bool_constant<(std::vector<T>().at(0), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template<typename T = bool> + requires (std::bool_constant<(std::vector<T>().back(), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +static_assert( ! access_empty() ); + +template<typename T = bool> + constexpr std::false_type + access_empty_front() { return {}; } + +template<typename T = bool> + requires (std::bool_constant<(std::vector<T>()[0], true)>::value) + constexpr std::true_type + access_empty_front() { return {}; } + +template<typename T = bool> + requires (std::bool_constant<(std::vector<T>().front(), true)>::value) + constexpr std::true_type + access_empty_front() { return {}; } + +static_assert( ! access_empty_front() ); // { dg-error "ambiguous" "PR 103191" { target { ! debug-mode } } } diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc new file mode 100644 index 0000000..02faa02 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc @@ -0,0 +1,216 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +template<typename T> +struct Alloc : std::allocator<T> +{ + using std::allocator<T>::allocator; + + constexpr explicit Alloc(int p) : personality(p) { } + + template<typename U> + constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { } + + int personality = 0; + + using propagate_on_container_move_assignment = std::false_type; + + constexpr bool operator==(const Alloc& a) const noexcept + { return personality == a.personality; } +}; + +constexpr std::size_t +capacity_for(std::size_t n) +{ + std::size_t N = std::vector<bool>(1).capacity(); + if (auto r = n % N) + return n - r + N; + return n; +} + +constexpr bool +copy_assign() +{ + // vector::operator=(const vector&) + + std::vector<bool> v1, v2; + v1 = v1; + v2 = v1; + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + for (int i = 0; i < 10; ++i) + v1.push_back(i); + v2 = v1; + VERIFY(v2.size() == 10); + v2.reserve(50); + v1.push_back(1); + v2 = v1; + VERIFY(v2.size() == 11); + VERIFY(v2.capacity() == capacity_for(50)); + + std::vector<bool, Alloc<bool>> va1(Alloc<bool>(1)), va2(Alloc<bool>(2)); + va2 = va1; + VERIFY( va2.get_allocator().personality == 2 ); + va1.push_back(999); + va2 = va1; + VERIFY( va2.get_allocator().personality == 2 ); + + return true; +} + +static_assert( copy_assign() ); + +constexpr bool +move_assign() +{ + // vector::operator=(const vector&) + + std::vector<bool> v1, v2; + v1 = std::move(v1); + v2 = std::move(v1); + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + for (int i = 0; i < 10; ++i) + v1.push_back(i); + v2 = std::move(v1); + VERIFY(v2.size() == 10); + v2.reserve(50); + v1.push_back(1); + v2 = std::move(v1); + VERIFY(v2.size() == 1); + VERIFY(v1.capacity() == 0); + VERIFY(v2.capacity() == capacity_for(1)); + + std::vector<bool, Alloc<bool>> va1(Alloc<bool>(1)), va2(Alloc<bool>(2)); + va2 = std::move(va1); + VERIFY( va2.get_allocator().personality == 2 ); + va1.push_back(9); + va1.push_back(99); + va1.push_back(999); + va1.push_back(9999); + va2 = std::move(va1); + va2 = std::move(va1); + VERIFY( va2.get_allocator().personality == 2 ); + + return true; +} + +static_assert( move_assign() ); + +constexpr bool +initializer_list_assign() +{ + std::vector<bool> v1; + v1 = {1, 0, 1}; + VERIFY( v1.size() == 3 ); + VERIFY( v1.capacity() == capacity_for(3) ); + v1 = {1, 0}; + VERIFY( v1.size() == 2 ); + VERIFY( v1.capacity() == capacity_for(3) ); + v1 = {1, 1, 0, 1, 1, 1, 0, 1, 1}; + VERIFY( v1.size() == 9 ); + VERIFY( v1.capacity() == capacity_for(9) ); + + std::vector<bool, Alloc<bool>> va1(Alloc<bool>(111)); + va1 = {1, 0, 0}; + VERIFY( va1.get_allocator().personality == 111 ); + + return true; +} + +static_assert( initializer_list_assign() ); + +constexpr bool +assign_iterator_range() +{ + std::vector<bool> v; + + int arr[] = { 1, 2, 3, 4 }; + v.assign(arr, arr+3); + VERIFY( v.size() == 3 ); + v.reserve(5); + v.assign(arr, arr+3); + VERIFY( v.capacity() == capacity_for(5) ); + + struct input_iterator + { + using iterator_category = std::input_iterator_tag; + using value_type = bool; + using pointer = const bool*; + using reference = bool; + 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 bool operator*() const { return val % 2; } + constexpr const bool* operator->() const { return nullptr; } + + constexpr bool operator==(const input_iterator&) const = default; + + int val; + }; + + v.assign(input_iterator(9), input_iterator()); + VERIFY( v.size() == 9 ); + + return true; +} + +static_assert( assign_iterator_range() ); + +constexpr bool +assign_value() +{ + std::vector<bool> v1; + v1.assign(3, 8); + VERIFY( v1.size() == 3 ); + VERIFY( v1.capacity() == capacity_for(3) ); + v1.assign(2, 9); + VERIFY( v1.size() == 2 ); + VERIFY( v1.capacity() == capacity_for(3) ); + v1.assign(9, 10); + VERIFY( v1.size() == 9 ); + VERIFY( v1.capacity() == capacity_for(9) ); + + std::vector<bool, Alloc<bool>> va1(Alloc<bool>(111)); + va1.assign(2, 9); + VERIFY( va1.size() == 2 ); + VERIFY( va1.get_allocator().personality == 111 ); + + return true; +} + +static_assert( assign_value() ); + +constexpr bool +assign_initializer_list() +{ + std::vector<bool> v1; + v1.assign({0, 1, 0}); + VERIFY( v1.size() == 3 ); + VERIFY( v1.capacity() == capacity_for(3) ); + v1.assign({1, 0}); + VERIFY( v1.size() == 2 ); + VERIFY( v1.capacity() == capacity_for(3) ); + v1.assign({1, 0, 0, 1, 1, 0, 0, 1, 1}); + VERIFY( v1.size() == 9 ); + VERIFY( v1.capacity() == capacity_for(9) ); + + std::vector<bool, Alloc<bool>> va1(Alloc<bool>(111)); + va1.assign({1, 1, 1}); + VERIFY( va1.get_allocator().personality == 111 ); + + return true; +} + +static_assert( assign_initializer_list() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc new file mode 100644 index 0000000..b27df2b --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc @@ -0,0 +1,248 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +template<typename T> +struct Alloc : std::allocator<T> +{ + using std::allocator<T>::allocator; + + constexpr explicit Alloc(int p) : personality(p) { } + + template<typename U> + constexpr Alloc(const Alloc<U>& 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<bool> v; + std::vector<bool>::reference r = v.emplace_back(""); + VERIFY( r == true ); + v.emplace_back(r); + VERIFY( v.back() == true ); + v.emplace_back(v.front()); + VERIFY( v.back() == true ); + v.resize(64); + v.emplace_back(v.back()); + VERIFY( v.back() == false ); + VERIFY( v.size() == 65 ); + v.emplace_back(8); + VERIFY( v.size() == 66 ); + VERIFY( v.back() == true ); + v.emplace_back(); + VERIFY( v.size() == 67 ); + VERIFY( v.back() == false ); + + v.pop_back(); + VERIFY( v.size() == 66 ); + VERIFY( v.back() == true ); + for (int i = 0, n = v.size(); i < n; ++i) + v.pop_back(); + VERIFY( v.empty() ); + + v.push_back(true); + for (std::size_t i = 0, c = v.capacity(); i <= c; ++i) + v.push_back(v.front()); + VERIFY( v.capacity() > v.size() ); + + std::vector<bool, Alloc<bool>> va; + va.push_back(true); + va.push_back(va.front()); + VERIFY( va.size() == 2 ); + + return true; +} + +static_assert( test_push_back() ); + +template<typename T = bool> +constexpr std::false_type +pop_back_empty() { return {}; } + +template<typename T = bool> +requires (std::bool_constant<(std::vector<T>().pop_back(), true)>::value) +constexpr std::true_type +pop_back_empty() { return {}; } + +static_assert( ! pop_back_empty() ); + +constexpr bool +test_insert_erase() +{ + std::vector<bool> 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 ); + // 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(), true); + VERIFY( v.size() == 7 ); + VERIFY( v.back() == true ); + + // 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 = bool; + using pointer = const bool*; + using reference = bool; + 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 bool operator*() const { return val % 2; } + constexpr const bool* operator->() const { return nullptr; } + + 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.insert(v.end() - 9, input_iterator(18), input_iterator()); + VERIFY( v.size() == 30 ); + short a[] = { false, true }; + v.insert(v.end(), a, a + 2); + VERIFY( v.size() == 32 ); + + // vector::insert(const_iterator, initializer_list<T>) + v.insert(v.begin(), {1,1,1}); + VERIFY( v.size() == 35 ); + + // vector::erase(const_iterator) + v.erase(v.end() - 1); + VERIFY( v.size() == 34 ); + VERIFY( v.back() == false ); + 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<bool, Alloc<bool>> 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 std::size_t +capacity_for(std::size_t n) +{ + std::size_t N = std::vector<bool>(1).capacity(); + if (auto r = n % N) + return n - r + N; + return n; +} + +constexpr bool +test_clear() +{ + std::vector<bool> v0; + v0.clear(); + VERIFY( v0.size() == 0 ); + VERIFY( v0.capacity() == 0 ); + + std::vector<bool> v{1, 0, 0}; + v.clear(); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == capacity_for(3) ); + + std::vector<bool, Alloc<bool>> va; + va.clear(); + va.push_back(1); + va.clear(); + va.clear(); + + return true; +} + +static_assert( test_clear() ); + +constexpr bool +test_flip() +{ + std::vector<bool> v{1, 0, 0, 1, 0, 1, 1, 0}; + v.flip(); + VERIFY( !v[0] && v[1] && v[2] && !v[3] && v[4] && !v[5] && !v[6] && v[7] ); + v[2].flip(); + VERIFY( !v[2] ); + v[2].flip(); + VERIFY( v[2] ); + + return true; +} + +static_assert( test_flip() ); + +constexpr bool +test_erasure() +{ + std::vector<bool> e{true,true,true,false,true,false}; + + auto n = std::erase(e, false); + VERIFY( n == 2 ); + VERIFY( e.size() == 4 ); + e[2] = false; + n = std::erase_if(e, [](std::vector<bool>::reference val) { return !val; }); + VERIFY( n == 1 ); + VERIFY( e.size() == 3 ); + + return true; +} + +static_assert( test_erasure() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/31370.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/31370.cc index a2b8c1a..c679446 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/31370.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/31370.cc @@ -24,11 +24,7 @@ #include <stdexcept> #include <testsuite_hooks.h> -#ifdef _GLIBCXX_DEBUG - using std::_GLIBCXX_STD_C::_S_word_bit; -#else - using std::_S_word_bit; -#endif +using std::_S_word_bit; inline void check_cap_ge_size(const std::vector<bool>& x) diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc new file mode 100644 index 0000000..ba444d0 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc @@ -0,0 +1,66 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <utility> +#include <testsuite_hooks.h> + +constexpr bool +test_std_swap() +{ + std::vector<bool> v1 = {true, false, true}; + std::vector<bool> v2 = {false, true}; + + std::swap(v1, v2); + + VERIFY(v1.size() == 2); + VERIFY(v1.at(0) == false); + VERIFY(v1.at(1) == true); + + VERIFY(v2.size() == 3); + VERIFY(v2[0]); + VERIFY(!v2[1]); + VERIFY(v2[2]); + + return true; +} + +static_assert(test_std_swap()); + +constexpr bool +test_member_swap() +{ + std::vector<bool> v1 = {true, false, true}; + std::vector<bool> v2 = {false, true}; + + v1.swap(v2); + + VERIFY(v1.size() == 2); + VERIFY(v1.at(0) == false); + VERIFY(v1.at(1) == true); + + VERIFY(v2.size() == 3); + VERIFY(v2[0]); + VERIFY(!v2[1]); + VERIFY(v2[2]); + + return true; +} + +static_assert(test_member_swap()); + +constexpr bool +test_reference_swap() +{ + std::vector<bool> v1 = {true, false, true}; + std::vector<bool>::swap(v1[0], v1[1]); + + VERIFY(v1[0] == false); + VERIFY(v1[1] == true); + VERIFY(v1[2] == true); + + return true; +} + +static_assert(test_reference_swap()); diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc new file mode 100644 index 0000000..de9d0b0 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc @@ -0,0 +1,101 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +constexpr bool +test_empty() +{ + std::vector<int> v; + VERIFY( v.empty() ); + v = {1}; + VERIFY( !v.empty() ); + + return true; +} + +static_assert( test_empty() ); + +constexpr bool +test_size() +{ + std::vector<int> v; + VERIFY( v.size() == 0 ); + v = {1}; + VERIFY( v.size() == 1 ); + + VERIFY( v.max_size() != 0 ); + + return true; +} + +static_assert( test_size() ); + +constexpr bool +test_capacity() +{ + std::vector<int> v; + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == v.size() ); + v = {1, 2, 3}; + VERIFY( v.size() == 3 ); + VERIFY( v.capacity() == v.size() ); + + return true; +} + +static_assert( test_capacity() ); + +constexpr bool +test_resize() +{ + std::vector<int> v; + v.reserve(9); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == 9 ); + v.resize(5); + VERIFY( v.size() == 5 ); + VERIFY( v.capacity() == 9 ); + v.resize(15, 6); + VERIFY( v.size() == 15 ); + VERIFY( v[10] == 6 ); + + return true; +} + +static_assert( test_resize() ); + +constexpr bool +test_reserve() +{ + std::vector<int> v; + v.reserve(9); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == 9 ); + v.resize(2); + VERIFY( v.size() == 2 ); + VERIFY( v.capacity() == 9 ); + + return true; +} + +static_assert( test_reserve() ); + +constexpr bool +test_shrink_to_fit() +{ + std::vector<int> v; + v.reserve(9); + v.shrink_to_fit(); + VERIFY( v.capacity() == 0 ); + v.reserve(9); + v.resize(5); + v.shrink_to_fit(); + VERIFY( v.capacity() == v.size() ); + + return true; +} + +static_assert( test_shrink_to_fit() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc index 0ffacb9..8f4a264 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cmp_c++20.cc @@ -16,12 +16,13 @@ // <http://www.gnu.org/licenses/>. // { dg-options "-std=gnu++2a" } -// { dg-do run { target c++2a } } +// { dg-do compile { target c++2a } } +// { dg-xfail-if "not supported" { debug-mode } } #include <vector> #include <testsuite_hooks.h> -void +constexpr bool test01() { std::vector<int> c1{ 1, 2, 3 }, c2{ 1, 2, 3, 4 }, c3{ 1, 2, 4 }; @@ -47,24 +48,26 @@ test01() struct E { - bool operator==(E) { return true; } + constexpr bool operator==(E) const { return true; } }; static_assert( ! std::totally_ordered<std::vector<E>> ); static_assert( ! std::three_way_comparable<E> ); static_assert( ! std::three_way_comparable<std::vector<E>> ); + + return true; } -void +constexpr bool test02() { struct W { int value = 0; - bool operator==(W rhs) const noexcept + constexpr bool operator==(W rhs) const noexcept { return (value | 1) == (rhs.value | 1); } - std::weak_ordering + constexpr std::weak_ordering operator<=>(W rhs) const noexcept { return (value | 1) <=> (rhs.value | 1); } }; @@ -75,23 +78,25 @@ test02() static_assert( std::same_as<decltype(c1 <=> c1), std::weak_ordering> ); VERIFY( c1 == c2 ); VERIFY( std::is_eq(c1 <=> c2) ); + + return true; } -void +constexpr bool test03() { struct P { int value = 0; - bool operator==(P rhs) const noexcept + constexpr bool operator==(P rhs) const noexcept { if (value < 0 || rhs.value < 0) return false; return value == rhs.value; } - std::partial_ordering + constexpr std::partial_ordering operator<=>(P rhs) const noexcept { if (value < 0 || rhs.value < 0) @@ -106,16 +111,18 @@ test03() static_assert( std::three_way_comparable<P> ); static_assert( std::same_as<decltype(c <=> c), std::partial_ordering> ); VERIFY( (c <=> c) == std::partial_ordering::unordered ); + + return true; } -void +constexpr bool test04() { struct L { int value = 0; - bool operator<(L rhs) const noexcept { return value < rhs.value; } + constexpr bool operator<(L rhs) const noexcept { return value < rhs.value; } }; static_assert( std::totally_ordered<std::vector<L>> ); @@ -123,9 +130,11 @@ test04() std::vector<L> c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} }; static_assert( std::same_as<decltype(c <=> c), std::weak_ordering> ); VERIFY( std::is_lt(c <=> d) ); + + return true; } -void +constexpr bool test05() { // vector iterators are random access, so should support <=> @@ -148,14 +157,12 @@ test05() static_assert( std::same_as<decltype(c.begin() <=> c.begin()), std::strong_ordering> ); -} -int -main() -{ - test01(); - test02(); - test03(); - test04(); - test05(); + return true; } + +static_assert( test01() ); +static_assert( test02() ); +static_assert( test03() ); +static_assert( test04() ); +static_assert( test05() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc index 302af9c..4f8396f 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164.cc @@ -31,20 +31,18 @@ void test01() { X x[1]; // Should not be able to create vector using uninitialized_copy: - std::vector<X> v1{x, x+1}; // { dg-error "here" } - - // Should not be able to create vector using uninitialized_fill_n: - std::vector<X> v2{2u, X{}}; // { dg-error "here" } + std::vector<X> v1{x, x+1}; // { dg-error "here" "" { target c++17_down } } + // { dg-error "deleted function 'X::X" "" { target c++20 } 0 } } void test02() { -#if __cplusplus >= 201703L struct Y : X { }; - // Can create initializer_list<Y> with C++17 guaranteed copy elision, - // but shouldn't be able to copy from it with uninitialized_copy: - std::vector<Y> v3{Y{}, Y{}, Y{}}; // { dg-error "here" "" { target c++17 } } -#endif + + // Should not be able to create vector using uninitialized_fill_n: + std::vector<Y> v2{2u, Y{}}; // { dg-error "here" "" { target c++17_down } } + // { dg-error "deleted function .*Y::Y" "" { target c++20 } 0 } } // { dg-error "must be constructible from input type" "" { target *-*-* } 0 } +// { dg-prune-output "construct_at" } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc new file mode 100644 index 0000000..24ade4e --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc @@ -0,0 +1,39 @@ +// Copyright (C) 2019-2021 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// <http://www.gnu.org/licenses/>. + +// { dg-do compile { target c++17 } } + +#include <vector> + +// PR libstdc++/89164 + +struct X +{ + X() = default; + X(const X&) = delete; +}; + +void test03() +{ + // Can create initializer_list<Y> with C++17 guaranteed copy elision, + // but shouldn't be able to copy from it with uninitialized_copy: + std::vector<X> v3{X{}, X{}, X{}}; // { dg-error "here" "" { target c++17_only } } + // { dg-error "deleted function .*X::X" "" { target c++20 } 0 } +} + +// { dg-error "must be constructible from input type" "" { target *-*-* } 0 } +// { dg-prune-output "construct_at" } diff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc new file mode 100644 index 0000000..f02b39a --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc @@ -0,0 +1,279 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> +#include <testsuite_iterators.h> + +template<typename T> +struct Alloc : std::allocator<T> +{ + using std::allocator<T>::allocator; + + constexpr explicit Alloc(int p) : personality(p) { } + + template<typename U> + constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { } + + int personality = 0; + + constexpr Alloc select_on_container_copy_construction() const + { return Alloc(-1); } + + constexpr bool operator==(const Alloc& a) const noexcept + { return personality == a.personality; } +}; + +namespace default_constructor_global_scope +{ + constexpr std::vector<int> v1; + static_assert(v1.size() == 0); + static_assert(v1.capacity() == 0); + + constexpr std::allocator<int> a; + constexpr std::vector<int> v2(a); + static_assert(v2.size() == 0); + static_assert(v2.capacity() == 0); + + constexpr Alloc<int> aa(10); + constexpr std::vector<int, Alloc<int>> v3(aa); + static_assert(v3.size() == 0); + static_assert(v3.capacity() == 0); + static_assert(v3.get_allocator() == aa); +} + +constexpr bool +default_constructor_function_scope() +{ + // vector() + + std::vector<int> v1; + VERIFY(v1.size() == 0); + VERIFY(v1.capacity() == 0); + + // vector(const Allocator&) + + const std::allocator<int> a; + std::vector<int> v2(a); + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + const Alloc<long> aa(10); + std::vector<long, Alloc<long>> v3(aa); + VERIFY(v3.size() == 0); + VERIFY(v3.capacity() == 0); + VERIFY(v3.get_allocator() == aa); + + return true; +} + +static_assert( default_constructor_function_scope() ); + +constexpr bool +sequence_constructors() +{ + // vector(size_type, const Allocator& = Allocator()) + + std::vector<int> v0(0); + VERIFY(v0.size() == 0); + + std::vector<int> v1(1); + VERIFY(v1.size() == 1); + + std::vector<int> v2(2); + VERIFY(v2.size() == 2); + + std::vector<int> v50(50); + VERIFY(v50.size() == 50); + + const std::allocator<int> a; + std::vector<int> a0(0, a); + VERIFY(a0.size() == 0); + + std::vector<int> a1(1, a); + VERIFY(a1.size() == 1); + + std::vector<int> a2(2, a); + VERIFY(a2.size() == 2); + + std::vector<int> a50(50, a); + VERIFY(a50.size() == 50); + + const Alloc<long> la(10); + std::vector<long, Alloc<long>> l0(0, la); + VERIFY(l0.size() == 0); + VERIFY(l0.get_allocator() == la); + + std::vector<long, Alloc<long>> l1(1, la); + VERIFY(l1.size() == 1); + VERIFY(l1.get_allocator() == la); + + std::vector<long, Alloc<long>> l2(2, la); + VERIFY(l2.size() == 2); + VERIFY(l2.get_allocator() == la); + + std::vector<long, Alloc<long>> l50(50, la); + VERIFY(l50.size() == 50); + VERIFY(l50.get_allocator() == la); + + // vector(size_type, const T&, const Allocator& = Allocator()) + + std::vector<int> v3(3, 4); + VERIFY(v3.size() == 3); + VERIFY(v3[0] == 4 && v3[2] == 4); + + std::vector<int> a3(3, 5, a); + VERIFY(a3.size() == 3); + VERIFY(a3[0] == 5 && a3[2] == 5); + + std::vector<long, Alloc<long>> l3(3, 6, la); + VERIFY(l3.size() == 3); + VERIFY(l3[0] == 6 && l3[2] == 6); + VERIFY(l3.get_allocator() == la); + + return true; +} + +static_assert(sequence_constructors()); + +constexpr bool +iterator_range_constructor() +{ + // vector(InputIterator, InputIterator, const Allocator& = Allocator()) + + short range[3] = { 1, 2, 3 }; + + std::vector<int> v0(std::begin(range), std::end(range)); + VERIFY(v0.size() == std::size(range)); + VERIFY(v0[0] == 1 && v0[1] == 2 && v0[2] == 3); + + const Alloc<long> a(5); + std::vector<long, Alloc<long>> l0(std::begin(range), std::end(range), a); + VERIFY(l0.size() == std::size(range)); + VERIFY(l0.get_allocator() == a); + VERIFY(l0[0] == 1 && l0[1] == 2 && l0[2] == 3); + + 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; + }; + + std::vector<int> v1(input_iterator(3), input_iterator()); + VERIFY(v1.size() == 3); + VERIFY(v1[0] == 3 && v1[1] == 2 && v1[2] == 1); + + std::vector<long, Alloc<long>> l1(input_iterator(2), input_iterator(), a); + VERIFY(l1.size() == 2); + VERIFY(l1.get_allocator() == a); + VERIFY(l1[0] == 2 && l1[1] == 1); + + return true; +} + +static_assert(iterator_range_constructor()); + +constexpr bool +initializer_list_constructor() +{ + // vector(initializer_list<T>, const Allocator& = Allocator()) + + std::vector<int> v0({ 1, 2, 3 }); + VERIFY(v0.size() == 3); + VERIFY(v0[0] == 1 && v0[1] == 2 && v0[2] == 3); + + const Alloc<long> a(5); + std::vector<long, Alloc<long>> l0({ 1, 2, 3 }, a); + VERIFY(l0.size() == 3); + VERIFY(l0.get_allocator() == a); + + return true; +} + +static_assert(initializer_list_constructor()); + +constexpr bool +copy_constructor() +{ + const std::vector<int> v0({ 1, 2, 3 }); + const std::vector<long, Alloc<long>> l0({ 4, 5, 6 }); + + // vector(const vector&) + + std::vector<int> v1(v0); + VERIFY( v1.size() == v0.size() ); + VERIFY( v1[0] == v0[0] && v1[1] == v0[1] && v1[2] == v0[2] ); + VERIFY( v1.get_allocator() == v0.get_allocator() ); + + const Alloc<short> as(6); + std::vector<short, Alloc<short>> s1(3, short(2), as); + std::vector<short, Alloc<short>> s2(s1); + VERIFY( s2.size() == s1.size() ); + VERIFY( s2.get_allocator().personality == -1 ); + + // vector(const vector&, const Allocator&) + + const Alloc<long> a(6); + std::vector<long, Alloc<long>> l1(l0, a); + VERIFY( l1.size() == l0.size() ); + VERIFY( l1[0] == l0[0] && l1[1] == l0[1] && l1[2] == l0[2] ); + VERIFY( l1.get_allocator() == a ); + VERIFY( l1.get_allocator() != l0.get_allocator() ); + + return true; +} + +static_assert(copy_constructor()); + +constexpr bool +move_constructor() +{ + const std::vector<int> v0({ 1, 2, 3 }); + const std::vector<long, Alloc<long>> l0({ 4, 5, 6 }); + + // vector(const vector&) + + std::vector<int> v1(v0); + std::vector<int> v2(std::move(v1)); + VERIFY( v2.size() == v0.size() ); + VERIFY( v1.empty() ); + VERIFY( v2[0] == v0[0] && v2[1] == v0[1] && v2[2] == v0[2] ); + VERIFY( v2.get_allocator() == v0.get_allocator() ); + + // vector(const vector&, const Allocator&) + + const Alloc<long> a(6); + std::vector<long, Alloc<long>> l1(l0); + std::vector<long, Alloc<long>> l2(std::move(l1), a); + VERIFY( l2.size() == l0.size() ); + VERIFY( l2[0] == l0[0] && l2[1] == l0[1] && l2[2] == l0[2] ); + VERIFY( l2.get_allocator() == a ); + VERIFY( l2.get_allocator() != l0.get_allocator() ); + + std::vector<long, Alloc<long>> l3(std::move(l2), a); + VERIFY( l3.size() == l0.size() ); + VERIFY( l3[0] == l0[0] && l3[1] == l0[1] && l3[2] == l0[2] ); + VERIFY( l3.get_allocator() == a ); + VERIFY( l3.get_allocator() == l2.get_allocator() ); + + return true; +} + +static_assert(move_constructor()); diff --git a/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc new file mode 100644 index 0000000..45b3167 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc @@ -0,0 +1,26 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +constexpr bool +test_data() +{ + std::vector<int> v; + VERIFY( v.data() == nullptr ); + v.reserve(1); + VERIFY( v.data() != nullptr ); + const std::vector<int> v2{1,3,5,9}; + VERIFY( v.data() != v2.data() ); + VERIFY( v2.data()[2] == 5 ); + + v = v2; + VERIFY( v.data() != v2.data() ); + VERIFY( v.data()[1] == 3 ); + + return true; +} + +static_assert(test_data()); diff --git a/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc new file mode 100644 index 0000000..9b3b7f63 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc @@ -0,0 +1,91 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +constexpr bool +test_iterators() +{ + std::vector<int> v; + VERIFY( v.begin() == v.end() ); + v.reserve(1); + VERIFY( v.begin() == v.end() ); + v.resize(2); + VERIFY( v.begin() != v.end() ); + VERIFY( v.cbegin() == v.begin() ); + VERIFY( v.crbegin() == v.rbegin() ); + VERIFY( v.cend() == v.end() ); + VERIFY( v.crend() == v.rend() ); + + auto it = v.begin(); + VERIFY( &*it == &v.front() ); + VERIFY( it++ == v.begin() ); + VERIFY( ++it == v.end() ); + VERIFY( (it - 2) == v.begin() ); + it -= 2; + it += 1; + VERIFY( (it + 1) == v.end() ); + + auto rit = v.rbegin(); + VERIFY( &*rit == &v.back() ); + VERIFY( rit++ == v.rbegin() ); + VERIFY( ++rit == v.rend() ); + VERIFY( (rit - 2) == v.rbegin() ); + rit -= 2; + rit += 1; + VERIFY( (rit + 1) == v.rend() ); + + return true; +} + +static_assert(test_iterators()); + +constexpr bool +test_access() +{ + std::vector<int> v{1, 2, 3}; + VERIFY( v.at(1) == 2 ); + VERIFY( v[2] == 3 ); + VERIFY( &v[2] == &v.at(2) ); + VERIFY( &v.front() == &v[0] ); + VERIFY( &v.back() == &v[2] ); + + const auto& vc = v; + VERIFY( vc.at(1) == 2 ); + VERIFY( &vc.at(1) == &v.at(1) ); + VERIFY( &vc.at(1) == &vc[1] ); + VERIFY( &vc.front() == &vc[0] ); + VERIFY( &vc.back() == &vc[2] ); + + return true; +} + +static_assert(test_access()); + +template<typename T = int> + constexpr std::false_type + access_empty() { return {}; } + +template<typename T = int> + requires (std::bool_constant<(std::vector<T>().at(0), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template<typename T = int> + requires (std::bool_constant<(std::vector<T>()[0], true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template<typename T = int> + requires (std::bool_constant<(std::vector<T>().front(), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template<typename T = int> + requires (std::bool_constant<(std::vector<T>().back(), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +static_assert( ! access_empty() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc new file mode 100644 index 0000000..638cffe --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc @@ -0,0 +1,207 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +template<typename T> +struct Alloc : std::allocator<T> +{ + using std::allocator<T>::allocator; + + constexpr explicit Alloc(int p) : personality(p) { } + + template<typename U> + constexpr Alloc(const Alloc<U>& a) : personality(a.personality) { } + + int personality = 0; + + using propagate_on_container_move_assignment = std::false_type; + + constexpr bool operator==(const Alloc& a) const noexcept + { return personality == a.personality; } +}; + +constexpr bool +copy_assign() +{ + // vector::operator=(const vector&) + + std::vector<int> v1, v2; + v1 = v1; + v2 = v1; + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + for (int i = 0; i < 10; ++i) + v1.push_back(i); + v2 = v1; + VERIFY(v2.size() == 10); + v2.reserve(50); + v1.push_back(1); + v2 = v1; + VERIFY(v2.size() == 11); + VERIFY(v2.capacity() == 50); + + std::vector<int, Alloc<int>> va1(Alloc<int>(1)), va2(Alloc<int>(2)); + va2 = va1; + VERIFY( va2.get_allocator().personality == 2 ); + va1.push_back(999); + va2 = va1; + VERIFY( va2.get_allocator().personality == 2 ); + + return true; +} + +static_assert( copy_assign() ); + +constexpr bool +move_assign() +{ + // vector::operator=(const vector&) + + std::vector<int> v1, v2; + v1 = std::move(v1); + v2 = std::move(v1); + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + for (int i = 0; i < 10; ++i) + v1.push_back(i); + v2 = std::move(v1); + VERIFY(v2.size() == 10); + v2.reserve(50); + v1.push_back(1); + v2 = std::move(v1); + VERIFY(v2.size() == 1); + VERIFY(v1.capacity() == 0); + VERIFY(v2.capacity() == 1); + + std::vector<int, Alloc<int>> va1(Alloc<int>(1)), va2(Alloc<int>(2)); + va2 = std::move(va1); + VERIFY( va2.get_allocator().personality == 2 ); + va1.push_back(9); + va1.push_back(99); + va1.push_back(999); + va1.push_back(9999); + va2 = std::move(va1); + va2 = std::move(va1); + VERIFY( va2.get_allocator().personality == 2 ); + + return true; +} + +static_assert( move_assign() ); + +constexpr bool +initializer_list_assign() +{ + std::vector<int> v1; + v1 = {1, 2, 3}; + VERIFY( v1.size() == 3 ); + VERIFY( v1.capacity() == 3 ); + v1 = {1, 2}; + VERIFY( v1.size() == 2 ); + VERIFY( v1.capacity() == 3 ); + v1 = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + VERIFY( v1.size() == 9 ); + VERIFY( v1.capacity() == 9 ); + + std::vector<int, Alloc<int>> va1(Alloc<int>(111)); + va1 = {1, 2, 3}; + VERIFY( va1.get_allocator().personality == 111 ); + + return true; +} + +static_assert( initializer_list_assign() ); + +constexpr bool +assign_iterator_range() +{ + std::vector<int> v; + + int arr[] = { 1, 2, 3, 4 }; + v.assign(arr, arr+3); + VERIFY( v.size() == 3 ); + v.reserve(5); + v.assign(arr, arr+3); + VERIFY( v.capacity() == 5 ); + + 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; + }; + + v.assign(input_iterator(9), input_iterator()); + VERIFY( v.size() == 9 ); + + return true; +} + +static_assert( assign_iterator_range() ); + +constexpr bool +assign_value() +{ + std::vector<int> v1; + v1.assign(3, 8); + VERIFY( v1.size() == 3 ); + VERIFY( v1.capacity() == 3 ); + v1.assign(2, 9); + VERIFY( v1.size() == 2 ); + VERIFY( v1.capacity() == 3 ); + v1.assign(9, 10); + VERIFY( v1.size() == 9 ); + VERIFY( v1.capacity() == 9 ); + + std::vector<int, Alloc<int>> va1(Alloc<int>(111)); + va1.assign(2, 9); + VERIFY( va1.size() == 2 ); + VERIFY( va1.get_allocator().personality == 111 ); + + return true; +} + +static_assert( assign_value() ); + +constexpr bool +assign_initializer_list() +{ + std::vector<int> v1; + v1.assign({1, 2, 3}); + VERIFY( v1.size() == 3 ); + VERIFY( v1.capacity() == 3 ); + v1.assign({1, 2}); + VERIFY( v1.size() == 2 ); + VERIFY( v1.capacity() == 3 ); + v1.assign({1, 2, 3, 4, 5, 6, 7, 8, 9}); + VERIFY( v1.size() == 9 ); + VERIFY( v1.capacity() == 9 ); + + std::vector<int, Alloc<int>> va1(Alloc<int>(111)); + va1.assign({1, 2, 3}); + VERIFY( va1.get_allocator().personality == 111 ); + + return true; +} + +static_assert( assign_initializer_list() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc new file mode 100644 index 0000000..36efecf --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc @@ -0,0 +1,226 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <testsuite_hooks.h> + +template<typename T> +struct Alloc : std::allocator<T> +{ + using std::allocator<T>::allocator; + + constexpr explicit Alloc(int p) : personality(p) { } + + template<typename U> + constexpr Alloc(const Alloc<U>& 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<int> 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<int, Alloc<int>> va; + va.push_back(99); + va.push_back(va.front()); + VERIFY( va.size() == 2 ); + + return true; +} + +static_assert( test_push_back() ); + +template<typename T = int> +constexpr std::false_type +pop_back_empty() { return {}; } + +template<typename T = int> +requires (std::bool_constant<(std::vector<T>().pop_back(), true)>::value) +constexpr std::true_type +pop_back_empty() { return {}; } + +static_assert( ! pop_back_empty() ); + +constexpr bool +test_insert_erase() +{ + std::vector<int> 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<T>) + 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<int, Alloc<int>> 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<int> v0; + v0.clear(); + VERIFY( v0.size() == 0 ); + VERIFY( v0.capacity() == 0 ); + + std::vector<int> v{1, 10, 100}; + v.clear(); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == 3 ); + + std::vector<int, Alloc<int>> 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<const char*> 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() ); diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc new file mode 100644 index 0000000..4d06558 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc @@ -0,0 +1,51 @@ +// { dg-options "-std=gnu++20" } +// { dg-do compile { target c++20 } } +// { dg-xfail-if "not supported" { debug-mode } } + +#include <vector> +#include <utility> +#include <testsuite_hooks.h> + +constexpr bool +test_std_swap() +{ + std::vector<int> v1 = {1, 2, 3}; + std::vector<int> v2 = {0, 1}; + + std::swap(v1, v2); + + VERIFY(v1.size() == 2); + VERIFY(v1.at(0) == 0); + VERIFY(v1.at(1) == 1); + + VERIFY(v2.size() == 3); + VERIFY(v2[0] == 1); + VERIFY(v2[1] == 2); + VERIFY(v2[2] == 3); + + return true; +} + +static_assert(test_std_swap()); + +constexpr bool +test_member_swap() +{ + std::vector<int> v1 = {1, 2, 3}; + std::vector<int> v2 = {0, 1}; + + v1.swap(v2); + + VERIFY(v1.size() == 2); + VERIFY(v1.at(0) == 0); + VERIFY(v1.at(1) == 1); + + VERIFY(v2.size() == 3); + VERIFY(v2[0] == 1); + VERIFY(v2[1] == 2); + VERIFY(v2[2] == 3); + + return true; +} + +static_assert(test_member_swap()); |