From: François Dumont Date: Tue, 1 May 2012 20:29:16 +0000 (+0000) Subject: re PR libstdc++/53115 (_Hashtable::_M_rehash_aux(false_type) is broken) X-Git-Tag: misc/gccgo-go1_1_2~3166 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=b7a9facb2c4308b738b0785a291ae31f02d30b76;p=thirdparty%2Fgcc.git re PR libstdc++/53115 (_Hashtable::_M_rehash_aux(false_type) is broken) 2012-05-01 François Dumont PR libstdc++/53115 * include/bits/hashtable.h (_Hashtable<>::_M_rehash_aux(size_type, false_type)): Fix buckets after insertion of several equivalent elements. * testsuite/23_containers/unordered_multiset/insert/53115.cc: New. * testsuite/23_containers/unordered_multimap/insert/53115.cc: New. From-SVN: r187025 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 99be46799d29..f8f37a8efd70 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,12 @@ +2012-05-01 François Dumont + + PR libstdc++/53115 + * include/bits/hashtable.h + (_Hashtable<>::_M_rehash_aux(size_type, false_type)): Fix buckets + after insertion of several equivalent elements. + * testsuite/23_containers/unordered_multiset/insert/53115.cc: New. + * testsuite/23_containers/unordered_multimap/insert/53115.cc: New. + 2012-04-29 Marc Glisse Paolo Carlini diff --git a/libstdc++-v3/include/bits/hashtable.h b/libstdc++-v3/include/bits/hashtable.h index 5adc7ca98bbf..9a7954949169 100644 --- a/libstdc++-v3/include/bits/hashtable.h +++ b/libstdc++-v3/include/bits/hashtable.h @@ -1698,36 +1698,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION while (__p) { - bool __check_now = true; __node_type* __next = __p->_M_next(); std::size_t __bkt = __hash_code_base::_M_bucket_index(__p, __n); - if (!__new_buckets[__bkt]) + if (__prev_p && __prev_bkt == __bkt) { - __p->_M_nxt = _M_before_begin._M_nxt; - _M_before_begin._M_nxt = __p; - __new_buckets[__bkt] = &_M_before_begin; - if (__p->_M_nxt) - __new_buckets[__bbegin_bkt] = __p; - __bbegin_bkt = __bkt; + // Previous insert was already in this bucket, we insert after + // the previously inserted one to preserve equivalent elements + // relative order. + __p->_M_nxt = __prev_p->_M_nxt; + __prev_p->_M_nxt = __p; + + // Inserting after a node in a bucket require to check that we + // haven't change the bucket last node, in this case next + // bucket containing its before begin node must be updated. We + // schedule a check as soon as we move out of the sequence of + // equivalent nodes to limit the number of checks. + __check_bucket = true; } else { - if (__prev_p && __prev_bkt == __bkt) + if (__check_bucket) { - // Previous insert was already in this bucket, we insert after - // the previously inserted one to preserve equivalent elements - // relative order. - __p->_M_nxt = __prev_p->_M_nxt; - __prev_p->_M_nxt = __p; - - // Inserting after a node in a bucket require to check that we - // haven't change the bucket last node, in this case next - // bucket containing its before begin node must be updated. We - // schedule a check as soon as we move out of the sequence of - // equivalent nodes to limit the number of checks. - __check_bucket = true; - __check_now = false; + // Check if we shall update the next bucket because of insertions + // into __prev_bkt bucket. + if (__prev_p->_M_nxt) + { + std::size_t __next_bkt + = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), + __n); + if (__next_bkt != __prev_bkt) + __new_buckets[__next_bkt] = __prev_p; + } + __check_bucket = false; + } + + if (!__new_buckets[__bkt]) + { + __p->_M_nxt = _M_before_begin._M_nxt; + _M_before_begin._M_nxt = __p; + __new_buckets[__bkt] = &_M_before_begin; + if (__p->_M_nxt) + __new_buckets[__bbegin_bkt] = __p; + __bbegin_bkt = __bkt; } else { @@ -1735,21 +1748,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __new_buckets[__bkt]->_M_nxt = __p; } } - - if (__check_now && __check_bucket) - { - // Check if we shall update the next bucket because of insertions - // into __prev_bkt bucket. - if (__prev_p->_M_nxt) - { - std::size_t __next_bkt - = __hash_code_base::_M_bucket_index(__prev_p->_M_next(), - __n); - if (__next_bkt != __prev_bkt) - __new_buckets[__next_bkt] = __prev_p; - } - __check_bucket = false; - } __prev_p = __p; __prev_bkt = __bkt; __p = __next; diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/53115.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/53115.cc new file mode 100644 index 000000000000..4eb5d4261975 --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/53115.cc @@ -0,0 +1,101 @@ +// { dg-options "-std=gnu++11" } +// +// Copyright (C) 2012 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 +// . + +#include +#include + +namespace +{ + std::size_t + get_nb_bucket_elems(const std::unordered_multimap& us) + { + std::size_t nb = 0; + for (std::size_t b = 0; b != us.bucket_count(); ++b) + nb += us.bucket_size(b); + return nb; + } +} + +void test01() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + std::unordered_multimap umm; + umm.insert(make_pair(10, 1)); + VERIFY( umm.size() == 1 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(10, 2)); + VERIFY( umm.size() == 2 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(10, 3)); + VERIFY( umm.size() == 3 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(10, 4)); + VERIFY( umm.size() == 4 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(10, 5)); + VERIFY( umm.size() == 5 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(24, 6)); + VERIFY( umm.size() == 6 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(25, 7)); + VERIFY( umm.size() == 7 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(2, 8)); + VERIFY( umm.size() == 8 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(2, 9)); + VERIFY( umm.size() == 9 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(1, 10)); + VERIFY( umm.size() == 10 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); + + umm.insert(make_pair(10, 11)); + VERIFY( umm.size() == 11 ); + VERIFY( std::distance(umm.begin(), umm.end()) == umm.size() ); + VERIFY( get_nb_bucket_elems(umm) == umm.size() ); +} + +int main() +{ + test01(); + return 0; +} diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multiset/insert/53115.cc b/libstdc++-v3/testsuite/23_containers/unordered_multiset/insert/53115.cc new file mode 100644 index 000000000000..a23eacb753fc --- /dev/null +++ b/libstdc++-v3/testsuite/23_containers/unordered_multiset/insert/53115.cc @@ -0,0 +1,101 @@ +// { dg-options "-std=gnu++11" } +// +// Copyright (C) 2012 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 +// . + +#include +#include + +namespace +{ + std::size_t + get_nb_bucket_elems(const std::unordered_multiset& us) + { + std::size_t nb = 0; + for (std::size_t b = 0; b != us.bucket_count(); ++b) + nb += us.bucket_size(b); + return nb; + } +} + +void test01() +{ + using namespace std; + bool test __attribute__((unused)) = true; + + std::unordered_multiset mms; + mms.insert(10); + VERIFY( mms.size() == 1 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(10); + VERIFY( mms.size() == 2 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(10); + VERIFY( mms.size() == 3 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(10); + VERIFY( mms.size() == 4 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(10); + VERIFY( mms.size() == 5 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(24); + VERIFY( mms.size() == 6 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(25); + VERIFY( mms.size() == 7 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(2); + VERIFY( mms.size() == 8 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(2); + VERIFY( mms.size() == 9 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(1); + VERIFY( mms.size() == 10 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); + + mms.insert(10); + VERIFY( mms.size() == 11 ); + VERIFY( std::distance(mms.begin(), mms.end()) == mms.size() ); + VERIFY( get_nb_bucket_elems(mms) == mms.size() ); +} + +int main() +{ + test01(); + return 0; +}