]> rtime.felk.cvut.cz Git - l4.git/blobdiff - l4/pkg/libstdc++-v3/contrib/libstdc++-v3-4.7/include/bits/hashtable.h
update
[l4.git] / l4 / pkg / libstdc++-v3 / contrib / libstdc++-v3-4.7 / include / bits / hashtable.h
index 41418a8a509465547a0f7d32d99c63cd54e46492..c7a8be055637b861d0ffc0fb0cdf8aa11abc4910 100644 (file)
@@ -1,6 +1,7 @@
 // hashtable.h header -*- C++ -*-
 
-// Copyright (C) 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+// Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013
+// 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
@@ -98,43 +99,44 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * - size_type       _M_bucket_count
    * - size_type       _M_element_count
    *
-   * with _Bucket being _Hash_node* and _Hash_node constaining:
+   * with _Bucket being _Hash_node* and _Hash_node containing:
    * - _Hash_node*   _M_next
    * - Tp            _M_value
-   * - size_t        _M_code if cache_hash_code is true
+   * - size_t        _M_hash_code if cache_hash_code is true
    *
-   * In terms of Standard containers the hastable is like the aggregation of:
+   * In terms of Standard containers the hashtable is like the aggregation of:
    * - std::forward_list<_Node> containing the elements
    * - std::vector<std::forward_list<_Node>::iterator> representing the buckets
    *
-   * The non-empty buckets contain the node before the first bucket node. This
-   * design allow to implement something like a std::forward_list::insert_after
-   * on container insertion and std::forward_list::erase_after on container
-   * erase calls. _M_before_begin is equivalent to
-   * std::foward_list::before_begin. Empty buckets are containing nullptr.
-   * Note that one of the non-empty bucket contains &_M_before_begin which is
-   * not a derefenrenceable node so the node pointers in buckets shall never be
-   * derefenrenced, only its next node can be.
+   * The non-empty buckets contain the node before the first node in the
+   * bucket. This design makes it possible to implement something like a
+   * std::forward_list::insert_after on container insertion and
+   * std::forward_list::erase_after on container erase calls.
+   * _M_before_begin is equivalent to std::foward_list::before_begin.
+   * Empty buckets contain nullptr.
+   * Note that one of the non-empty buckets contains &_M_before_begin which is
+   * not a dereferenceable node so the node pointer in a bucket shall never be
+   * dereferenced, only its next node can be.
    * 
-   * Walk through a bucket nodes require a check on the hash code to see if the
-   * node is still in the bucket. Such a design impose a quite efficient hash
-   * functor and is one of the reasons it is highly advise to set
-   * __cache_hash_code to true.
+   * Walking through a bucket's nodes requires a check on the hash code to see
+   * if each node is still in the bucket. Such a design assumes a quite
+   * efficient hash functor and is one of the reasons it is
+   * highly advisable to set __cache_hash_code to true.
    *
    * The container iterators are simply built from nodes. This way incrementing
    * the iterator is perfectly efficient independent of how many empty buckets
    * there are in the container.
    *
-   * On insert we compute element hash code and thanks to it find the bucket
-   * index. If the element must be inserted on an empty bucket we add it at the
-   * beginning of the singly linked list and make the bucket point to
+   * On insert we compute the element's hash code and use it to it find the
+   * bucket index. If the element must be inserted in an empty bucket we add
+   * it at the beginning of the singly linked list and make the bucket point to
    * _M_before_begin. The bucket that used to point to _M_before_begin, if any,
    * is updated to point to its new before begin node.
    *
-   * On erase, the simple iterator design impose to use the hash functor to get
-   * the index of the bucket to update. For this reason, when __cache_hash_code
-   * is set to false, there is a static assertion that the hash functor cannot
-   * throw.
+   * On erase, the simple iterator design requires using the hash functor to
+   * get the index of the bucket to update. For this reason, when
+   * __cache_hash_code is set to false, the hash functor must not throw
+   * and this is enforced by a statied assertion.
    */
 
   template<typename _Key, typename _Value, typename _Allocator,
@@ -549,8 +551,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename _Pair, typename = typename
        std::enable_if<__and_<integral_constant<bool, !__constant_iterators>,
