From patchwork Fri Oct 11 15:31:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 1175289 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-510777-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="TxI8686R"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 46qX4C71jmz9sP4 for ; Sat, 12 Oct 2019 02:31:39 +1100 (AEDT) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=Gu2ih6QkLGTTq4LWZ4VthBiG95yPYSRWViDPhQyuUt1nb5iArd19N neYTbbqEKrmMU3GQywMb5q5IqmNvT1eJF8QsjS7Gw7AAfIEfVsJgvbWnv5shJ+GW 7AumXPFbhQTWGardTKtlKf5jfyQZXpCaNhtf/wGHzfrhTVpH0pdgYs= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=dC+0x+TyhwWUBUritAOu2Md5nXw=; b=TxI8686RDBmV8N1sgnRS /qpMG1/hu8EGQ1w3OwS8TtIcAmLNGIz6Hq+XOzvDQpK0qA2xNf5qaEV+69yaTGvG KgGUZWARZ2/hrNJN1BLZjw75tLEZYPz48R4vhzjyhI63WtY1NQSXET2NeipZpOFr GQUOqhlA2wAN8Yys045qkYI= Received: (qmail 93635 invoked by alias); 11 Oct 2019 15:31:31 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 93616 invoked by uid 89); 11 Oct 2019 15:31:31 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-16.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, KAM_SHORT, SPF_HELO_PASS autolearn=ham version=3.3.1 spammy=1297, Proposal, U*redi X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 11 Oct 2019 15:31:27 +0000 Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id EF2A946671; Fri, 11 Oct 2019 15:31:25 +0000 (UTC) Received: from localhost (unknown [10.33.36.149]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4FA6010013D9; Fri, 11 Oct 2019 15:31:25 +0000 (UTC) Date: Fri, 11 Oct 2019 16:31:24 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/92059 fix several bugs in tr2::dynamic_bitset Message-ID: <20191011153124.GA12258@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.12.1 (2019-06-15) PR libstdc++/92059 * include/tr2/dynamic_bitset (__dynamic_bitset_base): Define all special member functions as defaulted. Add noexcept to most members. (__dynamic_bitset_base(size_t, unsigned long long, const _Alloc&)): Mask off unwanted bits in the __val parameter. Avoid undefined left shifts. (__dynamic_bitset_base::_M_assign): Remove. (__dynamic_bitset_base::_M_do_reset): Use std::fill. (__dynamic_bitset_base::_M_are_all_aux): Avoid integer promotion when block_type has lower rank than int. (dynamic_bitset): Add noexcept to most members. Use injected-class-name in return types and parameter types. (dynamic_bitset::_M_Nb): Add default member initializer. (dynamic_bitset(), dynamic_bitset(const dynamic_bitset&)): Define as defaulted. (dynamic_bitset(dynamic_bitset&&)): Clear source object after move. (dynamic_bitset::operator=(const dynamic_bitset&)): Define as defaulted. (dynamic_bitset::operator=(dynamic_bitset&&)): Add noexcept-specifier. Define without using swap, to propagate allocator correctly. (dynamic_bitset(const char*, const _Alloc&)): Use strlen. (dynamic_bitset::_M_do_sanitize, dynamic_bitset::_M_do_fill): Use casts to avoid unwanted integer promotions. (dynamic_bitset::_M_copy_from_ptr): Rearrange template parameters and add default template arguments and default argument to simplify usage. (dynamic_bitset::_M_copy_from_string): Adjust call to _M_copy_from_ptr. (operator==(const dynamic_bitset&, const dynamic_bitset&)) (operator<(const dynamic_bitset&, const dynamic_bitset&)): Use _M_Nb. * include/tr2/dynamic_bitset.tcc (dynamic_bitset::_M_copy_from_ptr): Adjust template parameters to match declaration. * testsuite/tr2/dynamic_bitset/cmp.cc: New test. * testsuite/tr2/dynamic_bitset/cons.cc: New test. * testsuite/tr2/dynamic_bitset/copy.cc: New test. * testsuite/tr2/dynamic_bitset/move.cc: New test. * testsuite/tr2/dynamic_bitset/pr92059.cc: New test. Tested x86_64-linux. Committed to trunk. This seems worth backporting too, as the type is now no longer totally broken (e.g. it is now copy constructible, and the move constructor no longer breaks the class invariant). commit 18ed132a6b119bc2c23078848a8981ba96067a15 Author: redi Date: Fri Oct 11 15:29:55 2019 +0000 PR libstdc++/92059 fix several bugs in tr2::dynamic_bitset PR libstdc++/92059 * include/tr2/dynamic_bitset (__dynamic_bitset_base): Define all special member functions as defaulted. Add noexcept to most members. (__dynamic_bitset_base(size_t, unsigned long long, const _Alloc&)): Mask off unwanted bits in the __val parameter. Avoid undefined left shifts. (__dynamic_bitset_base::_M_assign): Remove. (__dynamic_bitset_base::_M_do_reset): Use std::fill. (__dynamic_bitset_base::_M_are_all_aux): Avoid integer promotion when block_type has lower rank than int. (dynamic_bitset): Add noexcept to most members. Use injected-class-name in return types and parameter types. (dynamic_bitset::_M_Nb): Add default member initializer. (dynamic_bitset(), dynamic_bitset(const dynamic_bitset&)): Define as defaulted. (dynamic_bitset(dynamic_bitset&&)): Clear source object after move. (dynamic_bitset::operator=(const dynamic_bitset&)): Define as defaulted. (dynamic_bitset::operator=(dynamic_bitset&&)): Add noexcept-specifier. Define without using swap, to propagate allocator correctly. (dynamic_bitset(const char*, const _Alloc&)): Use strlen. (dynamic_bitset::_M_do_sanitize, dynamic_bitset::_M_do_fill): Use casts to avoid unwanted integer promotions. (dynamic_bitset::_M_copy_from_ptr): Rearrange template parameters and add default template arguments and default argument to simplify usage. (dynamic_bitset::_M_copy_from_string): Adjust call to _M_copy_from_ptr. (operator==(const dynamic_bitset&, const dynamic_bitset&)) (operator<(const dynamic_bitset&, const dynamic_bitset&)): Use _M_Nb. * include/tr2/dynamic_bitset.tcc (dynamic_bitset::_M_copy_from_ptr): Adjust template parameters to match declaration. * testsuite/tr2/dynamic_bitset/cmp.cc: New test. * testsuite/tr2/dynamic_bitset/cons.cc: New test. * testsuite/tr2/dynamic_bitset/copy.cc: New test. * testsuite/tr2/dynamic_bitset/move.cc: New test. * testsuite/tr2/dynamic_bitset/pr92059.cc: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@276890 138bc75d-0d04-0410-961f-82ee72b054a4 diff --git a/libstdc++-v3/include/tr2/dynamic_bitset b/libstdc++-v3/include/tr2/dynamic_bitset index 434a4cc87ec..28c877c0484 100644 --- a/libstdc++-v3/include/tr2/dynamic_bitset +++ b/libstdc++-v3/include/tr2/dynamic_bitset @@ -34,10 +34,9 @@ #include #include #include -#include // For std::allocator -#include // For invalid_argument, out_of_range, - // overflow_error -#include +#include +#include +#include // For fill #include namespace std _GLIBCXX_VISIBILITY(default) @@ -76,41 +75,48 @@ namespace tr2 std::vector _M_w; explicit - __dynamic_bitset_base(const allocator_type& __alloc = allocator_type()) + __dynamic_bitset_base(const allocator_type& __alloc) : _M_w(__alloc) { } - explicit - __dynamic_bitset_base(__dynamic_bitset_base&& __b) - { this->_M_w.swap(__b._M_w); } + __dynamic_bitset_base() = default; + __dynamic_bitset_base(const __dynamic_bitset_base&) = default; + __dynamic_bitset_base(__dynamic_bitset_base&& __b) = default; + __dynamic_bitset_base& operator=(const __dynamic_bitset_base&) = default; + __dynamic_bitset_base& operator=(__dynamic_bitset_base&&) = default; + ~__dynamic_bitset_base() = default; explicit __dynamic_bitset_base(size_type __nbits, unsigned long long __val = 0ULL, const allocator_type& __alloc = allocator_type()) - : _M_w(__nbits / _S_bits_per_block - + (__nbits % _S_bits_per_block > 0), - __val, __alloc) + : _M_w(__nbits / _S_bits_per_block + (__nbits % _S_bits_per_block > 0), + block_type(0), __alloc) { - unsigned long long __mask = ~static_cast(0); - size_t __n = std::min(this->_M_w.size(), - sizeof(unsigned long long) / sizeof(block_type)); - for (size_t __i = 0; __i < __n; ++__i) + if (__nbits < std::numeric_limits::digits) + __val &= ~(-1ULL << __nbits); + if (__val == 0) + return; + + if _GLIBCXX17_CONSTEXPR (sizeof(__val) == sizeof(block_type)) + _M_w[0] = __val; + else { - this->_M_w[__i] = (__val & __mask) >> (__i * _S_bits_per_block); - __mask <<= _S_bits_per_block; + const size_t __n + = std::min(_M_w.size(), sizeof(__val) / sizeof(block_type)); + for (size_t __i = 0; __val && __i < __n; ++__i) + { + _M_w[__i] = static_cast(__val); + __val >>= _S_bits_per_block; + } } } void - _M_assign(const __dynamic_bitset_base& __b) - { this->_M_w = __b._M_w; } - - void - _M_swap(__dynamic_bitset_base& __b) + _M_swap(__dynamic_bitset_base& __b) noexcept { this->_M_w.swap(__b._M_w); } void - _M_clear() + _M_clear() noexcept { this->_M_w.clear(); } void @@ -129,7 +135,7 @@ namespace tr2 } allocator_type - _M_get_allocator() const + _M_get_allocator() const noexcept { return this->_M_w.get_allocator(); } static size_type @@ -149,23 +155,23 @@ namespace tr2 { return (static_cast(1)) << _S_whichbit(__pos); } block_type& - _M_getword(size_type __pos) + _M_getword(size_type __pos) noexcept { return this->_M_w[_S_whichword(__pos)]; } block_type - _M_getword(size_type __pos) const + _M_getword(size_type __pos) const noexcept { return this->_M_w[_S_whichword(__pos)]; } block_type& - _M_hiword() + _M_hiword() noexcept { return this->_M_w[_M_w.size() - 1]; } block_type - _M_hiword() const + _M_hiword() const noexcept { return this->_M_w[_M_w.size() - 1]; } void - _M_do_and(const __dynamic_bitset_base& __x) + _M_do_and(const __dynamic_bitset_base& __x) noexcept { if (__x._M_w.size() == this->_M_w.size()) for (size_t __i = 0; __i < this->_M_w.size(); ++__i) @@ -175,7 +181,7 @@ namespace tr2 } void - _M_do_or(const __dynamic_bitset_base& __x) + _M_do_or(const __dynamic_bitset_base& __x) noexcept { if (__x._M_w.size() == this->_M_w.size()) for (size_t __i = 0; __i < this->_M_w.size(); ++__i) @@ -185,7 +191,7 @@ namespace tr2 } void - _M_do_xor(const __dynamic_bitset_base& __x) + _M_do_xor(const __dynamic_bitset_base& __x) noexcept { if (__x._M_w.size() == this->_M_w.size()) for (size_t __i = 0; __i < this->_M_w.size(); ++__i) @@ -195,7 +201,7 @@ namespace tr2 } void - _M_do_dif(const __dynamic_bitset_base& __x) + _M_do_dif(const __dynamic_bitset_base& __x) noexcept { if (__x._M_w.size() == this->_M_w.size()) for (size_t __i = 0; __i < this->_M_w.size(); ++__i) @@ -211,28 +217,27 @@ namespace tr2 _M_do_right_shift(size_t __shift); void - _M_do_flip() + _M_do_flip() noexcept { for (size_t __i = 0; __i < this->_M_w.size(); ++__i) this->_M_w[__i] = ~this->_M_w[__i]; } void - _M_do_set() + _M_do_set() noexcept { for (size_t __i = 0; __i < this->_M_w.size(); ++__i) - this->_M_w[__i] = ~static_cast(0); + this->_M_w[__i] = static_cast(-1); } void - _M_do_reset() + _M_do_reset() noexcept { - for (size_t __i = 0; __i < this->_M_w.size(); ++__i) - this->_M_w[__i] = static_cast(0); + std::fill(_M_w.begin(), _M_w.end(), static_cast(0)); } bool - _M_is_equal(const __dynamic_bitset_base& __x) const + _M_is_equal(const __dynamic_bitset_base& __x) const noexcept { if (__x._M_w.size() == this->_M_w.size()) { @@ -246,7 +251,7 @@ namespace tr2 } bool - _M_is_less(const __dynamic_bitset_base& __x) const + _M_is_less(const __dynamic_bitset_base& __x) const noexcept { if (__x._M_w.size() == this->_M_w.size()) { @@ -264,17 +269,17 @@ namespace tr2 } size_t - _M_are_all_aux() const + _M_are_all_aux() const noexcept { for (size_t __i = 0; __i < this->_M_w.size() - 1; ++__i) - if (_M_w[__i] != ~static_cast(0)) + if (_M_w[__i] != static_cast(-1)) return 0; return ((this->_M_w.size() - 1) * _S_bits_per_block + __builtin_popcountll(this->_M_hiword())); } bool - _M_is_any() const + _M_is_any() const noexcept { for (size_t __i = 0; __i < this->_M_w.size(); ++__i) if (this->_M_w[__i] != static_cast(0)) @@ -283,7 +288,7 @@ namespace tr2 } bool - _M_is_subset_of(const __dynamic_bitset_base& __b) + _M_is_subset_of(const __dynamic_bitset_base& __b) noexcept { if (__b._M_w.size() == this->_M_w.size()) { @@ -297,7 +302,7 @@ namespace tr2 } bool - _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const + _M_is_proper_subset_of(const __dynamic_bitset_base& __b) const noexcept { if (this->is_subset_of(__b)) { @@ -311,7 +316,7 @@ namespace tr2 } size_t - _M_do_count() const + _M_do_count() const noexcept { size_t __result = 0; for (size_t __i = 0; __i < this->_M_w.size(); ++__i) @@ -357,6 +362,7 @@ namespace tr2 * * See N2050, * Proposal to Add a Dynamically Sizeable Bitset to the Standard Library. + * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2050.pdf * * In the general unoptimized case, storage is allocated in * word-sized blocks. Let B be the number of bits in a word, then @@ -435,7 +441,7 @@ namespace tr2 { size_type __shift = this->_M_Nb % bits_per_block; if (__shift > 0) - this->_M_hiword() &= ~((~static_cast(0)) << __shift); + this->_M_hiword() &= block_type(~(block_type(-1) << __shift)); } // Set the unused bits in the uppermost word. @@ -444,22 +450,22 @@ namespace tr2 { size_type __shift = this->_M_Nb % bits_per_block; if (__shift > 0) - this->_M_hiword() |= ((~static_cast(0)) << __shift); + this->_M_hiword() |= block_type(block_type(-1) << __shift); } /** * These versions of single-bit set, reset, flip, and test * do no range checking. */ - dynamic_bitset<_WordT, _Alloc>& - _M_unchecked_set(size_type __pos) + dynamic_bitset& + _M_unchecked_set(size_type __pos) noexcept { this->_M_getword(__pos) |= _Base::_S_maskbit(__pos); return *this; } - dynamic_bitset<_WordT, _Alloc>& - _M_unchecked_set(size_type __pos, int __val) + dynamic_bitset& + _M_unchecked_set(size_type __pos, int __val) noexcept { if (__val) this->_M_getword(__pos) |= _Base::_S_maskbit(__pos); @@ -468,26 +474,26 @@ namespace tr2 return *this; } - dynamic_bitset<_WordT, _Alloc>& - _M_unchecked_reset(size_type __pos) + dynamic_bitset& + _M_unchecked_reset(size_type __pos) noexcept { this->_M_getword(__pos) &= ~_Base::_S_maskbit(__pos); return *this; } - dynamic_bitset<_WordT, _Alloc>& - _M_unchecked_flip(size_type __pos) + dynamic_bitset& + _M_unchecked_flip(size_type __pos) noexcept { this->_M_getword(__pos) ^= _Base::_S_maskbit(__pos); return *this; } bool - _M_unchecked_test(size_type __pos) const + _M_unchecked_test(size_type __pos) const noexcept { return ((this->_M_getword(__pos) & _Base::_S_maskbit(__pos)) != static_cast<_WordT>(0)); } - size_type _M_Nb; + size_type _M_Nb = 0; public: /** @@ -511,22 +517,16 @@ namespace tr2 block_type *_M_wp; size_type _M_bpos; - // left undefined - reference(); - public: - reference(dynamic_bitset& __b, size_type __pos) + reference(dynamic_bitset& __b, size_type __pos) noexcept { this->_M_wp = &__b._M_getword(__pos); this->_M_bpos = _Base::_S_whichbit(__pos); } - ~reference() - { } - // For b[i] = __x; reference& - operator=(bool __x) + operator=(bool __x) noexcept { if (__x) *this->_M_wp |= _Base::_S_maskbit(this->_M_bpos); @@ -537,7 +537,7 @@ namespace tr2 // For b[i] = b[__j]; reference& - operator=(const reference& __j) + operator=(const reference& __j) noexcept { if ((*(__j._M_wp) & _Base::_S_maskbit(__j._M_bpos))) *this->_M_wp |= _Base::_S_maskbit(this->_M_bpos); @@ -548,16 +548,16 @@ namespace tr2 // Flips the bit bool - operator~() const + operator~() const noexcept { return (*(_M_wp) & _Base::_S_maskbit(this->_M_bpos)) == 0; } // For __x = b[i]; - operator bool() const + operator bool() const noexcept { return (*(this->_M_wp) & _Base::_S_maskbit(this->_M_bpos)) != 0; } // For b[i].flip(); reference& - flip() + flip() noexcept { *this->_M_wp ^= _Base::_S_maskbit(this->_M_bpos); return *this; @@ -569,10 +569,14 @@ namespace tr2 typedef bool const_reference; // 23.3.5.1 constructors: + + /// All bits set to zero. + dynamic_bitset() = default; + /// All bits set to zero. explicit - dynamic_bitset(const allocator_type& __alloc = allocator_type()) - : _Base(__alloc), _M_Nb(0) + dynamic_bitset(const allocator_type& __alloc) + : _Base(__alloc) { } /// Initial bits bitwise-copied from a single word (others set to zero). @@ -585,7 +589,7 @@ namespace tr2 dynamic_bitset(initializer_list __il, const allocator_type& __alloc = allocator_type()) - : _Base(__alloc), _M_Nb(0) + : _Base(__alloc) { this->append(__il); } /** @@ -609,8 +613,7 @@ namespace tr2 __n = std::basic_string<_CharT, _Traits, _Alloc1>::npos, _CharT __zero = _CharT('0'), _CharT __one = _CharT('1'), const allocator_type& __alloc = allocator_type()) - : _Base(__alloc), - _M_Nb(0) // Watch for npos. + : _Base(__alloc) { if (__pos > __str.size()) __throw_out_of_range(__N("dynamic_bitset::bitset initial position " @@ -619,8 +622,7 @@ namespace tr2 // Watch for npos. this->_M_Nb = (__n > __str.size() ? __str.size() - __pos : __n); this->resize(this->_M_Nb); - this->_M_copy_from_string(__str, __pos, __n, - _CharT('0'), _CharT('1')); + this->_M_copy_from_string(__str, __pos, __n); } /** @@ -633,61 +635,42 @@ namespace tr2 explicit dynamic_bitset(const char* __str, const allocator_type& __alloc = allocator_type()) - : _Base(__alloc) + : _Base(__builtin_strlen(__str), 0ULL, __alloc), + _M_Nb(__builtin_strlen(__str)) { - size_t __len = 0; - if (__str) - while (__str[__len] != '\0') - ++__len; - this->resize(__len); - this->_M_copy_from_ptr> - (__str, __len, 0, __len, '0', '1'); + this->_M_copy_from_ptr(__str, _M_Nb, 0, _M_Nb); } - /** - * @brief Copy constructor. - */ - dynamic_bitset(const dynamic_bitset& __b) - : _Base(__b), _M_Nb(__b.size()) - { } + /// Copy constructor. + dynamic_bitset(const dynamic_bitset&) = default; - /** - * @brief Move constructor. - */ - dynamic_bitset(dynamic_bitset&& __b) - : _Base(std::forward<_Base>(__b)), _M_Nb(__b.size()) - { } + /// Move constructor. + dynamic_bitset(dynamic_bitset&& __b) noexcept + : _Base(std::move(__b)), _M_Nb(__b._M_Nb) + { __b.clear(); } - /** - * @brief Swap with another bitset. - */ + /// Swap with another bitset. void - swap(dynamic_bitset& __b) + swap(dynamic_bitset& __b) noexcept { this->_M_swap(__b); std::swap(this->_M_Nb, __b._M_Nb); } - /** - * @brief Assignment. - */ - dynamic_bitset& - operator=(const dynamic_bitset& __b) - { - if (&__b != this) - { - this->_M_assign(__b); - this->_M_Nb = __b._M_Nb; - } - } + /// Copy assignment operator. + dynamic_bitset& operator=(const dynamic_bitset&) = default; - /** - * @brief Move assignment. - */ + /// Move assignment operator. dynamic_bitset& operator=(dynamic_bitset&& __b) + noexcept(std::is_nothrow_move_assignable<_Base>::value) { - this->swap(__b); + static_cast<_Base&>(*this) = static_cast<_Base&&>(__b); + _M_Nb = __b._M_Nb; + if _GLIBCXX17_CONSTEXPR (std::is_nothrow_move_assignable<_Base>::value) + __b._M_Nb = 0; + else if (get_allocator() == __b.get_allocator()) + __b._M_Nb = 0; return *this; } @@ -695,7 +678,7 @@ namespace tr2 * @brief Return the allocator for the bitset. */ allocator_type - get_allocator() const + get_allocator() const noexcept { return this->_M_get_allocator(); } /** @@ -734,6 +717,8 @@ namespace tr2 ++this->_M_Nb; } + // XXX why is there no pop_back() member in the proposal? + /** * @brief Append a block. */ @@ -770,36 +755,36 @@ namespace tr2 * * These should be self-explanatory. */ - dynamic_bitset<_WordT, _Alloc>& - operator&=(const dynamic_bitset<_WordT, _Alloc>& __rhs) + dynamic_bitset& + operator&=(const dynamic_bitset& __rhs) { this->_M_do_and(__rhs); return *this; } - dynamic_bitset<_WordT, _Alloc>& - operator&=(dynamic_bitset<_WordT, _Alloc>&& __rhs) + dynamic_bitset& + operator&=(dynamic_bitset&& __rhs) { this->_M_do_and(std::move(__rhs)); return *this; } - dynamic_bitset<_WordT, _Alloc>& - operator|=(const dynamic_bitset<_WordT, _Alloc>& __rhs) + dynamic_bitset& + operator|=(const dynamic_bitset& __rhs) { this->_M_do_or(__rhs); return *this; } - dynamic_bitset<_WordT, _Alloc>& - operator^=(const dynamic_bitset<_WordT, _Alloc>& __rhs) + dynamic_bitset& + operator^=(const dynamic_bitset& __rhs) { this->_M_do_xor(__rhs); return *this; } - dynamic_bitset<_WordT, _Alloc>& - operator-=(const dynamic_bitset<_WordT, _Alloc>& __rhs) + dynamic_bitset& + operator-=(const dynamic_bitset& __rhs) { this->_M_do_dif(__rhs); return *this; @@ -813,7 +798,7 @@ namespace tr2 * * These should be self-explanatory. */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& operator<<=(size_type __pos) { if (__builtin_expect(__pos < this->_M_Nb, 1)) @@ -826,7 +811,7 @@ namespace tr2 return *this; } - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& operator>>=(size_type __pos) { if (__builtin_expect(__pos < this->_M_Nb, 1)) @@ -844,7 +829,7 @@ namespace tr2 /** * @brief Sets every bit to true. */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& set() { this->_M_do_set(); @@ -858,7 +843,7 @@ namespace tr2 * @param __val Either true or false, defaults to true. * @throw std::out_of_range If @a __pos is bigger the size of the %set. */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& set(size_type __pos, bool __val = true) { if (__pos >= _M_Nb) @@ -869,7 +854,7 @@ namespace tr2 /** * @brief Sets every bit to false. */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& reset() { this->_M_do_reset(); @@ -883,7 +868,7 @@ namespace tr2 * * Same as writing @c set(__pos, false). */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& reset(size_type __pos) { if (__pos >= _M_Nb) @@ -894,7 +879,7 @@ namespace tr2 /** * @brief Toggles every bit to its opposite value. */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& flip() { this->_M_do_flip(); @@ -907,7 +892,7 @@ namespace tr2 * @param __pos The index of the bit. * @throw std::out_of_range If @a __pos is bigger the size of the %set. */ - dynamic_bitset<_WordT, _Alloc>& + dynamic_bitset& flip(size_type __pos) { if (__pos >= _M_Nb) @@ -916,7 +901,7 @@ namespace tr2 } /// See the no-argument flip(). - dynamic_bitset<_WordT, _Alloc> + dynamic_bitset operator~() const { return dynamic_bitset<_WordT, _Alloc>(*this).flip(); } @@ -978,19 +963,23 @@ namespace tr2 } // Helper functions for string operations. - template + template, + typename _CharT = typename _Traits::char_type> void _M_copy_from_ptr(const _CharT*, size_t, size_t, size_t, - _CharT, _CharT); + _CharT __zero = _CharT('0'), + _CharT __one = _CharT('1')); template void - _M_copy_from_string(const std::basic_string<_CharT, - _Traits, _Alloc1>& __str, size_t __pos, size_t __n, + _M_copy_from_string(const basic_string<_CharT, _Traits, _Alloc1>& __str, + size_t __pos, size_t __n, _CharT __zero = _CharT('0'), _CharT __one = _CharT('1')) - { _M_copy_from_ptr<_CharT, _Traits>(__str.data(), __str.size(), - __pos, __n, __zero, __one); } + { + _M_copy_from_ptr<_Traits>(__str.data(), __str.size(), __pos, __n, + __zero, __one); + } template void @@ -1065,13 +1054,13 @@ namespace tr2 //@{ /// Self-explanatory. - dynamic_bitset<_WordT, _Alloc> + dynamic_bitset operator<<(size_type __pos) const - { return dynamic_bitset<_WordT, _Alloc>(*this) <<= __pos; } + { return dynamic_bitset(*this) <<= __pos; } - dynamic_bitset<_WordT, _Alloc> + dynamic_bitset operator>>(size_type __pos) const - { return dynamic_bitset<_WordT, _Alloc>(*this) >>= __pos; } + { return dynamic_bitset(*this) >>= __pos; } //@} /** @@ -1102,14 +1091,14 @@ namespace tr2 { return this->_M_is_proper_subset_of(__b); } friend bool - operator==(const dynamic_bitset<_WordT, _Alloc>& __lhs, - const dynamic_bitset<_WordT, _Alloc>& __rhs) - { return __lhs._M_is_equal(__rhs); } + operator==(const dynamic_bitset& __lhs, + const dynamic_bitset& __rhs) noexcept + { return __lhs._M_Nb == __rhs._M_Nb && __lhs._M_is_equal(__rhs); } friend bool - operator<(const dynamic_bitset<_WordT, _Alloc>& __lhs, - const dynamic_bitset<_WordT, _Alloc>& __rhs) - { return __lhs._M_is_less(__rhs); } + operator<(const dynamic_bitset& __lhs, + const dynamic_bitset& __rhs) noexcept + { return __lhs._M_is_less(__rhs) || __lhs._M_Nb < __rhs._M_Nb; } }; template diff --git a/libstdc++-v3/include/tr2/dynamic_bitset.tcc b/libstdc++-v3/include/tr2/dynamic_bitset.tcc index 8228d7bc472..bbd2cb3bb04 100644 --- a/libstdc++-v3/include/tr2/dynamic_bitset.tcc +++ b/libstdc++-v3/include/tr2/dynamic_bitset.tcc @@ -174,7 +174,7 @@ namespace tr2 // Definitions of non-inline member functions. template - template + template void dynamic_bitset<_WordT, _Alloc>:: _M_copy_from_ptr(const _CharT* __str, size_t __len, diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc new file mode 100644 index 00000000000..a811307c73a --- /dev/null +++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cmp.cc @@ -0,0 +1,50 @@ +// Copyright (C) 2019 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 run { target c++11 } } + +#include +#include + +void +test01() +{ + std::tr2::dynamic_bitset<> a(100); + std::tr2::dynamic_bitset<> b = a; + VERIFY( a == b ); + b.resize(99); + VERIFY( a != b ); +} + +void +test02() +{ + std::tr2::dynamic_bitset<> a(100); + std::tr2::dynamic_bitset<> b = a; + VERIFY( !(a < b) ); + VERIFY( !(b < a) ); + b.resize(99); + VERIFY( !(a < b) ); + VERIFY( b < a ); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc new file mode 100644 index 00000000000..9e21a91ff52 --- /dev/null +++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/cons.cc @@ -0,0 +1,105 @@ +// Copyright (C) 2019 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 run { target c++11 } } + +#include +#include + +void +test01() +{ + std::tr2::dynamic_bitset<> a; + VERIFY( a.size() == 0 ); + VERIFY( a.empty() ); + std::tr2::dynamic_bitset<> b(1); + VERIFY( b.size() == 1 ); + VERIFY( !b.empty() ); + VERIFY( a != b ); +} + +void +test02() +{ + std::tr2::dynamic_bitset<> a(1, 0); // { 0 } + std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 } + VERIFY( a != b ); +} + +void +test03() +{ + std::tr2::dynamic_bitset<> a; + a.resize(1); // { 0 } + std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 } + VERIFY( a != b ); +} + +void +test04() +{ + std::tr2::dynamic_bitset<> a(3, 2); // { 0, 1, 0 } + std::tr2::dynamic_bitset<> b(2, 2); // { 0, 1 } + VERIFY( a != b ); +} + +void +test05() +{ + std::tr2::dynamic_bitset a(1, 0); // { 0 } + std::tr2::dynamic_bitset b(2, 2); // { 0, 1 } + VERIFY( a != b ); +} + +void +test06() +{ + std::tr2::dynamic_bitset a; + a.resize(1); // { 0 } + std::tr2::dynamic_bitset b(2, 2); // { 0, 1 } + VERIFY( a != b ); +} + +void +test07() +{ + std::tr2::dynamic_bitset a(3, 2); // { 0, 1, 0 } + std::tr2::dynamic_bitset b(2, 2); // { 0, 1 } + VERIFY( a != b ); +} + +void +test08() +{ + std::tr2::dynamic_bitset<> a(65, -1ULL); + std::tr2::dynamic_bitset<> b(64, -1ULL); + b.push_back(0); + VERIFY( a == b ); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test08(); +} diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc new file mode 100644 index 00000000000..06bc1158a82 --- /dev/null +++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/copy.cc @@ -0,0 +1,55 @@ +// Copyright (C) 2019 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 run { target c++11 } } + +#include +#include + +void +test01() +{ + std::tr2::dynamic_bitset<> a(100); + const auto n = a.num_blocks(); + std::tr2::dynamic_bitset<> b = a; + VERIFY(b.num_blocks() == n); + VERIFY(b.size() == 100); + VERIFY(a.num_blocks() == n); + VERIFY(a.size() == 100); + VERIFY(b == a); +} + +void +test02() +{ + std::tr2::dynamic_bitset<> a(100); + const auto n = a.num_blocks(); + std::tr2::dynamic_bitset<> b; + b = a; + VERIFY(b.num_blocks() == n); + VERIFY(b.size() == 100); + VERIFY(a.num_blocks() == n); + VERIFY(a.size() == 100); + VERIFY(b == a); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc new file mode 100644 index 00000000000..ed320db300d --- /dev/null +++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/move.cc @@ -0,0 +1,53 @@ +// Copyright (C) 2019 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 run { target c++11 } } + +#include +#include + +void +test01() +{ + std::tr2::dynamic_bitset<> a(100); + const auto n = a.num_blocks(); + std::tr2::dynamic_bitset<> b = std::move(a); + VERIFY(b.num_blocks() == n); + VERIFY(b.size() == 100); + VERIFY(a.num_blocks() == 0); + VERIFY(a.size() == 0); +} + +void +test02() +{ + std::tr2::dynamic_bitset<> a(100); + const auto n = a.num_blocks(); + std::tr2::dynamic_bitset<> b; + b = std::move(a); + VERIFY(b.num_blocks() == n); + VERIFY(b.size() == 100); + VERIFY(a.num_blocks() == 0); + VERIFY(a.size() == 0); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc new file mode 100644 index 00000000000..0aec1adf65b --- /dev/null +++ b/libstdc++-v3/testsuite/tr2/dynamic_bitset/pr92059.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2019 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 run { target c++11 } } + +#include +#include + +void +test01() +{ + // PR libstdc++/92059 + std::tr2::dynamic_bitset<> b1(10000), b2(10000); + b2 = b1; // crashed on missing return + VERIFY( b2 == b1); +} + +int +main() +{ + test01(); +}