François
52446.patch
Index: include/bits/hashtable.h
===================================================================
--- include/bits/hashtable.h (revision 185352)
+++ include/bits/hashtable.h (working copy)
@@ -596,6 +596,11 @@
// reserve, if present, comes from _Rehash_base.
private:
+ // Rehash method when keys are unique
+ void _M_rehash(size_type __n, std::true_type);
+ // Rehash method when there might be equivalent keys.
+ void _M_rehash(size_type __n, std::false_type);
+
// Unconditionally change size of bucket array to n, restore hash policy
// state to __state on exception.
void _M_rehash(size_type __n, const _RehashPolicyState& __state);
@@ -1592,41 +1597,141 @@
{
__try
{
- _Bucket* __new_buckets = _M_allocate_buckets(__n);
- _Node* __p = _M_begin();
- _M_before_begin._M_nxt = nullptr;
- std::size_t __cur_bbegin_bkt;
- while (__p)
+ _M_rehash(__n, integral_constant<bool, __uk>());
+ }
+ __catch(...)
+ {
+ // A failure here means that buckets allocation failed. We only
+ // have to restore hash policy previous state.
+ _M_rehash_policy._M_reset(__state);
+ __throw_exception_again;
+ }
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Allocator, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ bool __chc, bool __cit, bool __uk>
+ void
+ _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
+ _M_rehash(size_type __n, std::true_type)
+ {
+ // This version of rehash do not have to care about equivalent elements
+ // relative order.
+ _Bucket* __new_buckets = _M_allocate_buckets(__n);
+ _Node* __p = _M_begin();
+ _M_before_begin._M_nxt = nullptr;
+ std::size_t __cur_bbegin_bkt;
+ while (__p)
+ {
+ _Node* __next = __p->_M_next();
+ std::size_t __new_index = _HCBase::_M_bucket_index(__p, __n);
+ if (!__new_buckets[__new_index])
{
- _Node* __next = __p->_M_next();
- std::size_t __new_index = _HCBase::_M_bucket_index(__p, __n);
- if (!__new_buckets[__new_index])
+ __p->_M_nxt = _M_before_begin._M_nxt;
+ _M_before_begin._M_nxt = __p;
+ __new_buckets[__new_index] =&_M_before_begin;
+ if (__p->_M_nxt)
+ __new_buckets[__cur_bbegin_bkt] = __p;
+ __cur_bbegin_bkt = __new_index;
+ }
+ else
+ {
+ __p->_M_nxt = __new_buckets[__new_index]->_M_nxt;
+ __new_buckets[__new_index]->_M_nxt = __p;
+ }
+ __p = __next;
+ }
+ _M_deallocate_buckets(_M_buckets, _M_bucket_count);
+ _M_bucket_count = __n;
+ _M_buckets = __new_buckets;
+ }
+
+ template<typename _Key, typename _Value,
+ typename _Allocator, typename _ExtractKey, typename _Equal,
+ typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
+ bool __chc, bool __cit, bool __uk>
+ void
+ _Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal,
+ _H1, _H2, _Hash, _RehashPolicy, __chc, __cit, __uk>::
+ _M_rehash(size_type __n, std::false_type)
+ {
+ // This version of rehash must guaranty that equivalent elements relative
+ // order is preserve.
+ _Bucket* __new_buckets = _M_allocate_buckets(__n);
+ _Node* __p = _M_begin();
+ _M_before_begin._M_nxt = nullptr;
+ std::size_t __cur_bbegin_bkt;
+ std::size_t __prev_index;
+ _Node* __prev_p = nullptr;
+ bool __check_next_bucket = false;
+ while (__p)
+ {
+ bool __check_now = true;
+ _Node* __next = __p->_M_next();
+ std::size_t __new_index = _HCBase::_M_bucket_index(__p, __n);
+ if (!__new_buckets[__new_index])
+ {
+ __p->_M_nxt = _M_before_begin._M_nxt;
+ _M_before_begin._M_nxt = __p;
+ __new_buckets[__new_index] =&_M_before_begin;
+ if (__p->_M_nxt)
+ __new_buckets[__cur_bbegin_bkt] = __p;
+ __cur_bbegin_bkt = __new_index;
+ }
+ else
+ {
+ if (__prev_p&& __prev_index == __new_index)
{
- __p->_M_nxt = _M_before_begin._M_nxt;
- _M_before_begin._M_nxt = __p;
- __new_buckets[__new_index] =&_M_before_begin;
- if (__p->_M_nxt)
- __new_buckets[__cur_bbegin_bkt] = __p;
- __cur_bbegin_bkt = __new_index;
+ // 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;