-                             std::is_convertible<_Pair,
-                                                 value_type>>::value>::type>
+                             std::is_constructible<value_type,
+                                                   _Pair&&>>::value>::type>
        _Insert_Return_Type
        insert(_Pair&& __v)
        { return _M_insert(std::forward<_Pair>(__v),
@@ -558,8 +560,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       template<typename _Pair, typename = typename
         std::enable_if<__and_<integral_constant<bool, !__constant_iterators>,
-                             std::is_convertible<_Pair,
-                                                 value_type>>::value>::type>
+                             std::is_constructible<value_type,
+                                                   _Pair&&>>::value>::type>
        iterator
        insert(const_iterator, _Pair&& __v)
        { return _Insert_Conv_Type()(insert(std::forward<_Pair>(__v))); }
@@ -759,11 +761,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        _M_element_count(0),
        _M_rehash_policy()
       {
-       _M_bucket_count = std::max(_M_rehash_policy._M_next_bkt(__bucket_hint),
-                                  _M_rehash_policy.
-                                  _M_bkt_for_elements(__detail::
-                                                      __distance_fw(__f,
-                                                                    __l)));
+       _M_bucket_count =
+         _M_rehash_policy._M_bkt_for_elements(__detail::__distance_fw(__f,
+                                                                      __l));
+       if (_M_bucket_count <= __bucket_hint)
+         _M_bucket_count = _M_rehash_policy._M_next_bkt(__bucket_hint);
+
         // We don't want the rehash policy to ask for the hashtable to shrink
         // on the first insertion so we need to reset its previous resize
        // level.
@@ -980,7 +983,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
          else if (__result)
            // All equivalent values are next to each other, if we found a not
            // equivalent value after an equivalent one it means that we won't
-           // find anymore an equivalent value.
+           // find any more equivalent values.
            break;
          if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __n)
            break;
@@ -1102,7 +1105,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       else
        {
          // The bucket is empty, the new node is inserted at the beginning of
-         // the singly linked list and the bucket will contain _M_before_begin
+         // the singly-linked list and the bucket will contain _M_before_begin
          // pointer.
          __new_node->_M_nxt = _M_before_begin._M_nxt;
          _M_before_begin._M_nxt = __new_node;
@@ -1250,7 +1253,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            else
              // The inserted node has no equivalent in the hashtable. We must
              // insert the new node at the beginning of the bucket to preserve
-             // equivalent elements relative positions.
+             // equivalent elements' relative positions.
              _M_insert_bucket_begin(__bkt, __new_node);
            ++_M_element_count;
            return iterator(__new_node);
@@ -1432,7 +1435,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       std::size_t __bkt = _M_bucket_index(__n);
 
       // Look for previous node to unlink it from the erased one, this is why
-      // we need buckets to contain the before begin to make this research fast.
+      // we need buckets to contain the before begin to make this search fast.
       _BaseNode* __prev_n = _M_get_previous_node(__bkt, __n);
       if (__n == _M_bucket_begin(__bkt))
        _M_remove_bucket_begin(__bkt, __n->_M_next(),
@@ -1581,10 +1584,23 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     rehash(size_type __n)
     {
       const _RehashPolicyState& __saved_state = _M_rehash_policy._M_state();
-      _M_rehash(std::max(_M_rehash_policy._M_next_bkt(__n),
-                        _M_rehash_policy._M_bkt_for_elements(_M_element_count
-                                                             + 1)),
-               __saved_state);
+      std::size_t __buckets
+       = _M_rehash_policy._M_bkt_for_elements(_M_element_count + 1);
+      if (__buckets <= __n)
+       __buckets = _M_rehash_policy._M_next_bkt(__n);
+
+      if (__buckets != _M_bucket_count)
+       {
+         _M_rehash(__buckets, __saved_state);
+         
+         // We don't want the rehash policy to ask for the hashtable to shrink
+         // on the next insertion so we need to reset its previous resize
+         // level.
+         _M_rehash_policy._M_prev_resize = 0;
+       }
+      else
+       // No rehash, restore previous state to keep a consistent state.
+       _M_rehash_policy._M_reset(__saved_state);
     }
 
   template<typename _Key, typename _Value,
@@ -1622,7 +1638,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       _Bucket* __new_buckets = _M_allocate_buckets(__n);
       _Node* __p = _M_begin();
       _M_before_begin._M_nxt = nullptr;
-      std::size_t __bbegin_bkt;
+      std::size_t __bbegin_bkt = 0;
       while (__p)
        {
          _Node* __next = __p->_M_next();
@@ -1663,43 +1679,54 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 
       _Node* __p = _M_begin();
       _M_before_begin._M_nxt = nullptr;
-      std::size_t __bbegin_bkt;
-      std::size_t __prev_bkt;
+      std::size_t __bbegin_bkt = 0;
+      std::size_t __prev_bkt = 0;
       _Node* __prev_p = nullptr;
       bool __check_bucket = false;
 
       while (__p)
        {
-         bool __check_now = true;
          _Node* __next = __p->_M_next();
          std::size_t __bkt = _HCBase::_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
+                       = _HCBase::_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
                {
@@ -1707,20 +1734,7 @@ _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
-                   = _HCBase::_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;