]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
re PR libstdc++/53115 (_Hashtable::_M_rehash_aux(false_type) is broken)
authorFrançois Dumont <fdumont@gcc.gnu.org>
Tue, 1 May 2012 20:29:16 +0000 (20:29 +0000)
committerFrançois Dumont <fdumont@gcc.gnu.org>
Tue, 1 May 2012 20:29:16 +0000 (20:29 +0000)
2012-05-01  François Dumont  <fdumont@gcc.gnu.org>

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

libstdc++-v3/ChangeLog
libstdc++-v3/include/bits/hashtable.h
libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/53115.cc [new file with mode: 0644]
libstdc++-v3/testsuite/23_containers/unordered_multiset/insert/53115.cc [new file with mode: 0644]

index 99be46799d29c29ebdbf9bd5e175b8929fc6e18b..f8f37a8efd70791069e0c09b7508cb6a4e720352 100644 (file)
@@ -1,3 +1,12 @@
+2012-05-01  François Dumont  <fdumont@gcc.gnu.org>
+
+       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  <marc.glisse@inria.fr>
            Paolo Carlini  <paolo.carlini@oracle.com>
 
index 5adc7ca98bbf68563c479028ed71697c5fea1853..9a795494916964771317332e05f9b9bc60b198c6 100644 (file)
@@ -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 (file)
index 0000000..4eb5d42
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_map>
+#include <testsuite_hooks.h>
+
+namespace
+{
+  std::size_t
+  get_nb_bucket_elems(const std::unordered_multimap<int, int>& 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<int, int> 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 (file)
index 0000000..a23eacb
--- /dev/null
@@ -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
+// <http://www.gnu.org/licenses/>.
+
+#include <unordered_set>
+#include <testsuite_hooks.h>
+
+namespace
+{
+  std::size_t
+  get_nb_bucket_elems(const std::unordered_multiset<int>& 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<int> 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;
+}