From patchwork Fri Nov 12 00:44:18 2021 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 47507 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 4B81B3858406 for ; Fri, 12 Nov 2021 00:46:11 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 4B81B3858406 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gcc.gnu.org; s=default; t=1636677971; bh=9MLsnNTVtdDAgu7QiGF8VHsoKSKKyO9RPGX+6HlwpAk=; h=To:Subject:Date:List-Id:List-Unsubscribe:List-Archive:List-Post: List-Help:List-Subscribe:From:Reply-To:Cc:From; b=iOVo1ehX6EPmxvhUq39GlHykGPhe+cLgynEYT0gb4bT3cimgmHcscRm+Yo5Lo/XjC L38HIKvyO2rVov3/F5gPVT/bcs2PkGBxuGRFOmxrV6WyNMbW035ASgKudq1kbr3Oxy saxcDgqm6vOTcqLvG1qd/QrHo/zHmnXkNXldnvYs= X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTPS id DB8963858C27 for ; Fri, 12 Nov 2021 00:44:25 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org DB8963858C27 Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-99-Ljj7hl-yMm2Iriocn_aQSg-1; Thu, 11 Nov 2021 19:44:21 -0500 X-MC-Unique: Ljj7hl-yMm2Iriocn_aQSg-1 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 5FFCBA40C0; Fri, 12 Nov 2021 00:44:20 +0000 (UTC) Received: from localhost (unknown [10.33.36.17]) by smtp.corp.redhat.com (Postfix) with ESMTP id 47E4660C9F; Fri, 12 Nov 2021 00:44:19 +0000 (UTC) To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [committed] libstdc++: Implement constexpr std::vector for C++20 Date: Fri, 12 Nov 2021 00:44:18 +0000 Message-Id: <20211112004418.3125362-1-jwakely@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.79 on 10.5.11.12 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com X-Spam-Status: No, score=-14.5 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_NUMSUBJECT, RCVD_IN_DNSWL_LOW, RCVD_IN_MSPIKE_H4, RCVD_IN_MSPIKE_WL, SPF_HELO_NONE, SPF_NONE, TXREP, T_FILL_THIS_FORM_SHORT, URIBL_SBL_A autolearn=unavailable autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-Patchwork-Original-From: Jonathan Wakely via Gcc-patches From: Jonathan Wakely Reply-To: Jonathan Wakely Cc: Josh Marshall Errors-To: gcc-patches-bounces+patchwork=sourceware.org@gcc.gnu.org Sender: "Gcc-patches" Tested x86_64-linux, committed to trunk. 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 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>): Add constexpr to every member function. (_Bvector_base::_M_allocate): Initialize storage during constant evaluation. (vector::_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): Move logic to ... (__do_uninit_copy): New function. (__uninitialized_fill): Move logic to ... (__do_uninit_fill): New function. (__uninitialized_fill_n): 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): 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. --- libstdc++-v3/include/bits/alloc_traits.h | 2 + libstdc++-v3/include/bits/allocator.h | 1 + libstdc++-v3/include/bits/stl_algobase.h | 1 + libstdc++-v3/include/bits/stl_bvector.h | 251 ++++++++++++---- libstdc++-v3/include/bits/stl_uninitialized.h | 158 ++++++---- libstdc++-v3/include/bits/stl_vector.h | 209 ++++++++++--- libstdc++-v3/include/bits/vector.tcc | 28 +- libstdc++-v3/include/std/vector | 2 + .../23_containers/headers/vector/synopsis.cc | 14 + .../vector/bool/capacity/29134.cc | 5 - .../vector/bool/capacity/constexpr.cc | 115 +++++++ .../23_containers/vector/bool/cmp_c++20.cc | 19 +- .../vector/bool/cons/constexpr.cc | 280 ++++++++++++++++++ .../vector/bool/element_access/constexpr.cc | 102 +++++++ .../vector/bool/modifiers/assign/constexpr.cc | 216 ++++++++++++++ .../vector/bool/modifiers/constexpr.cc | 248 ++++++++++++++++ .../vector/bool/modifiers/insert/31370.cc | 6 +- .../vector/bool/modifiers/swap/constexpr.cc | 66 +++++ .../vector/capacity/constexpr.cc | 101 +++++++ .../23_containers/vector/cmp_c++20.cc | 49 +-- .../23_containers/vector/cons/89164.cc | 16 +- .../23_containers/vector/cons/89164_c++17.cc | 39 +++ .../23_containers/vector/cons/constexpr.cc | 279 +++++++++++++++++ .../vector/data_access/constexpr.cc | 26 ++ .../vector/element_access/constexpr.cc | 91 ++++++ .../vector/modifiers/assign/constexpr.cc | 207 +++++++++++++ .../vector/modifiers/constexpr.cc | 226 ++++++++++++++ .../vector/modifiers/swap/constexpr.cc | 51 ++++ 28 files changed, 2606 insertions(+), 202 deletions(-) create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/capacity/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/cons/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/element_access/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/swap/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/capacity/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/cons/89164_c++17.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/cons/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/data_access/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/element_access/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/modifiers/constexpr.cc create mode 100644 libstdc++-v3/testsuite/23_containers/vector/modifiers/swap/constexpr.cc diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h index 602a90d4d8a..a0a95f37f66 100644 --- a/libstdc++-v3/include/bits/alloc_traits.h +++ b/libstdc++-v3/include/bits/alloc_traits.h @@ -833,6 +833,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION */ template + _GLIBCXX20_CONSTEXPR void _Destroy(_ForwardIterator __first, _ForwardIterator __last, _Allocator& __alloc) @@ -847,6 +848,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template + _GLIBCXX20_CONSTEXPR inline void _Destroy(_ForwardIterator __first, _ForwardIterator __last, allocator<_Tp>&) diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h index a6883c6758a..f83e6b87666 100644 --- a/libstdc++-v3/include/bits/allocator.h +++ b/libstdc++-v3/include/bits/allocator.h @@ -309,6 +309,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template struct __shrink_to_fit_aux<_Tp, true> { + _GLIBCXX20_CONSTEXPR static bool _S_do_it(_Tp& __c) noexcept { diff --git a/libstdc++-v3/include/bits/stl_algobase.h b/libstdc++-v3/include/bits/stl_algobase.h index 0e0586836a6..f441165714b 100644 --- a/libstdc++-v3/include/bits/stl_algobase.h +++ b/libstdc++-v3/include/bits/stl_algobase.h @@ -956,6 +956,7 @@ _GLIBCXX_END_NAMESPACE_CONTAINER const _GLIBCXX_STD_C::_Deque_iterator<_Tp, _Tp&, _Tp*>&, const _VTp&); + _GLIBCXX20_CONSTEXPR void __fill_a1(_GLIBCXX_STD_C::_Bit_iterator, _GLIBCXX_STD_C::_Bit_iterator, const bool&); diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h index 31d878427c2..381c47b6132 100644 --- a/libstdc++-v3/include/bits/stl_bvector.h +++ b/libstdc++-v3/include/bits/stl_bvector.h @@ -64,29 +64,38 @@ namespace std _GLIBCXX_VISIBILITY(default) { _GLIBCXX_BEGIN_NAMESPACE_VERSION -_GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef unsigned long _Bit_type; enum { _S_word_bit = int(__CHAR_BIT__ * sizeof(_Bit_type)) }; + __attribute__((__nonnull__)) + _GLIBCXX20_CONSTEXPR + void + __fill_bvector_n(_Bit_type*, size_t, bool) _GLIBCXX_NOEXCEPT; + +_GLIBCXX_BEGIN_NAMESPACE_CONTAINER + struct _Bit_reference { _Bit_type * _M_p; _Bit_type _M_mask; + _GLIBCXX20_CONSTEXPR _Bit_reference(_Bit_type * __x, _Bit_type __y) : _M_p(__x), _M_mask(__y) { } + _GLIBCXX20_CONSTEXPR _Bit_reference() _GLIBCXX_NOEXCEPT : _M_p(0), _M_mask(0) { } #if __cplusplus >= 201103L _Bit_reference(const _Bit_reference&) = default; #endif - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR operator bool() const _GLIBCXX_NOEXCEPT { return !!(*_M_p & _M_mask); } + _GLIBCXX20_CONSTEXPR _Bit_reference& operator=(bool __x) _GLIBCXX_NOEXCEPT { @@ -97,26 +106,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR _Bit_reference& operator=(const _Bit_reference& __x) _GLIBCXX_NOEXCEPT { return *this = bool(__x); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR bool operator==(const _Bit_reference& __x) const { return bool(*this) == bool(__x); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR bool operator<(const _Bit_reference& __x) const { return !bool(*this) && bool(__x); } + _GLIBCXX20_CONSTEXPR void flip() _GLIBCXX_NOEXCEPT { *_M_p ^= _M_mask; } }; #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR inline void swap(_Bit_reference __x, _Bit_reference __y) noexcept { @@ -125,6 +137,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __y = __tmp; } + _GLIBCXX20_CONSTEXPR inline void swap(_Bit_reference __x, bool& __y) noexcept { @@ -133,6 +146,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __y = __tmp; } + _GLIBCXX20_CONSTEXPR inline void swap(bool& __x, _Bit_reference __y) noexcept { @@ -148,9 +162,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Bit_type * _M_p; unsigned int _M_offset; + _GLIBCXX20_CONSTEXPR _Bit_iterator_base(_Bit_type * __x, unsigned int __y) : _M_p(__x), _M_offset(__y) { } + _GLIBCXX20_CONSTEXPR void _M_bump_up() { @@ -161,6 +177,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } } + _GLIBCXX20_CONSTEXPR void _M_bump_down() { @@ -171,6 +188,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } } + _GLIBCXX20_CONSTEXPR void _M_incr(ptrdiff_t __i) { @@ -230,7 +248,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { return !(__x < __y); } #endif // three-way comparison - friend ptrdiff_t + friend _GLIBCXX20_CONSTEXPR ptrdiff_t operator-(const _Bit_iterator_base& __x, const _Bit_iterator_base& __y) { return (int(_S_word_bit) * (__x._M_p - __y._M_p) @@ -248,20 +266,24 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif typedef _Bit_iterator iterator; + _GLIBCXX20_CONSTEXPR _Bit_iterator() : _Bit_iterator_base(0, 0) { } + _GLIBCXX20_CONSTEXPR _Bit_iterator(_Bit_type * __x, unsigned int __y) : _Bit_iterator_base(__x, __y) { } + _GLIBCXX20_CONSTEXPR iterator _M_const_cast() const { return *this; } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference operator*() const { return reference(_M_p, 1UL << _M_offset); } + _GLIBCXX20_CONSTEXPR iterator& operator++() { @@ -269,6 +291,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR iterator operator++(int) { @@ -277,6 +300,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return __tmp; } + _GLIBCXX20_CONSTEXPR iterator& operator--() { @@ -284,6 +308,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR iterator operator--(int) { @@ -292,6 +317,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return __tmp; } + _GLIBCXX20_CONSTEXPR iterator& operator+=(difference_type __i) { @@ -299,6 +325,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR iterator& operator-=(difference_type __i) { @@ -306,13 +333,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference operator[](difference_type __i) const { return *(*this + __i); } _GLIBCXX_NODISCARD - friend iterator + friend _GLIBCXX20_CONSTEXPR iterator operator+(const iterator& __x, difference_type __n) { iterator __tmp = __x; @@ -321,12 +348,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } _GLIBCXX_NODISCARD - friend iterator + friend _GLIBCXX20_CONSTEXPR iterator operator+(difference_type __n, const iterator& __x) { return __x + __n; } _GLIBCXX_NODISCARD - friend iterator + friend _GLIBCXX20_CONSTEXPR iterator operator-(const iterator& __x, difference_type __n) { iterator __tmp = __x; @@ -346,23 +373,28 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif typedef _Bit_const_iterator const_iterator; + _GLIBCXX20_CONSTEXPR _Bit_const_iterator() : _Bit_iterator_base(0, 0) { } + _GLIBCXX20_CONSTEXPR _Bit_const_iterator(_Bit_type * __x, unsigned int __y) : _Bit_iterator_base(__x, __y) { } + _GLIBCXX20_CONSTEXPR _Bit_const_iterator(const _Bit_iterator& __x) : _Bit_iterator_base(__x._M_p, __x._M_offset) { } + _GLIBCXX20_CONSTEXPR _Bit_iterator _M_const_cast() const { return _Bit_iterator(_M_p, _M_offset); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference operator*() const { return _Bit_reference(_M_p, 1UL << _M_offset); } + _GLIBCXX20_CONSTEXPR const_iterator& operator++() { @@ -370,6 +402,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR const_iterator operator++(int) { @@ -378,6 +411,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return __tmp; } + _GLIBCXX20_CONSTEXPR const_iterator& operator--() { @@ -385,6 +419,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR const_iterator operator--(int) { @@ -393,6 +428,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return __tmp; } + _GLIBCXX20_CONSTEXPR const_iterator& operator+=(difference_type __i) { @@ -400,6 +436,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR const_iterator& operator-=(difference_type __i) { @@ -407,13 +444,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference operator[](difference_type __i) const { return *(*this + __i); } _GLIBCXX_NODISCARD - friend const_iterator + friend _GLIBCXX20_CONSTEXPR const_iterator operator+(const const_iterator& __x, difference_type __n) { const_iterator __tmp = __x; @@ -422,7 +459,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } _GLIBCXX_NODISCARD - friend const_iterator + friend _GLIBCXX20_CONSTEXPR const_iterator operator-(const const_iterator& __x, difference_type __n) { const_iterator __tmp = __x; @@ -431,7 +468,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } _GLIBCXX_NODISCARD - friend const_iterator + friend _GLIBCXX20_CONSTEXPR const_iterator operator+(difference_type __n, const const_iterator& __x) { return __x + __n; } }; @@ -454,25 +491,30 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER struct { _Bit_type* _M_p; // Allow assignment from iterators (assume offset is zero): + _GLIBCXX20_CONSTEXPR void operator=(_Bit_iterator __it) { _M_p = __it._M_p; } } _M_start; #endif _Bit_iterator _M_finish; _Bit_pointer _M_end_of_storage; + _GLIBCXX20_CONSTEXPR _Bvector_impl_data() _GLIBCXX_NOEXCEPT : _M_start(), _M_finish(), _M_end_of_storage() { } #if __cplusplus >= 201103L _Bvector_impl_data(const _Bvector_impl_data&) = default; + _Bvector_impl_data& operator=(const _Bvector_impl_data&) = default; + _GLIBCXX20_CONSTEXPR _Bvector_impl_data(_Bvector_impl_data&& __x) noexcept : _Bvector_impl_data(__x) { __x._M_reset(); } + _GLIBCXX20_CONSTEXPR void _M_move_data(_Bvector_impl_data&& __x) noexcept { @@ -481,10 +523,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #endif + _GLIBCXX20_CONSTEXPR void _M_reset() _GLIBCXX_NOEXCEPT { *this = _Bvector_impl_data(); } + _GLIBCXX20_CONSTEXPR void _M_swap_data(_Bvector_impl_data& __x) _GLIBCXX_NOEXCEPT { @@ -497,11 +541,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER struct _Bvector_impl : public _Bit_alloc_type, public _Bvector_impl_data { + _GLIBCXX20_CONSTEXPR _Bvector_impl() _GLIBCXX_NOEXCEPT_IF( is_nothrow_default_constructible<_Bit_alloc_type>::value) : _Bit_alloc_type() { } + _GLIBCXX20_CONSTEXPR _Bvector_impl(const _Bit_alloc_type& __a) _GLIBCXX_NOEXCEPT : _Bit_alloc_type(__a) { } @@ -509,15 +555,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L // Not defaulted, to enforce noexcept(true) even when // !is_nothrow_move_constructible<_Bit_alloc_type>. + _GLIBCXX20_CONSTEXPR _Bvector_impl(_Bvector_impl&& __x) noexcept : _Bit_alloc_type(std::move(__x)), _Bvector_impl_data(std::move(__x)) { } + _GLIBCXX20_CONSTEXPR _Bvector_impl(_Bit_alloc_type&& __a, _Bvector_impl&& __x) noexcept : _Bit_alloc_type(std::move(__a)), _Bvector_impl_data(std::move(__x)) { } #endif + _GLIBCXX20_CONSTEXPR _Bit_type* _M_end_addr() const _GLIBCXX_NOEXCEPT { @@ -530,14 +579,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER public: typedef _Alloc allocator_type; + _GLIBCXX20_CONSTEXPR _Bit_alloc_type& _M_get_Bit_allocator() _GLIBCXX_NOEXCEPT { return this->_M_impl; } + _GLIBCXX20_CONSTEXPR const _Bit_alloc_type& _M_get_Bit_allocator() const _GLIBCXX_NOEXCEPT { return this->_M_impl; } + _GLIBCXX20_CONSTEXPR allocator_type get_allocator() const _GLIBCXX_NOEXCEPT { return allocator_type(_M_get_Bit_allocator()); } @@ -548,27 +600,43 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Bvector_base() { } #endif + _GLIBCXX20_CONSTEXPR _Bvector_base(const allocator_type& __a) : _M_impl(__a) { } #if __cplusplus >= 201103L _Bvector_base(_Bvector_base&&) = default; + _GLIBCXX20_CONSTEXPR _Bvector_base(_Bvector_base&& __x, const allocator_type& __a) noexcept : _M_impl(_Bit_alloc_type(__a), std::move(__x._M_impl)) { } #endif + _GLIBCXX20_CONSTEXPR ~_Bvector_base() { this->_M_deallocate(); } protected: _Bvector_impl _M_impl; + _GLIBCXX20_CONSTEXPR _Bit_pointer _M_allocate(size_t __n) - { return _Bit_alloc_traits::allocate(_M_impl, _S_nword(__n)); } + { + _Bit_pointer __p = _Bit_alloc_traits::allocate(_M_impl, _S_nword(__n)); +#if __has_builtin(__builtin_is_constant_evaluated) + if (__builtin_is_constant_evaluated()) + { + __n = _S_nword(__n); + for (size_t __i = 0; __i < __n; ++__i) + __p[__i] = 0ul; + } +#endif + return __p; + } + _GLIBCXX20_CONSTEXPR void _M_deallocate() { @@ -583,11 +651,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR void _M_move_data(_Bvector_base&& __x) noexcept { _M_impl._M_move_data(std::move(__x._M_impl)); } #endif + _GLIBCXX_CONSTEXPR static size_t _S_nword(size_t __n) { return (__n + int(_S_word_bit) - 1) / int(_S_word_bit); } @@ -637,6 +707,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef std::reverse_iterator reverse_iterator; typedef _Alloc allocator_type; + _GLIBCXX20_CONSTEXPR allocator_type get_allocator() const { return _Base::get_allocator(); } @@ -654,16 +725,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector() { } #endif + _GLIBCXX20_CONSTEXPR explicit vector(const allocator_type& __a) : _Base(__a) { } #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR explicit vector(size_type __n, const allocator_type& __a = allocator_type()) : vector(__n, false, __a) { } + _GLIBCXX20_CONSTEXPR vector(size_type __n, const bool& __value, const allocator_type& __a = allocator_type()) #else @@ -677,6 +751,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_initialize_value(__value); } + _GLIBCXX20_CONSTEXPR vector(const vector& __x) : _Base(_Bit_alloc_traits::_S_select_on_copy(__x._M_get_Bit_allocator())) { @@ -688,10 +763,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector(vector&&) = default; private: + _GLIBCXX20_CONSTEXPR vector(vector&& __x, const allocator_type& __a, true_type) noexcept : _Base(std::move(__x), __a) { } + _GLIBCXX20_CONSTEXPR vector(vector&& __x, const allocator_type& __a, false_type) : _Base(__a) { @@ -706,12 +783,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } public: + _GLIBCXX20_CONSTEXPR vector(vector&& __x, const __type_identity_t& __a) noexcept(_Bit_alloc_traits::_S_always_equal()) : vector(std::move(__x), __a, typename _Bit_alloc_traits::is_always_equal{}) { } + _GLIBCXX20_CONSTEXPR vector(const vector& __x, const __type_identity_t& __a) : _Base(__a) { @@ -719,6 +798,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_copy_aligned(__x.begin(), __x.end(), begin()); } + _GLIBCXX20_CONSTEXPR vector(initializer_list __l, const allocator_type& __a = allocator_type()) : _Base(__a) @@ -731,6 +811,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template> + _GLIBCXX20_CONSTEXPR vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) @@ -750,8 +831,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #endif + _GLIBCXX20_CONSTEXPR ~vector() _GLIBCXX_NOEXCEPT { } + _GLIBCXX20_CONSTEXPR vector& operator=(const vector& __x) { @@ -783,6 +866,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR vector& operator=(vector&& __x) noexcept(_Bit_alloc_traits::_S_nothrow_move()) { @@ -808,6 +892,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return *this; } + _GLIBCXX20_CONSTEXPR vector& operator=(initializer_list __l) { @@ -820,6 +905,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // versions: one that takes a count, and one that takes a range. // The range version is a member template, so we dispatch on whether // or not the type is an integer. + _GLIBCXX20_CONSTEXPR void assign(size_type __n, const bool& __x) { _M_fill_assign(__n, __x); } @@ -827,6 +913,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template> + _GLIBCXX20_CONSTEXPR void assign(_InputIterator __first, _InputIterator __last) { _M_assign_aux(__first, __last, std::__iterator_category(__first)); } @@ -842,79 +929,80 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR void assign(initializer_list __l) { _M_assign_aux(__l.begin(), __l.end(), random_access_iterator_tag()); } #endif - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR iterator begin() _GLIBCXX_NOEXCEPT { return iterator(this->_M_impl._M_start._M_p, 0); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_iterator begin() const _GLIBCXX_NOEXCEPT { return const_iterator(this->_M_impl._M_start._M_p, 0); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR iterator end() _GLIBCXX_NOEXCEPT { return this->_M_impl._M_finish; } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_iterator end() const _GLIBCXX_NOEXCEPT { return this->_M_impl._M_finish; } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reverse_iterator rbegin() _GLIBCXX_NOEXCEPT { return reverse_iterator(end()); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reverse_iterator rbegin() const _GLIBCXX_NOEXCEPT { return const_reverse_iterator(end()); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reverse_iterator rend() _GLIBCXX_NOEXCEPT { return reverse_iterator(begin()); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reverse_iterator rend() const _GLIBCXX_NOEXCEPT { return const_reverse_iterator(begin()); } #if __cplusplus >= 201103L - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(this->_M_impl._M_start._M_p, 0); } - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_iterator cend() const noexcept { return this->_M_impl._M_finish; } - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } #endif - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type size() const _GLIBCXX_NOEXCEPT { return size_type(end() - begin()); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type max_size() const _GLIBCXX_NOEXCEPT { @@ -927,27 +1015,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER ? __asize * int(_S_word_bit) : __isize); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type capacity() const _GLIBCXX_NOEXCEPT { return size_type(const_iterator(this->_M_impl._M_end_addr(), 0) - begin()); } - _GLIBCXX_NODISCARD bool + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + bool empty() const _GLIBCXX_NOEXCEPT { return begin() == end(); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference operator[](size_type __n) { return begin()[__n]; } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference operator[](size_type __n) const { return begin()[__n]; } protected: + _GLIBCXX20_CONSTEXPR void _M_range_check(size_type __n) const { @@ -959,14 +1049,23 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } public: + _GLIBCXX20_CONSTEXPR reference at(size_type __n) - { _M_range_check(__n); return (*this)[__n]; } + { + _M_range_check(__n); + return (*this)[__n]; + } + _GLIBCXX20_CONSTEXPR const_reference at(size_type __n) const - { _M_range_check(__n); return (*this)[__n]; } + { + _M_range_check(__n); + return (*this)[__n]; + } + _GLIBCXX20_CONSTEXPR void reserve(size_type __n) { @@ -976,26 +1075,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_reallocate(__n); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference front() { return *begin(); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference front() const { return *begin(); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference back() { return *(end() - 1); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference back() const { return *(end() - 1); } + _GLIBCXX20_CONSTEXPR void push_back(bool __x) { @@ -1005,6 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_insert_aux(end(), __x); } + _GLIBCXX20_CONSTEXPR void swap(vector& __x) _GLIBCXX_NOEXCEPT { @@ -1018,6 +1119,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } // [23.2.5]/1, third-to-last entry in synopsis listing + _GLIBCXX20_CONSTEXPR static void swap(reference __x, reference __y) _GLIBCXX_NOEXCEPT { @@ -1026,6 +1128,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER __y = __tmp; } + _GLIBCXX20_CONSTEXPR iterator #if __cplusplus >= 201103L insert(const_iterator __position, const bool& __x = bool()) @@ -1045,6 +1148,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template> + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last) @@ -1068,6 +1172,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, size_type __n, const bool& __x) { @@ -1082,15 +1187,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __p, initializer_list __l) { return this->insert(__p, __l.begin(), __l.end()); } #endif + _GLIBCXX20_CONSTEXPR void pop_back() { --this->_M_impl._M_finish; } + _GLIBCXX20_CONSTEXPR iterator #if __cplusplus >= 201103L erase(const_iterator __position) @@ -1099,6 +1207,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif { return _M_erase(__position._M_const_cast()); } + _GLIBCXX20_CONSTEXPR iterator #if __cplusplus >= 201103L erase(const_iterator __first, const_iterator __last) @@ -1107,6 +1216,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif { return _M_erase(__first._M_const_cast(), __last._M_const_cast()); } + _GLIBCXX20_CONSTEXPR void resize(size_type __new_size, bool __x = bool()) { @@ -1117,11 +1227,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR void shrink_to_fit() { _M_shrink_to_fit(); } #endif + _GLIBCXX20_CONSTEXPR void flip() _GLIBCXX_NOEXCEPT { @@ -1130,6 +1242,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER *__p = ~*__p; } + _GLIBCXX20_CONSTEXPR void clear() _GLIBCXX_NOEXCEPT { _M_erase_at_end(begin()); } @@ -1137,6 +1250,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template #if __cplusplus > 201402L + _GLIBCXX20_CONSTEXPR reference #else void @@ -1150,6 +1264,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR iterator emplace(const_iterator __pos, _Args&&... __args) { return insert(__pos, bool(__args...)); } @@ -1157,6 +1272,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER protected: // Precondition: __first._M_offset == 0 && __result._M_offset == 0. + _GLIBCXX20_CONSTEXPR iterator _M_copy_aligned(const_iterator __first, const_iterator __last, iterator __result) @@ -1166,6 +1282,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER iterator(__q, 0)); } + _GLIBCXX20_CONSTEXPR void _M_initialize(size_type __n) { @@ -1179,19 +1296,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } } + _GLIBCXX20_CONSTEXPR void - _M_initialize_value(bool __x) + _M_initialize_value(bool __x) _GLIBCXX_NOEXCEPT { if (_Bit_type* __p = this->_M_impl._M_start._M_p) - __builtin_memset(__p, __x ? ~0 : 0, - (this->_M_impl._M_end_addr() - __p) - * sizeof(_Bit_type)); + __fill_bvector_n(__p, this->_M_impl._M_end_addr() - __p, __x); } + _GLIBCXX20_CONSTEXPR void _M_reallocate(size_type __n); #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR bool _M_shrink_to_fit(); #endif @@ -1216,6 +1334,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif template + _GLIBCXX20_CONSTEXPR void _M_initialize_range(_InputIterator __first, _InputIterator __last, std::input_iterator_tag) @@ -1225,6 +1344,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void _M_initialize_range(_ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag) @@ -1249,6 +1369,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER { _M_assign_aux(__first, __last, std::__iterator_category(__first)); } #endif + _GLIBCXX20_CONSTEXPR void _M_fill_assign(size_t __n, bool __x) { @@ -1265,6 +1386,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void _M_assign_aux(_InputIterator __first, _InputIterator __last, std::input_iterator_tag) @@ -1279,6 +1401,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag) @@ -1313,10 +1436,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER std::__iterator_category(__first)); } #endif + _GLIBCXX20_CONSTEXPR void _M_fill_insert(iterator __position, size_type __n, bool __x); template + _GLIBCXX20_CONSTEXPR void _M_insert_range(iterator __pos, _InputIterator __first, _InputIterator __last, std::input_iterator_tag) @@ -1329,13 +1454,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void _M_insert_range(iterator __position, _ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag); + _GLIBCXX20_CONSTEXPR void _M_insert_aux(iterator __position, bool __x); + _GLIBCXX20_CONSTEXPR size_type _M_check_len(size_type __n, const char* __s) const { @@ -1346,13 +1474,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return (__len < size() || __len > max_size()) ? max_size() : __len; } + _GLIBCXX20_CONSTEXPR void _M_erase_at_end(iterator __pos) { this->_M_impl._M_finish = __pos; } + _GLIBCXX20_CONSTEXPR iterator _M_erase(iterator __pos); + _GLIBCXX20_CONSTEXPR iterator _M_erase(iterator __first, iterator __last); @@ -1371,12 +1502,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _GLIBCXX_END_NAMESPACE_CONTAINER + // Fill a partial word. + _GLIBCXX20_CONSTEXPR inline void - __fill_bvector(_GLIBCXX_STD_C::_Bit_type * __v, - unsigned int __first, unsigned int __last, bool __x) + __fill_bvector(_Bit_type* __v, unsigned int __first, unsigned int __last, + bool __x) _GLIBCXX_NOEXCEPT { - using _GLIBCXX_STD_C::_Bit_type; - using _GLIBCXX_STD_C::_S_word_bit; const _Bit_type __fmask = ~0ul << __first; const _Bit_type __lmask = ~0ul >> (_S_word_bit - __last); const _Bit_type __mask = __fmask & __lmask; @@ -1387,20 +1518,36 @@ _GLIBCXX_END_NAMESPACE_CONTAINER *__v &= ~__mask; } + // Fill N full words, as if using memset, but usable in constant expressions. + __attribute__((__nonnull__)) + _GLIBCXX20_CONSTEXPR + inline void + __fill_bvector_n(_Bit_type* __p, size_t __n, bool __x) _GLIBCXX_NOEXCEPT + { +#if __has_builtin(__builtin_is_constant_evaluated) + if (__builtin_is_constant_evaluated()) + { + for (size_t __i = 0; __i < __n; ++__i) + __p[__i] = __x ? ~0ul : 0ul; + return; + } +#endif + __builtin_memset(__p, __x ? ~0 : 0, __n * sizeof(_Bit_type)); + } + + + _GLIBCXX20_CONSTEXPR inline void __fill_a1(_GLIBCXX_STD_C::_Bit_iterator __first, _GLIBCXX_STD_C::_Bit_iterator __last, const bool& __x) { - using _GLIBCXX_STD_C::_Bit_type; - using _GLIBCXX_STD_C::_S_word_bit; if (__first._M_p != __last._M_p) { _Bit_type* __first_p = __first._M_p; if (__first._M_offset != 0) __fill_bvector(__first_p++, __first._M_offset, _S_word_bit, __x); - __builtin_memset(__first_p, __x ? ~0 : 0, - (__last._M_p - __first_p) * sizeof(_Bit_type)); + __fill_bvector_n(__first_p, __last._M_p - __first_p, __x); if (__last._M_offset != 0) __fill_bvector(__last._M_p, 0, __last._M_offset, __x); diff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h index 2fee1e17f00..673f6a07675 100644 --- a/libstdc++-v3/include/bits/stl_uninitialized.h +++ b/libstdc++-v3/include/bits/stl_uninitialized.h @@ -107,6 +107,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __is_trivial(T) && __is_assignable(T&, U) #endif + template + _GLIBCXX20_CONSTEXPR + _ForwardIterator + __do_uninit_copy(_InputIterator __first, _InputIterator __last, + _ForwardIterator __result) + { + _ForwardIterator __cur = __result; + __try + { + for (; __first != __last; ++__first, (void)++__cur) + std::_Construct(std::__addressof(*__cur), *__first); + return __cur; + } + __catch(...) + { + std::_Destroy(__result, __cur); + __throw_exception_again; + } + } + template struct __uninitialized_copy { @@ -114,20 +134,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static _ForwardIterator __uninit_copy(_InputIterator __first, _InputIterator __last, _ForwardIterator __result) - { - _ForwardIterator __cur = __result; - __try - { - for (; __first != __last; ++__first, (void)++__cur) - std::_Construct(std::__addressof(*__cur), *__first); - return __cur; - } - __catch(...) - { - std::_Destroy(__result, __cur); - __throw_exception_again; - } - } + { return std::__do_uninit_copy(__first, __last, __result); } }; template<> @@ -180,6 +187,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented + template + _GLIBCXX20_CONSTEXPR void + __do_uninit_fill(_ForwardIterator __first, _ForwardIterator __last, + const _Tp& __x) + { + _ForwardIterator __cur = __first; + __try + { + for (; __cur != __last; ++__cur) + std::_Construct(std::__addressof(*__cur), __x); + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + template struct __uninitialized_fill { @@ -187,19 +212,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION static void __uninit_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x) - { - _ForwardIterator __cur = __first; - __try - { - for (; __cur != __last; ++__cur) - std::_Construct(std::__addressof(*__cur), __x); - } - __catch(...) - { - std::_Destroy(__first, __cur); - __throw_exception_again; - } - } + { std::__do_uninit_fill(__first, __last, __x); } }; template<> @@ -242,34 +255,40 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION /// @cond undocumented + template + _GLIBCXX20_CONSTEXPR + _ForwardIterator + __do_uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) + { + _ForwardIterator __cur = __first; + __try + { + for (; __n > 0; --__n, (void) ++__cur) + std::_Construct(std::__addressof(*__cur), __x); + return __cur; + } + __catch(...) + { + std::_Destroy(__first, __cur); + __throw_exception_again; + } + } + template struct __uninitialized_fill_n { template - static _ForwardIterator + static _ForwardIterator __uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) - { - _ForwardIterator __cur = __first; - __try - { - for (; __n > 0; --__n, (void) ++__cur) - std::_Construct(std::__addressof(*__cur), __x); - return __cur; - } - __catch(...) - { - std::_Destroy(__first, __cur); - __throw_exception_again; - } - } + { return std::__do_uninit_fill_n(__first, __n, __x); } }; template<> struct __uninitialized_fill_n { template - static _ForwardIterator + static _ForwardIterator __uninit_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x) { return std::fill_n(__first, __n, __x); } @@ -315,11 +334,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Extensions: versions of uninitialized_copy, uninitialized_fill, // and uninitialized_fill_n that take an allocator parameter. // We dispatch back to the standard versions when we're given the - // default allocator. For nondefault allocators we do not use + // default allocator. For nondefault allocators we do not use // any of the POD optimizations. template + _GLIBCXX20_CONSTEXPR _ForwardIterator __uninitialized_copy_a(_InputIterator __first, _InputIterator __last, _ForwardIterator __result, _Allocator& __alloc) @@ -340,13 +360,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator __uninitialized_copy_a(_InputIterator __first, _InputIterator __last, _ForwardIterator __result, allocator<_Tp>&) - { return std::uninitialized_copy(__first, __last, __result); } + { +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated()) + return std::__do_uninit_copy(__first, __last, __result); +#endif + return std::uninitialized_copy(__first, __last, __result); + } template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator __uninitialized_move_a(_InputIterator __first, _InputIterator __last, _ForwardIterator __result, _Allocator& __alloc) @@ -358,6 +386,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator __uninitialized_move_if_noexcept_a(_InputIterator __first, _InputIterator __last, @@ -370,6 +399,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template + _GLIBCXX20_CONSTEXPR void __uninitialized_fill_a(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x, _Allocator& __alloc) @@ -389,15 +419,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template + _GLIBCXX20_CONSTEXPR inline void __uninitialized_fill_a(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x, allocator<_Tp2>&) - { std::uninitialized_fill(__first, __last, __x); } + { +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated()) + return std::__do_uninit_fill(__first, __last, __x); +#endif + std::uninitialized_fill(__first, __last, __x); + } template + _GLIBCXX20_CONSTEXPR _ForwardIterator - __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, + __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, const _Tp& __x, _Allocator& __alloc) { _ForwardIterator __cur = __first; @@ -417,10 +455,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator - __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, + __uninitialized_fill_n_a(_ForwardIterator __first, _Size __n, const _Tp& __x, allocator<_Tp2>&) - { return std::uninitialized_fill_n(__first, __n, __x); } + { +#ifdef __cpp_lib_is_constant_evaluated + if (std::is_constant_evaluated()) + return std::__do_uninit_fill_n(__first, __n, __x); +#endif + return std::uninitialized_fill_n(__first, __n, __x); + } // Extensions: __uninitialized_copy_move, __uninitialized_move_copy, @@ -483,7 +528,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __throw_exception_again; } } - + // __uninitialized_fill_move // Fills [result, mid) with x, and moves [first, last) into // [mid, mid + (last - first)). @@ -582,6 +627,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_n_1 { template + _GLIBCXX20_CONSTEXPR static _ForwardIterator __uninit_default_n(_ForwardIterator __first, _Size __n) { @@ -604,6 +650,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION struct __uninitialized_default_n_1 { template + _GLIBCXX20_CONSTEXPR static _ForwardIterator __uninit_default_n(_ForwardIterator __first, _Size __n) { @@ -639,6 +686,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __uninitialized_default_n // Fills [first, first + n) with value-initialized value_types. template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator __uninitialized_default_n(_ForwardIterator __first, _Size __n) { @@ -689,8 +737,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Fills [first, first + n) with value_types constructed by the allocator // alloc, with no arguments passed to the construct call. template - _ForwardIterator - __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, + _GLIBCXX20_CONSTEXPR _ForwardIterator + __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, _Allocator& __alloc) { _ForwardIterator __cur = __first; @@ -711,8 +759,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // __uninitialized_default_n_a specialization for std::allocator, // which ignores the allocator and value-initializes the elements. template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator - __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, + __uninitialized_default_n_a(_ForwardIterator __first, _Size __n, allocator<_Tp>&) { return std::__uninitialized_default_n(__first, __n); } @@ -1022,6 +1071,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION : is_trivial<_Tp> { }; template + _GLIBCXX20_CONSTEXPR inline __enable_if_t::value, _Tp*> __relocate_a_1(_Tp* __first, _Tp* __last, _Tp* __result, allocator<_Up>&) noexcept @@ -1034,6 +1084,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator __relocate_a_1(_InputIterator __first, _InputIterator __last, _ForwardIterator __result, _Allocator& __alloc) @@ -1056,6 +1107,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template + _GLIBCXX20_CONSTEXPR inline _ForwardIterator __relocate_a(_InputIterator __first, _InputIterator __last, _ForwardIterator __result, _Allocator& __alloc) diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h index 2023581bc79..bd15b6bd8a8 100644 --- a/libstdc++-v3/include/bits/stl_vector.h +++ b/libstdc++-v3/include/bits/stl_vector.h @@ -94,17 +94,20 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER pointer _M_finish; pointer _M_end_of_storage; + _GLIBCXX20_CONSTEXPR _Vector_impl_data() _GLIBCXX_NOEXCEPT : _M_start(), _M_finish(), _M_end_of_storage() { } #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR _Vector_impl_data(_Vector_impl_data&& __x) noexcept : _M_start(__x._M_start), _M_finish(__x._M_finish), _M_end_of_storage(__x._M_end_of_storage) { __x._M_start = __x._M_finish = __x._M_end_of_storage = pointer(); } #endif + _GLIBCXX20_CONSTEXPR void _M_copy_data(_Vector_impl_data const& __x) _GLIBCXX_NOEXCEPT { @@ -113,6 +116,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _M_end_of_storage = __x._M_end_of_storage; } + _GLIBCXX20_CONSTEXPR void _M_swap_data(_Vector_impl_data& __x) _GLIBCXX_NOEXCEPT { @@ -128,11 +132,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER struct _Vector_impl : public _Tp_alloc_type, public _Vector_impl_data { + _GLIBCXX20_CONSTEXPR _Vector_impl() _GLIBCXX_NOEXCEPT_IF( is_nothrow_default_constructible<_Tp_alloc_type>::value) : _Tp_alloc_type() { } + _GLIBCXX20_CONSTEXPR _Vector_impl(_Tp_alloc_type const& __a) _GLIBCXX_NOEXCEPT : _Tp_alloc_type(__a) { } @@ -140,14 +146,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L // Not defaulted, to enforce noexcept(true) even when // !is_nothrow_move_constructible<_Tp_alloc_type>. + _GLIBCXX20_CONSTEXPR _Vector_impl(_Vector_impl&& __x) noexcept : _Tp_alloc_type(std::move(__x)), _Vector_impl_data(std::move(__x)) { } + _GLIBCXX20_CONSTEXPR _Vector_impl(_Tp_alloc_type&& __a) noexcept : _Tp_alloc_type(std::move(__a)) { } + _GLIBCXX20_CONSTEXPR _Vector_impl(_Tp_alloc_type&& __a, _Vector_impl&& __rv) noexcept : _Tp_alloc_type(std::move(__a)), _Vector_impl_data(std::move(__rv)) { } @@ -160,15 +169,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER typedef typename __gnu_cxx::__alloc_traits<_Tp_alloc_type> ::size_type size_type; - static void _S_shrink(_Vector_impl&, size_type) { } - static void _S_on_dealloc(_Vector_impl&) { } + static _GLIBCXX20_CONSTEXPR void + _S_shrink(_Vector_impl&, size_type) { } + static _GLIBCXX20_CONSTEXPR void + _S_on_dealloc(_Vector_impl&) { } typedef _Vector_impl& _Reinit; struct _Grow { - _Grow(_Vector_impl&, size_type) { } - void _M_grew(size_type) { } + _GLIBCXX20_CONSTEXPR _Grow(_Vector_impl&, size_type) { } + _GLIBCXX20_CONSTEXPR void _M_grew(size_type) { } }; }; @@ -181,22 +192,25 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Adjust ASan annotation for [_M_start, _M_end_of_storage) to // mark end of valid region as __curr instead of __prev. - static void + static _GLIBCXX20_CONSTEXPR void _S_adjust(_Vector_impl& __impl, pointer __prev, pointer __curr) { +#if __has_builtin(__builtin_is_constant_evaluated) + if (!__builtin_is_constant_evaluated()) +#endif __sanitizer_annotate_contiguous_container(__impl._M_start, __impl._M_end_of_storage, __prev, __curr); } - static void + static _GLIBCXX20_CONSTEXPR void _S_grow(_Vector_impl& __impl, size_type __n) { _S_adjust(__impl, __impl._M_finish, __impl._M_finish + __n); } - static void + static _GLIBCXX20_CONSTEXPR void _S_shrink(_Vector_impl& __impl, size_type __n) { _S_adjust(__impl, __impl._M_finish + __n, __impl._M_finish); } - static void + static _GLIBCXX20_CONSTEXPR void _S_on_dealloc(_Vector_impl& __impl) { if (__impl._M_start) @@ -206,12 +220,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Used on reallocation to tell ASan unused capacity is invalid. struct _Reinit { - explicit _Reinit(_Vector_impl& __impl) : _M_impl(__impl) + explicit _GLIBCXX20_CONSTEXPR + _Reinit(_Vector_impl& __impl) : _M_impl(__impl) { // Mark unused capacity as valid again before deallocating it. _S_on_dealloc(_M_impl); } + _GLIBCXX20_CONSTEXPR ~_Reinit() { // Mark unused capacity as invalid after reallocation. @@ -231,12 +247,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Tell ASan when unused capacity is initialized to be valid. struct _Grow { + _GLIBCXX20_CONSTEXPR _Grow(_Vector_impl& __impl, size_type __n) : _M_impl(__impl), _M_n(__n) { _S_grow(_M_impl, __n); } + _GLIBCXX20_CONSTEXPR ~_Grow() { if (_M_n) _S_shrink(_M_impl, _M_n); } + _GLIBCXX20_CONSTEXPR void _M_grew(size_type __n) { _M_n -= __n; } #if __cplusplus >= 201103L @@ -272,14 +291,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER public: typedef _Alloc allocator_type; + _GLIBCXX20_CONSTEXPR _Tp_alloc_type& _M_get_Tp_allocator() _GLIBCXX_NOEXCEPT { return this->_M_impl; } + _GLIBCXX20_CONSTEXPR const _Tp_alloc_type& _M_get_Tp_allocator() const _GLIBCXX_NOEXCEPT { return this->_M_impl; } + _GLIBCXX20_CONSTEXPR allocator_type get_allocator() const _GLIBCXX_NOEXCEPT { return allocator_type(_M_get_Tp_allocator()); } @@ -290,16 +312,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER _Vector_base() { } #endif + _GLIBCXX20_CONSTEXPR _Vector_base(const allocator_type& __a) _GLIBCXX_NOEXCEPT : _M_impl(__a) { } // Kept for ABI compatibility. #if !_GLIBCXX_INLINE_VERSION + _GLIBCXX20_CONSTEXPR _Vector_base(size_t __n) : _M_impl() { _M_create_storage(__n); } #endif + _GLIBCXX20_CONSTEXPR _Vector_base(size_t __n, const allocator_type& __a) : _M_impl(__a) { _M_create_storage(__n); } @@ -309,9 +334,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Kept for ABI compatibility. # if !_GLIBCXX_INLINE_VERSION + _GLIBCXX20_CONSTEXPR _Vector_base(_Tp_alloc_type&& __a) noexcept : _M_impl(std::move(__a)) { } + _GLIBCXX20_CONSTEXPR _Vector_base(_Vector_base&& __x, const allocator_type& __a) : _M_impl(__a) { @@ -325,11 +352,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } # endif + _GLIBCXX20_CONSTEXPR _Vector_base(const allocator_type& __a, _Vector_base&& __x) : _M_impl(_Tp_alloc_type(__a), std::move(__x._M_impl)) { } #endif + _GLIBCXX20_CONSTEXPR ~_Vector_base() _GLIBCXX_NOEXCEPT { _M_deallocate(_M_impl._M_start, @@ -339,6 +368,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER public: _Vector_impl _M_impl; + _GLIBCXX20_CONSTEXPR pointer _M_allocate(size_t __n) { @@ -346,6 +376,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer(); } + _GLIBCXX20_CONSTEXPR void _M_deallocate(pointer __p, size_t __n) { @@ -355,6 +386,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } protected: + _GLIBCXX20_CONSTEXPR void _M_create_storage(size_t __n) { @@ -443,25 +475,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER static constexpr bool _S_use_relocate() { +#if __cplusplus >= 202002L && __has_builtin(__builtin_is_constant_evaluated) + if (__builtin_is_constant_evaluated()) + return false; // Cannot use memcpy in constant evaluation contexts. +#endif // Instantiating std::__relocate_a might cause an error outside the // immediate context (in __relocate_object_a's noexcept-specifier), // so only do it if we know the type can be move-inserted into *this. return _S_nothrow_relocate(__is_move_insertable<_Tp_alloc_type>{}); } - static pointer + static _GLIBCXX20_CONSTEXPR pointer _S_do_relocate(pointer __first, pointer __last, pointer __result, _Tp_alloc_type& __alloc, true_type) noexcept { return std::__relocate_a(__first, __last, __result, __alloc); } - static pointer + static _GLIBCXX20_CONSTEXPR pointer _S_do_relocate(pointer, pointer, pointer __result, _Tp_alloc_type&, false_type) noexcept { return __result; } - static pointer + static _GLIBCXX20_CONSTEXPR pointer _S_relocate(pointer __first, pointer __last, pointer __result, _Tp_alloc_type& __alloc) noexcept { @@ -494,6 +530,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * @param __a An allocator object. */ explicit + _GLIBCXX20_CONSTEXPR vector(const allocator_type& __a) _GLIBCXX_NOEXCEPT : _Base(__a) { } @@ -507,6 +544,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * constructed elements. */ explicit + _GLIBCXX20_CONSTEXPR vector(size_type __n, const allocator_type& __a = allocator_type()) : _Base(_S_check_init_len(__n, __a), __a) { _M_default_initialize(__n); } @@ -519,6 +557,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * * This constructor fills the %vector with @a __n copies of @a __value. */ + _GLIBCXX20_CONSTEXPR vector(size_type __n, const value_type& __value, const allocator_type& __a = allocator_type()) : _Base(_S_check_init_len(__n, __a), __a) @@ -550,6 +589,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * The newly-created %vector uses a copy of the allocator object used * by @a __x (unless the allocator traits dictate a different object). */ + _GLIBCXX20_CONSTEXPR vector(const vector& __x) : _Base(__x.size(), _Alloc_traits::_S_select_on_copy(__x._M_get_Tp_allocator())) @@ -572,6 +612,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER vector(vector&&) noexcept = default; /// Copy constructor with alternative allocator + _GLIBCXX20_CONSTEXPR vector(const vector& __x, const __type_identity_t& __a) : _Base(__x.size(), __a) { @@ -582,10 +623,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } private: + _GLIBCXX20_CONSTEXPR vector(vector&& __rv, const allocator_type& __m, true_type) noexcept : _Base(__m, std::move(__rv)) { } + _GLIBCXX20_CONSTEXPR vector(vector&& __rv, const allocator_type& __m, false_type) : _Base(__m) { @@ -604,6 +647,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER public: /// Move constructor with alternative allocator + _GLIBCXX20_CONSTEXPR vector(vector&& __rv, const __type_identity_t& __m) noexcept( noexcept( vector(std::declval(), std::declval(), @@ -622,6 +666,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * This will call the element type's copy constructor N times * (where N is @a __l.size()) and do no memory reallocation. */ + _GLIBCXX20_CONSTEXPR vector(initializer_list __l, const allocator_type& __a = allocator_type()) : _Base(__a) @@ -650,6 +695,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template> + _GLIBCXX20_CONSTEXPR vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a = allocator_type()) : _Base(__a) @@ -675,6 +721,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * not touched in any way. Managing the pointer is the user's * responsibility. */ + _GLIBCXX20_CONSTEXPR ~vector() _GLIBCXX_NOEXCEPT { std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish, @@ -691,6 +738,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * * Whether the allocator is copied depends on the allocator traits. */ + _GLIBCXX20_CONSTEXPR vector& operator=(const vector& __x); @@ -705,6 +753,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * * Whether the allocator is moved depends on the allocator traits. */ + _GLIBCXX20_CONSTEXPR vector& operator=(vector&& __x) noexcept(_Alloc_traits::_S_nothrow_move()) { @@ -726,6 +775,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * that the resulting %vector's size is the same as the number * of elements assigned. */ + _GLIBCXX20_CONSTEXPR vector& operator=(initializer_list __l) { @@ -745,6 +795,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * %vector and that the resulting %vector's size is the same as * the number of elements assigned. */ + _GLIBCXX20_CONSTEXPR void assign(size_type __n, const value_type& __val) { _M_fill_assign(__n, __val); } @@ -764,6 +815,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template> + _GLIBCXX20_CONSTEXPR void assign(_InputIterator __first, _InputIterator __last) { _M_assign_dispatch(__first, __last, __false_type()); } @@ -790,6 +842,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * that the resulting %vector's size is the same as the number * of elements assigned. */ + _GLIBCXX20_CONSTEXPR void assign(initializer_list __l) { @@ -807,7 +860,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * element in the %vector. Iteration is done in ordinary * element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR iterator begin() _GLIBCXX_NOEXCEPT { return iterator(this->_M_impl._M_start); } @@ -817,7 +870,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * first element in the %vector. Iteration is done in ordinary * element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_iterator begin() const _GLIBCXX_NOEXCEPT { return const_iterator(this->_M_impl._M_start); } @@ -827,7 +880,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * element in the %vector. Iteration is done in ordinary * element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR iterator end() _GLIBCXX_NOEXCEPT { return iterator(this->_M_impl._M_finish); } @@ -837,7 +890,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * the last element in the %vector. Iteration is done in * ordinary element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_iterator end() const _GLIBCXX_NOEXCEPT { return const_iterator(this->_M_impl._M_finish); } @@ -847,7 +900,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * last element in the %vector. Iteration is done in reverse * element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reverse_iterator rbegin() _GLIBCXX_NOEXCEPT { return reverse_iterator(end()); } @@ -857,7 +910,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * to the last element in the %vector. Iteration is done in * reverse element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reverse_iterator rbegin() const _GLIBCXX_NOEXCEPT { return const_reverse_iterator(end()); } @@ -867,7 +920,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * before the first element in the %vector. Iteration is done * in reverse element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reverse_iterator rend() _GLIBCXX_NOEXCEPT { return reverse_iterator(begin()); } @@ -877,7 +930,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * to one before the first element in the %vector. Iteration * is done in reverse element order. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reverse_iterator rend() const _GLIBCXX_NOEXCEPT { return const_reverse_iterator(begin()); } @@ -888,7 +941,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * first element in the %vector. Iteration is done in ordinary * element order. */ - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_iterator cbegin() const noexcept { return const_iterator(this->_M_impl._M_start); } @@ -898,7 +951,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * the last element in the %vector. Iteration is done in * ordinary element order. */ - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_iterator cend() const noexcept { return const_iterator(this->_M_impl._M_finish); } @@ -908,7 +961,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * to the last element in the %vector. Iteration is done in * reverse element order. */ - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_reverse_iterator crbegin() const noexcept { return const_reverse_iterator(end()); } @@ -918,7 +971,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * to one before the first element in the %vector. Iteration * is done in reverse element order. */ - [[__nodiscard__]] + [[__nodiscard__]] _GLIBCXX20_CONSTEXPR const_reverse_iterator crend() const noexcept { return const_reverse_iterator(begin()); } @@ -926,13 +979,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // [23.2.4.2] capacity /** Returns the number of elements in the %vector. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type size() const _GLIBCXX_NOEXCEPT { return size_type(this->_M_impl._M_finish - this->_M_impl._M_start); } /** Returns the size() of the largest possible %vector. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type max_size() const _GLIBCXX_NOEXCEPT { return _S_max_size(_M_get_Tp_allocator()); } @@ -947,6 +1000,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * %vector's current size the %vector is truncated, otherwise * default constructed elements are appended. */ + _GLIBCXX20_CONSTEXPR void resize(size_type __new_size) { @@ -967,6 +1021,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * the %vector is extended and new elements are populated with * given data. */ + _GLIBCXX20_CONSTEXPR void resize(size_type __new_size, const value_type& __x) { @@ -987,6 +1042,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * the %vector is extended and new elements are populated with * given data. */ + _GLIBCXX20_CONSTEXPR void resize(size_type __new_size, value_type __x = value_type()) { @@ -999,6 +1055,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L /** A non-binding request to reduce capacity() to size(). */ + _GLIBCXX20_CONSTEXPR void shrink_to_fit() { _M_shrink_to_fit(); } @@ -1008,7 +1065,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns the total number of elements that the %vector can * hold before needing to allocate more memory. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR size_type capacity() const _GLIBCXX_NOEXCEPT { return size_type(this->_M_impl._M_end_of_storage @@ -1018,7 +1075,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns true if the %vector is empty. (Thus begin() would * equal end().) */ - _GLIBCXX_NODISCARD bool + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR + bool empty() const _GLIBCXX_NOEXCEPT { return begin() == end(); } @@ -1039,6 +1097,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * %advance, and thus prevent a possible reallocation of memory * and copying of %vector data. */ + _GLIBCXX20_CONSTEXPR void reserve(size_type __n); @@ -1054,7 +1113,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * out_of_range lookups are not defined. (For checked lookups * see at().) */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference operator[](size_type __n) _GLIBCXX_NOEXCEPT { @@ -1073,7 +1132,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * out_of_range lookups are not defined. (For checked lookups * see at().) */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference operator[](size_type __n) const _GLIBCXX_NOEXCEPT { @@ -1083,6 +1142,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER protected: /// Safety check used only from at(). + _GLIBCXX20_CONSTEXPR void _M_range_check(size_type __n) const { @@ -1105,6 +1165,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * is first checked that it is in the range of the vector. The * function throws out_of_range if the check fails. */ + _GLIBCXX20_CONSTEXPR reference at(size_type __n) { @@ -1123,6 +1184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * is first checked that it is in the range of the vector. The * function throws out_of_range if the check fails. */ + _GLIBCXX20_CONSTEXPR const_reference at(size_type __n) const { @@ -1134,7 +1196,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns a read/write reference to the data at the first * element of the %vector. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference front() _GLIBCXX_NOEXCEPT { @@ -1146,7 +1208,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns a read-only (constant) reference to the data at the first * element of the %vector. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference front() const _GLIBCXX_NOEXCEPT { @@ -1158,7 +1220,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns a read/write reference to the data at the last * element of the %vector. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR reference back() _GLIBCXX_NOEXCEPT { @@ -1170,7 +1232,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns a read-only (constant) reference to the data at the * last element of the %vector. */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const_reference back() const _GLIBCXX_NOEXCEPT { @@ -1185,12 +1247,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * Returns a pointer such that [data(), data() + size()) is a valid * range. For a non-empty %vector, data() == &front(). */ - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR _Tp* data() _GLIBCXX_NOEXCEPT { return _M_data_ptr(this->_M_impl._M_start); } - _GLIBCXX_NODISCARD + _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR const _Tp* data() const _GLIBCXX_NOEXCEPT { return _M_data_ptr(this->_M_impl._M_start); } @@ -1206,6 +1268,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * done in constant time if the %vector has preallocated space * available. */ + _GLIBCXX20_CONSTEXPR void push_back(const value_type& __x) { @@ -1222,12 +1285,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } #if __cplusplus >= 201103L + _GLIBCXX20_CONSTEXPR void push_back(value_type&& __x) { emplace_back(std::move(__x)); } template #if __cplusplus > 201402L + _GLIBCXX20_CONSTEXPR reference #else void @@ -1244,6 +1309,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * data is needed, it should be retrieved before pop_back() is * called. */ + _GLIBCXX20_CONSTEXPR void pop_back() _GLIBCXX_NOEXCEPT { @@ -1267,6 +1333,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * std::list. */ template + _GLIBCXX20_CONSTEXPR iterator emplace(const_iterator __position, _Args&&... __args) { return _M_emplace_aux(__position, std::forward<_Args>(__args)...); } @@ -1282,6 +1349,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * could be expensive for a %vector and if it is frequently * used the user should consider using std::list. */ + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, const value_type& __x); #else @@ -1312,6 +1380,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * could be expensive for a %vector and if it is frequently * used the user should consider using std::list. */ + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, value_type&& __x) { return _M_insert_rval(__position, std::move(__x)); } @@ -1329,6 +1398,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * %vector and if it is frequently used the user should * consider using std::list. */ + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, initializer_list __l) { @@ -1354,6 +1424,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * %vector and if it is frequently used the user should * consider using std::list. */ + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, size_type __n, const value_type& __x) { @@ -1398,6 +1469,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER */ template> + _GLIBCXX20_CONSTEXPR iterator insert(const_iterator __position, _InputIterator __first, _InputIterator __last) @@ -1448,6 +1520,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * the pointed-to memory is not touched in any way. Managing * the pointer is the user's responsibility. */ + _GLIBCXX20_CONSTEXPR iterator #if __cplusplus >= 201103L erase(const_iterator __position) @@ -1475,6 +1548,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * pointers, the pointed-to memory is not touched in any way. * Managing the pointer is the user's responsibility. */ + _GLIBCXX20_CONSTEXPR iterator #if __cplusplus >= 201103L erase(const_iterator __first, const_iterator __last) @@ -1499,6 +1573,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * * Whether the allocators are swapped depends on the allocator traits. */ + _GLIBCXX20_CONSTEXPR void swap(vector& __x) _GLIBCXX_NOEXCEPT { @@ -1517,6 +1592,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * pointed-to memory is not touched in any way. Managing the pointer is * the user's responsibility. */ + _GLIBCXX20_CONSTEXPR void clear() _GLIBCXX_NOEXCEPT { _M_erase_at_end(this->_M_impl._M_start); } @@ -1527,6 +1603,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * obtain @a n bytes of memory, and then copies [first,last) into it. */ template + _GLIBCXX20_CONSTEXPR pointer _M_allocate_and_copy(size_type __n, _ForwardIterator __first, _ForwardIterator __last) @@ -1577,6 +1654,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by the second initialize_dispatch above template + _GLIBCXX20_CONSTEXPR void _M_range_initialize(_InputIterator __first, _InputIterator __last, std::input_iterator_tag) @@ -1596,6 +1674,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by the second initialize_dispatch above template + _GLIBCXX20_CONSTEXPR void _M_range_initialize(_ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag) @@ -1612,6 +1691,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by the first initialize_dispatch above and by the // vector(n,value,a) constructor. + _GLIBCXX20_CONSTEXPR void _M_fill_initialize(size_type __n, const value_type& __value) { @@ -1622,6 +1702,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L // Called by the vector(n) constructor. + _GLIBCXX20_CONSTEXPR void _M_default_initialize(size_type __n) { @@ -1639,12 +1720,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // _GLIBCXX_RESOLVE_LIB_DEFECTS // 438. Ambiguity in the "do the right thing" clause template + _GLIBCXX20_CONSTEXPR void _M_assign_dispatch(_Integer __n, _Integer __val, __true_type) { _M_fill_assign(__n, __val); } // Called by the range assign to implement [23.1.1]/9 template + _GLIBCXX20_CONSTEXPR void _M_assign_dispatch(_InputIterator __first, _InputIterator __last, __false_type) @@ -1652,18 +1735,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by the second assign_dispatch above template + _GLIBCXX20_CONSTEXPR void _M_assign_aux(_InputIterator __first, _InputIterator __last, std::input_iterator_tag); // Called by the second assign_dispatch above template + _GLIBCXX20_CONSTEXPR void _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag); // Called by assign(n,t), and the range assign when it turns out // to be the same thing. + _GLIBCXX20_CONSTEXPR void _M_fill_assign(size_type __n, const value_type& __val); @@ -1674,6 +1760,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // _GLIBCXX_RESOLVE_LIB_DEFECTS // 438. Ambiguity in the "do the right thing" clause template + _GLIBCXX20_CONSTEXPR void _M_insert_dispatch(iterator __pos, _Integer __n, _Integer __val, __true_type) @@ -1681,6 +1768,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by the range insert to implement [23.1.1]/9 template + _GLIBCXX20_CONSTEXPR void _M_insert_dispatch(iterator __pos, _InputIterator __first, _InputIterator __last, __false_type) @@ -1691,26 +1779,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by the second insert_dispatch above template + _GLIBCXX20_CONSTEXPR void _M_range_insert(iterator __pos, _InputIterator __first, _InputIterator __last, std::input_iterator_tag); // Called by the second insert_dispatch above template + _GLIBCXX20_CONSTEXPR void _M_range_insert(iterator __pos, _ForwardIterator __first, _ForwardIterator __last, std::forward_iterator_tag); // Called by insert(p,n,x), and the range insert when it turns out to be // the same thing. + _GLIBCXX20_CONSTEXPR void _M_fill_insert(iterator __pos, size_type __n, const value_type& __x); #if __cplusplus >= 201103L // Called by resize(n). + _GLIBCXX20_CONSTEXPR void _M_default_append(size_type __n); + _GLIBCXX20_CONSTEXPR bool _M_shrink_to_fit(); #endif @@ -1728,53 +1821,69 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER struct _Temporary_value { template - explicit + _GLIBCXX20_CONSTEXPR explicit _Temporary_value(vector* __vec, _Args&&... __args) : _M_this(__vec) { _Alloc_traits::construct(_M_this->_M_impl, _M_ptr(), std::forward<_Args>(__args)...); } + _GLIBCXX20_CONSTEXPR ~_Temporary_value() { _Alloc_traits::destroy(_M_this->_M_impl, _M_ptr()); } - value_type& - _M_val() { return *_M_ptr(); } + _GLIBCXX20_CONSTEXPR value_type& + _M_val() noexcept { return _M_storage._M_val; } private: - _Tp* - _M_ptr() { return reinterpret_cast<_Tp*>(&__buf); } + _GLIBCXX20_CONSTEXPR _Tp* + _M_ptr() noexcept { return std::__addressof(_M_storage._M_val); } - vector* _M_this; - typename aligned_storage::type __buf; + union _Storage + { + constexpr _Storage() : _M_byte() { } + _GLIBCXX20_CONSTEXPR ~_Storage() { } + _Storage& operator=(const _Storage&) = delete; + unsigned char _M_byte; + _Tp _M_val; + }; + + vector* _M_this; + _Storage _M_storage; }; // Called by insert(p,x) and other functions when insertion needs to // reallocate or move existing elements. _Arg is either _Tp& or _Tp. template + _GLIBCXX20_CONSTEXPR void _M_insert_aux(iterator __position, _Arg&& __arg); template + _GLIBCXX20_CONSTEXPR void _M_realloc_insert(iterator __position, _Args&&... __args); // Either move-construct at the end, or forward to _M_insert_aux. + _GLIBCXX20_CONSTEXPR iterator _M_insert_rval(const_iterator __position, value_type&& __v); // Try to emplace at the end, otherwise forward to _M_insert_aux. template + _GLIBCXX20_CONSTEXPR iterator _M_emplace_aux(const_iterator __position, _Args&&... __args); // Emplacing an rvalue of the correct type can use _M_insert_rval. + _GLIBCXX20_CONSTEXPR iterator _M_emplace_aux(const_iterator __position, value_type&& __v) { return _M_insert_rval(__position, std::move(__v)); } #endif // Called by _M_fill_insert, _M_insert_aux etc. + _GLIBCXX20_CONSTEXPR size_type _M_check_len(size_type __n, const char* __s) const { @@ -1786,7 +1895,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } // Called by constructors to check initial size. - static size_type + static _GLIBCXX20_CONSTEXPR size_type _S_check_init_len(size_type __n, const allocator_type& __a) { if (__n > _S_max_size(_Tp_alloc_type(__a))) @@ -1795,7 +1904,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER return __n; } - static size_type + static _GLIBCXX20_CONSTEXPR size_type _S_max_size(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT { // std::distance(begin(), end()) cannot be greater than PTRDIFF_MAX, @@ -1811,6 +1920,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Called by erase(q1,q2), clear(), resize(), _M_fill_assign, // _M_assign_aux. + _GLIBCXX20_CONSTEXPR void _M_erase_at_end(pointer __pos) _GLIBCXX_NOEXCEPT { @@ -1823,9 +1933,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } } + _GLIBCXX20_CONSTEXPR iterator _M_erase(iterator __position); + _GLIBCXX20_CONSTEXPR iterator _M_erase(iterator __first, iterator __last); @@ -1834,6 +1946,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Constant-time move assignment when source object's memory can be // moved, either because the source's allocator will move too // or because the allocators are equal. + _GLIBCXX20_CONSTEXPR void _M_move_assign(vector&& __x, true_type) noexcept { @@ -1845,6 +1958,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // Do move assignment when it might not be possible to move source // object's memory, resulting in a linear-time operation. + _GLIBCXX20_CONSTEXPR void _M_move_assign(vector&& __x, false_type) { @@ -1863,12 +1977,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif template + _GLIBCXX20_CONSTEXPR _Up* _M_data_ptr(_Up* __ptr) const _GLIBCXX_NOEXCEPT { return __ptr; } #if __cplusplus >= 201103L template + _GLIBCXX20_CONSTEXPR typename std::pointer_traits<_Ptr>::element_type* _M_data_ptr(_Ptr __ptr) const { return empty() ? nullptr : std::__to_address(__ptr); } @@ -1911,6 +2027,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * and if corresponding elements compare equal. */ template + _GLIBCXX20_CONSTEXPR inline bool operator==(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) { return (__x.size() == __y.size() @@ -1929,6 +2046,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER * `<` and `>=` etc. */ template + _GLIBCXX20_CONSTEXPR inline __detail::__synth3way_t<_Tp> operator<=>(const vector<_Tp, _Alloc>& __x, const vector<_Tp, _Alloc>& __y) { @@ -1981,6 +2099,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER /// See std::vector::swap(). template + _GLIBCXX20_CONSTEXPR inline void swap(vector<_Tp, _Alloc>& __x, vector<_Tp, _Alloc>& __y) _GLIBCXX_NOEXCEPT_IF(noexcept(__x.swap(__y))) diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index 16366e03c86..7e3115cb7a6 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -62,6 +62,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: reserve(size_type __n) @@ -102,6 +103,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template #if __cplusplus > 201402L + _GLIBCXX20_CONSTEXPR typename vector<_Tp, _Alloc>::reference #else void @@ -126,6 +128,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #endif template + _GLIBCXX20_CONSTEXPR typename vector<_Tp, _Alloc>::iterator vector<_Tp, _Alloc>:: #if __cplusplus >= 201103L @@ -167,6 +170,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR typename vector<_Tp, _Alloc>::iterator vector<_Tp, _Alloc>:: _M_erase(iterator __position) @@ -180,6 +184,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR typename vector<_Tp, _Alloc>::iterator vector<_Tp, _Alloc>:: _M_erase(iterator __first, iterator __last) @@ -194,6 +199,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR vector<_Tp, _Alloc>& vector<_Tp, _Alloc>:: operator=(const vector<_Tp, _Alloc>& __x) @@ -253,6 +259,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_fill_assign(size_t __n, const value_type& __val) @@ -278,6 +285,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_assign_aux(_InputIterator __first, _InputIterator __last, @@ -296,6 +304,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_assign_aux(_ForwardIterator __first, _ForwardIterator __last, @@ -336,6 +345,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template + _GLIBCXX20_CONSTEXPR auto vector<_Tp, _Alloc>:: _M_insert_rval(const_iterator __position, value_type&& __v) -> iterator @@ -360,6 +370,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR auto vector<_Tp, _Alloc>:: _M_emplace_aux(const_iterator __position, _Args&&... __args) @@ -391,6 +402,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_insert_aux(iterator __position, _Arg&& __arg) @@ -422,6 +434,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_realloc_insert(iterator __position, _Args&&... __args) @@ -505,6 +518,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_fill_insert(iterator __position, size_type __n, const value_type& __x) @@ -607,6 +621,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_default_append(size_type __n) @@ -683,6 +698,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR bool vector<_Tp, _Alloc>:: _M_shrink_to_fit() @@ -696,6 +712,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_range_insert(iterator __pos, _InputIterator __first, @@ -717,6 +734,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR void vector<_Tp, _Alloc>:: _M_range_insert(iterator __position, _ForwardIterator __first, @@ -806,6 +824,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER // vector template + _GLIBCXX20_CONSTEXPR void vector:: _M_reallocate(size_type __n) @@ -820,6 +839,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void vector:: _M_fill_insert(iterator __position, size_type __n, bool __x) @@ -852,6 +872,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER template template + _GLIBCXX20_CONSTEXPR void vector:: _M_insert_range(iterator __position, _ForwardIterator __first, @@ -886,6 +907,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR void vector:: _M_insert_aux(iterator __position, bool __x) @@ -914,6 +936,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR typename vector::iterator vector:: _M_erase(iterator __position) @@ -925,6 +948,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER } template + _GLIBCXX20_CONSTEXPR typename vector::iterator vector:: _M_erase(iterator __first, iterator __last) @@ -936,6 +960,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER #if __cplusplus >= 201103L template + _GLIBCXX20_CONSTEXPR bool vector:: _M_shrink_to_fit() @@ -974,9 +999,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION operator()(const _GLIBCXX_STD_C::vector& __b) const noexcept { size_t __hash = 0; - using _GLIBCXX_STD_C::_S_word_bit; - using _GLIBCXX_STD_C::_Bit_type; - const size_t __words = __b.size() / _S_word_bit; if (__words) { diff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector index 096511c05b2..890b0ddb3eb 100644 --- a/libstdc++-v3/include/std/vector +++ b/libstdc++-v3/include/std/vector @@ -102,6 +102,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION #define __cpp_lib_erase_if 202002L template + _GLIBCXX20_CONSTEXPR inline typename vector<_Tp, _Alloc>::size_type erase_if(vector<_Tp, _Alloc>& __cont, _Predicate __pred) { @@ -115,6 +116,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template + _GLIBCXX20_CONSTEXPR inline typename vector<_Tp, _Alloc>::size_type erase(vector<_Tp, _Alloc>& __cont, const _Up& __value) { diff --git a/libstdc++-v3/testsuite/23_containers/headers/vector/synopsis.cc b/libstdc++-v3/testsuite/23_containers/headers/vector/synopsis.cc index 0fc46fe0528..f02659f99be 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 vector; template + CONSTEXPR bool operator==(const vector& x, const vector& y); +#if __cplusplus < 202002L template bool operator< (const vector& x, const vector& y); @@ -53,17 +61,21 @@ namespace std { template bool operator<=(const vector& x, const vector& y); +#endif template + CONSTEXPR void swap(vector& x, vector& y) NOTHROW(noexcept(x.swap(y))); template class vector; template + CONSTEXPR bool operator==(const vector& x, const vector& y); +#if __cplusplus < 202002L template bool operator< (const vector& x, const vector& y); @@ -83,7 +95,9 @@ namespace std { template bool operator<=(const vector& x, const vector& y); +#endif template + CONSTEXPR void swap(vector& x, vector& 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 43f3343a578..da5e6b420d2 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 is special, see libstdc++/31370. vector 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 00000000000..52b10b66120 --- /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 +#include + +constexpr std::size_t +capacity_for(std::size_t n) +{ + std::size_t N = std::vector(1).capacity(); + if (auto r = n % N) + return n - r + N; + return n; +} + +constexpr bool +test_empty() +{ + std::vector v; + VERIFY( v.empty() ); + v = {1}; + VERIFY( !v.empty() ); + + return true; +} + +static_assert( test_empty() ); + +constexpr bool +test_size() +{ + std::vector 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 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 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 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 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 7a730df2e18..ae2bd03c2ba 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 @@ // . // { 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 #include -void +constexpr bool test01() { std::vector 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::strong_ordering> ); + + return true; } -void +constexpr bool test05() { // vector iterators are random access, so should support <=> @@ -63,11 +66,9 @@ test05() static_assert( std::same_as c.begin()), std::strong_ordering> ); + + return true; } -int -main() -{ - test01(); - test05(); -} +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 00000000000..edd506081cc --- /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 +#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 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 v1; + static_assert(v1.size() == 0); + static_assert(v1.capacity() == 0); + + constexpr std::allocator a; + constexpr std::vector v2(a); + static_assert(v2.size() == 0); + static_assert(v2.capacity() == 0); + + constexpr Alloc aa(10); + constexpr std::vector> 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 v1; + VERIFY(v1.size() == 0); + VERIFY(v1.capacity() == 0); + + // vector(const Allocator&) + + const std::allocator a; + std::vector v2(a); + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + const Alloc aa(10); + std::vector> 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 v0(0); + VERIFY(v0.size() == 0); + + std::vector v1(1); + VERIFY(v1.size() == 1); + + std::vector v2(2); + VERIFY(v2.size() == 2); + + std::vector v50(50); + VERIFY(v50.size() == 50); + + const std::allocator a; + std::vector a0(0, a); + VERIFY(a0.size() == 0); + + std::vector a1(1, a); + VERIFY(a1.size() == 1); + + std::vector a2(2, a); + VERIFY(a2.size() == 2); + + std::vector a50(50, a); + VERIFY(a50.size() == 50); + + const Alloc la(10); + std::vector> l0(0, la); + VERIFY(l0.size() == 0); + VERIFY(l0.get_allocator() == la); + + std::vector> l1(1, la); + VERIFY(l1.size() == 1); + VERIFY(l1.get_allocator() == la); + + std::vector> l2(2, la); + VERIFY(l2.size() == 2); + VERIFY(l2.get_allocator() == la); + + std::vector> l50(50, la); + VERIFY(l50.size() == 50); + VERIFY(l50.get_allocator() == la); + + // vector(size_type, const T&, const Allocator& = Allocator()) + + std::vector v3(3, true); + VERIFY(v3.size() == 3); + VERIFY(v3[0] == true && v3[2] == true); + + std::vector a3(3, false, a); + VERIFY(a3.size() == 3); + VERIFY(a3[0] == false && a3[2] == false); + + std::vector> 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 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 a(5); + std::vector> 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 v1(input_iterator(3), input_iterator()); + VERIFY(v1.size() == 3); + VERIFY(v1[0] == true && v1[1] == false && v1[2] == true); + + std::vector> 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, const Allocator& = Allocator()) + + std::vector v0({ false, true, false }); + VERIFY(v0.size() == 3); + VERIFY(v0[0] == false && v0[1] == true && v0[2] == false); + + const Alloc a(5); + std::vector> 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 v0({ 1, 0, 0, 1, 0, 1, 1, 0 }); + const std::vector> l0({ 0, 0, 1, 1, 0, 1, 0, 1, 1, 1 }); + + // vector(const vector&) + + std::vector 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 as(6); + std::vector> s1(3, true, as); + std::vector> s2(s1); + VERIFY( s2.size() == s1.size() ); + VERIFY( s2.get_allocator().personality == -1 ); + + // vector(const vector&, const Allocator&) + + const Alloc a(6); + std::vector> 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 v0({ 1, 0, 0, 1, 0, 1, 1, 0 }); + const std::vector> l0({ 0, 0, 1, 1, 0, 1, 0, 1, 1, 1 }); + + // vector(const vector&) + + std::vector v1(v0); + std::vector 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 a(6); + std::vector> l1(l0); + std::vector> 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> 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 00000000000..6fa87588eff --- /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 +#include + +constexpr bool +test_iterators() +{ + std::vector 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 v{1, 1, 0, 0, 1, 0, 1, 0, 1}; + std::vector::reference r1 = v.at(1); + VERIFY( r1 ); + std::vector::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 + constexpr std::false_type + access_empty() { return {}; } + +template + requires (std::bool_constant<(std::vector().at(0), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template + requires (std::bool_constant<(std::vector().back(), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +static_assert( ! access_empty() ); + +template + constexpr std::false_type + access_empty_front() { return {}; } + +template + requires (std::bool_constant<(std::vector()[0], true)>::value) + constexpr std::true_type + access_empty_front() { return {}; } + +template + requires (std::bool_constant<(std::vector().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 00000000000..02faa02f954 --- /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 +#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; + + 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(1).capacity(); + if (auto r = n % N) + return n - r + N; + return n; +} + +constexpr bool +copy_assign() +{ + // vector::operator=(const vector&) + + std::vector 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> va1(Alloc(1)), va2(Alloc(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 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> va1(Alloc(1)), va2(Alloc(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 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> va1(Alloc(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 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 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> va1(Alloc(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 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> va1(Alloc(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 00000000000..b27df2b2227 --- /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 +#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; + std::vector::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> va; + va.push_back(true); + 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 ); + // 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) + 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> 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(1).capacity(); + if (auto r = n % N) + return n - r + N; + return n; +} + +constexpr bool +test_clear() +{ + std::vector v0; + v0.clear(); + VERIFY( v0.size() == 0 ); + VERIFY( v0.capacity() == 0 ); + + std::vector v{1, 0, 0}; + v.clear(); + VERIFY( v.size() == 0 ); + VERIFY( v.capacity() == capacity_for(3) ); + + std::vector> va; + va.clear(); + va.push_back(1); + va.clear(); + va.clear(); + + return true; +} + +static_assert( test_clear() ); + +constexpr bool +test_flip() +{ + std::vector 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 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::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 a2b8c1aa4ad..c67944663cf 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 #include -#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& 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 00000000000..ba444d04ee9 --- /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 +#include +#include + +constexpr bool +test_std_swap() +{ + std::vector v1 = {true, false, true}; + std::vector 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 v1 = {true, false, true}; + std::vector 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 v1 = {true, false, true}; + std::vector::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 00000000000..de9d0b03790 --- /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 +#include + +constexpr bool +test_empty() +{ + std::vector v; + VERIFY( v.empty() ); + v = {1}; + VERIFY( !v.empty() ); + + return true; +} + +static_assert( test_empty() ); + +constexpr bool +test_size() +{ + std::vector 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 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 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 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 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 0ffacb96f75..8f4a2645e91 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 @@ // . // { 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 #include -void +constexpr bool test01() { std::vector 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> ); static_assert( ! std::three_way_comparable ); static_assert( ! std::three_way_comparable> ); + + 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 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

); static_assert( std::same_as 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> ); @@ -123,9 +130,11 @@ test04() std::vector c{ {1}, {2}, {3} }, d{ {1}, {2}, {3}, {4} }; static_assert( std::same_as 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 c.begin()), std::strong_ordering> ); + + return true; } -int -main() -{ - test01(); - test02(); - test03(); - test04(); - test05(); -} +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 302af9c2e97..4f8396fba6d 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 v1{x, x+1}; // { dg-error "here" } - - // Should not be able to create vector using uninitialized_fill_n: - std::vector v2{2u, X{}}; // { dg-error "here" } + std::vector 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 with C++17 guaranteed copy elision, - // but shouldn't be able to copy from it with uninitialized_copy: - std::vector v3{Y{}, Y{}, Y{}}; // { dg-error "here" "" { target c++17 } } -#endif + + // Should not be able to create vector using uninitialized_fill_n: + std::vector 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 00000000000..24ade4e0800 --- /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 +// . + +// { dg-do compile { target c++17 } } + +#include + +// PR libstdc++/89164 + +struct X +{ + X() = default; + X(const X&) = delete; +}; + +void test03() +{ + // Can create initializer_list with C++17 guaranteed copy elision, + // but shouldn't be able to copy from it with uninitialized_copy: + std::vector 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 00000000000..f02b39aefad --- /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 +#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 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 v1; + static_assert(v1.size() == 0); + static_assert(v1.capacity() == 0); + + constexpr std::allocator a; + constexpr std::vector v2(a); + static_assert(v2.size() == 0); + static_assert(v2.capacity() == 0); + + constexpr Alloc aa(10); + constexpr std::vector> 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 v1; + VERIFY(v1.size() == 0); + VERIFY(v1.capacity() == 0); + + // vector(const Allocator&) + + const std::allocator a; + std::vector v2(a); + VERIFY(v2.size() == 0); + VERIFY(v2.capacity() == 0); + + const Alloc aa(10); + std::vector> 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 v0(0); + VERIFY(v0.size() == 0); + + std::vector v1(1); + VERIFY(v1.size() == 1); + + std::vector v2(2); + VERIFY(v2.size() == 2); + + std::vector v50(50); + VERIFY(v50.size() == 50); + + const std::allocator a; + std::vector a0(0, a); + VERIFY(a0.size() == 0); + + std::vector a1(1, a); + VERIFY(a1.size() == 1); + + std::vector a2(2, a); + VERIFY(a2.size() == 2); + + std::vector a50(50, a); + VERIFY(a50.size() == 50); + + const Alloc la(10); + std::vector> l0(0, la); + VERIFY(l0.size() == 0); + VERIFY(l0.get_allocator() == la); + + std::vector> l1(1, la); + VERIFY(l1.size() == 1); + VERIFY(l1.get_allocator() == la); + + std::vector> l2(2, la); + VERIFY(l2.size() == 2); + VERIFY(l2.get_allocator() == la); + + std::vector> l50(50, la); + VERIFY(l50.size() == 50); + VERIFY(l50.get_allocator() == la); + + // vector(size_type, const T&, const Allocator& = Allocator()) + + std::vector v3(3, 4); + VERIFY(v3.size() == 3); + VERIFY(v3[0] == 4 && v3[2] == 4); + + std::vector a3(3, 5, a); + VERIFY(a3.size() == 3); + VERIFY(a3[0] == 5 && a3[2] == 5); + + std::vector> 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 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 a(5); + std::vector> 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 v1(input_iterator(3), input_iterator()); + VERIFY(v1.size() == 3); + VERIFY(v1[0] == 3 && v1[1] == 2 && v1[2] == 1); + + std::vector> 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, const Allocator& = Allocator()) + + std::vector v0({ 1, 2, 3 }); + VERIFY(v0.size() == 3); + VERIFY(v0[0] == 1 && v0[1] == 2 && v0[2] == 3); + + const Alloc a(5); + std::vector> 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 v0({ 1, 2, 3 }); + const std::vector> l0({ 4, 5, 6 }); + + // vector(const vector&) + + std::vector 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 as(6); + std::vector> s1(3, short(2), as); + std::vector> s2(s1); + VERIFY( s2.size() == s1.size() ); + VERIFY( s2.get_allocator().personality == -1 ); + + // vector(const vector&, const Allocator&) + + const Alloc a(6); + std::vector> 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 v0({ 1, 2, 3 }); + const std::vector> l0({ 4, 5, 6 }); + + // vector(const vector&) + + std::vector v1(v0); + std::vector 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 a(6); + std::vector> l1(l0); + std::vector> 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> 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 00000000000..45b3167eab0 --- /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 +#include + +constexpr bool +test_data() +{ + std::vector v; + VERIFY( v.data() == nullptr ); + v.reserve(1); + VERIFY( v.data() != nullptr ); + const std::vector 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 00000000000..9b3b7f634d7 --- /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 +#include + +constexpr bool +test_iterators() +{ + std::vector 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 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 + constexpr std::false_type + access_empty() { return {}; } + +template + requires (std::bool_constant<(std::vector().at(0), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template + requires (std::bool_constant<(std::vector()[0], true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template + requires (std::bool_constant<(std::vector().front(), true)>::value) + constexpr std::true_type + access_empty() { return {}; } + +template + requires (std::bool_constant<(std::vector().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 00000000000..638cffe9822 --- /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 +#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; + + 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 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> va1(Alloc(1)), va2(Alloc(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 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> va1(Alloc(1)), va2(Alloc(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 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> va1(Alloc(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 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 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> va1(Alloc(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 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> va1(Alloc(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 00000000000..36efecf5807 --- /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 +#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() ); 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 00000000000..4d06558b47b --- /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 +#include +#include + +constexpr bool +test_std_swap() +{ + std::vector v1 = {1, 2, 3}; + std::vector 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 v1 = {1, 2, 3}; + std::vector 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());