// numerous checks in the code to avoid 0 modulus.
__bucket_type _M_single_bucket = nullptr;
+ void
+ _M_update_bbegin()
+ {
+ if (_M_begin())
+ _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
+ }
+
+ void
+ _M_update_bbegin(__node_type* __n)
+ {
+ _M_before_begin._M_nxt = __n;
+ _M_update_bbegin();
+ }
+
bool
_M_uses_single_bucket(__bucket_type* __bkts) const
{ return __builtin_expect(__bkts == &_M_single_bucket, false); }
std::pair<const_iterator, const_iterator>
equal_range(const key_type& __k) const;
- protected:
+ private:
// Bucket index computation helpers.
size_type
_M_bucket_index(__node_type* __n) const noexcept
__node_type* __this_n
= __node_gen(__fwd_value_for<_Ht>(__ht_n->_M_v()));
this->_M_copy_code(__this_n, __ht_n);
- _M_before_begin._M_nxt = __this_n;
- _M_buckets[_M_bucket_index(__this_n)] = &_M_before_begin;
+ _M_update_bbegin(__this_n);
// Then deal with other nodes.
__node_base* __prev_n = __this_n;
_M_buckets = &_M_single_bucket;
_M_single_bucket = __ht._M_single_bucket;
}
+
_M_bucket_count = __ht._M_bucket_count;
_M_before_begin._M_nxt = __ht._M_before_begin._M_nxt;
_M_element_count = __ht._M_element_count;
std::__alloc_on_move(this->_M_node_allocator(), __ht._M_node_allocator());
- // Fix buckets containing the _M_before_begin pointers that can't be
- // moved.
- if (_M_begin())
- _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
+ // Fix bucket containing the _M_before_begin pointer that can't be moved.
+ _M_update_bbegin();
__ht._M_reset();
}
_M_single_bucket = __ht._M_single_bucket;
}
- // Update, if necessary, bucket pointing to before begin that hasn't
- // moved.
- if (_M_begin())
- _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
+ // Fix bucket containing the _M_before_begin pointer that can't be moved.
+ _M_update_bbegin();
__ht._M_reset();
}
else
_M_buckets = __ht._M_buckets;
- _M_before_begin._M_nxt = __ht._M_before_begin._M_nxt;
- // Update, if necessary, bucket pointing to before begin that hasn't
+ // Fix bucket containing the _M_before_begin pointer that can't be
// moved.
- if (_M_begin())
- _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
+ _M_update_bbegin(__ht._M_begin());
+
__ht._M_reset();
}
else
// Fix buckets containing the _M_before_begin pointers that can't be
// swapped.
- if (_M_begin())
- _M_buckets[_M_bucket_index(_M_begin())] = &_M_before_begin;
-
- if (__x._M_begin())
- __x._M_buckets[__x._M_bucket_index(__x._M_begin())]
- = &__x._M_before_begin;
+ _M_update_bbegin();
+ __x._M_update_bbegin();
}
template<typename _Key, typename _Value,
{
__hash_code __code = this->_M_hash_code(__k);
std::size_t __bkt = _M_bucket_index(__k, __code);
- __node_type* __p = _M_find_node(__bkt, __k, __code);
- return __p ? iterator(__p) : end();
+ return iterator(_M_find_node(__bkt, __k, __code));
}
template<typename _Key, typename _Value,
{
__hash_code __code = this->_M_hash_code(__k);
std::size_t __bkt = _M_bucket_index(__k, __code);
- __node_type* __p = _M_find_node(__bkt, __k, __code);
- return __p ? const_iterator(__p) : end();
+ return const_iterator(_M_find_node(__bkt, __k, __code));
}
template<typename _Key, typename _Value,
count(const key_type& __k) const
-> size_type
{
- __hash_code __code = this->_M_hash_code(__k);
- std::size_t __bkt = _M_bucket_index(__k, __code);
- __node_type* __p = _M_bucket_begin(__bkt);
- if (!__p)
+ auto __it = find(__k);
+ if (!__it._M_cur)
return 0;
- std::size_t __result = 0;
- for (;; __p = __p->_M_next())
- {
- if (this->_M_equals(__k, __code, __p))
- ++__result;
- else if (__result)
- // All equivalent values are next to each other, if we
- // found a non-equivalent value after an equivalent one it
- // means that we won't find any new equivalent value.
- break;
- if (!__p->_M_nxt || _M_bucket_index(__p->_M_next()) != __bkt)
- break;
- }
+ if (__unique_keys::value)
+ return 1;
+
+ // All equivalent values are next to each other, if we find a
+ // non-equivalent value after an equivalent one it means that we won't
+ // find any new equivalent value.
+ size_type __result = 1;
+ for (auto __ref = __it++;
+ __it._M_cur && this->_M_node_equals(__ref._M_cur, __it._M_cur);
+ ++__it)
+ ++__result;
+
return __result;
}
equal_range(const key_type& __k)
-> pair<iterator, iterator>
{
- __hash_code __code = this->_M_hash_code(__k);
- std::size_t __bkt = _M_bucket_index(__k, __code);
- __node_type* __p = _M_find_node(__bkt, __k, __code);
+ auto __ite = find(__k);
+ if (!__ite._M_cur)
+ return { __ite, __ite };
- if (__p)
- {
- __node_type* __p1 = __p->_M_next();
- while (__p1 && _M_bucket_index(__p1) == __bkt
- && this->_M_equals(__k, __code, __p1))
- __p1 = __p1->_M_next();
+ auto __beg = __ite++;
+ if (__unique_keys::value)
+ return { __beg, __ite };
- return std::make_pair(iterator(__p), iterator(__p1));
- }
- else
- return std::make_pair(end(), end());
+ // All equivalent values are next to each other, if we find a
+ // non-equivalent value after an equivalent one it means that we won't
+ // find any new equivalent value.
+ while (__ite._M_cur && this->_M_node_equals(__beg._M_cur, __ite._M_cur))
+ ++__ite;
+
+ return { __beg, __ite };
}
template<typename _Key, typename _Value,
equal_range(const key_type& __k) const
-> pair<const_iterator, const_iterator>
{
- __hash_code __code = this->_M_hash_code(__k);
- std::size_t __bkt = _M_bucket_index(__k, __code);
- __node_type* __p = _M_find_node(__bkt, __k, __code);
+ auto __ite = find(__k);
+ if (!__ite._M_cur)
+ return { __ite, __ite };
- if (__p)
- {
- __node_type* __p1 = __p->_M_next();
- while (__p1 && _M_bucket_index(__p1) == __bkt
- && this->_M_equals(__k, __code, __p1))
- __p1 = __p1->_M_next();
+ auto __beg = __ite++;
+ if (__unique_keys::value)
+ return { __beg, __ite };
- return std::make_pair(const_iterator(__p), const_iterator(__p1));
- }
- else
- return std::make_pair(end(), end());
+ // All equivalent values are next to each other, if we find a
+ // non-equivalent value after an equivalent one it means that we won't
+ // find any new equivalent value.
+ while (__ite._M_cur && this->_M_node_equals(__beg._M_cur, __ite._M_cur))
+ ++__ite;
+
+ return { __beg, __ite };
}
- // Find the node whose key compares equal to k in the bucket bkt.
- // Return nullptr if no node is found.
+ // Find the node before the one whose key compares equal to k in the bucket
+ // bkt. Return nullptr if no node is found.
template<typename _Key, typename _Value,
typename _Alloc, typename _ExtractKey, typename _Equal,
typename _H1, typename _H2, typename _Hash, typename _RehashPolicy,
break;
__prev_p = __p;
}
+
return nullptr;
}
// contain _M_before_begin pointer.
__node->_M_nxt = _M_before_begin._M_nxt;
_M_before_begin._M_nxt = __node;
+
if (__node->_M_nxt)
// We must update former begin bucket that is pointing to
// _M_before_begin.
_M_buckets[_M_bucket_index(__node->_M_next())] = __node;
+
_M_buckets[__bkt] = &_M_before_begin;
}
}
// them so that the key stays valid during the first loop. It might be
// invalidated indirectly when destroying nodes.
__node_type* __n = static_cast<__node_type*>(__prev_n->_M_nxt);
- __node_type* __n_last = __n;
- std::size_t __n_last_bkt = __bkt;
- do
- {
- __n_last = __n_last->_M_next();
- if (!__n_last)
- break;
- __n_last_bkt = _M_bucket_index(__n_last);
- }
- while (__n_last_bkt == __bkt && this->_M_equals(__k, __code, __n_last));
+ __node_type* __n_last = __n->_M_next();
+ while (__n_last && this->_M_node_equals(__n, __n_last))
+ __n_last = __n_last->_M_next();
+
+ std::size_t __n_last_bkt = __n_last ? _M_bucket_index(__n_last) : __bkt;
// Deallocate nodes.
size_type __result = 0;
this->_M_deallocate_node(__n);
__n = __p;
++__result;
- --_M_element_count;
}
while (__n != __n_last);
+ _M_element_count -= __result;
if (__prev_n == _M_buckets[__bkt])
_M_remove_bucket_begin(__bkt, __n_last, __n_last_bkt);
- else if (__n_last && __n_last_bkt != __bkt)
+ else if (__n_last_bkt != __bkt)
_M_buckets[__n_last_bkt] = __prev_n;
__prev_n->_M_nxt = __n_last;
return __result;
__p->_M_nxt = __new_buckets[__bkt]->_M_nxt;
__new_buckets[__bkt]->_M_nxt = __p;
}
+
__p = __next;
}
-> mapped_type&
{
__hashtable* __h = static_cast<__hashtable*>(this);
- __hash_code __code = __h->_M_hash_code(__k);
- std::size_t __bkt = __h->_M_bucket_index(__k, __code);
- __node_type* __p = __h->_M_find_node(__bkt, __k, __code);
+ auto __ite = __h->find(__k);
- if (!__p)
+ if (!__ite._M_cur)
__throw_out_of_range(__N("_Map_base::at"));
- return __p->_M_v().second;
+ return __ite->second;
}
template<typename _Key, typename _Pair, typename _Alloc, typename _Equal,
-> const mapped_type&
{
const __hashtable* __h = static_cast<const __hashtable*>(this);
- __hash_code __code = __h->_M_hash_code(__k);
- std::size_t __bkt = __h->_M_bucket_index(__k, __code);
- __node_type* __p = __h->_M_find_node(__bkt, __k, __code);
+ auto __ite = __h->find(__k);
- if (!__p)
+ if (!__ite._M_cur)
__throw_out_of_range(__N("_Map_base::at"));
- return __p->_M_v().second;
+ return __ite->second;
}
/**
template<typename _NodeT>
struct _Equal_hash_code
{
- static bool
- _S_equals(__hash_code, const _NodeT&)
- { return true; }
+ static bool
+ _S_equals(__hash_code, const _NodeT&)
+ { return true; }
+
+ static bool
+ _S_node_equals(const _NodeT&, const _NodeT&)
+ { return true; }
};
template<typename _Ptr2>
struct _Equal_hash_code<_Hash_node<_Ptr2, true>>
{
- static bool
- _S_equals(__hash_code __c, const _Hash_node<_Ptr2, true>& __n)
- { return __c == __n._M_hash_code; }
+ static bool
+ _S_equals(__hash_code __c, const _Hash_node<_Ptr2, true>& __n)
+ { return __c == __n._M_hash_code; }
+
+ static bool
+ _S_node_equals(const _Hash_node<_Ptr2, true>& __lhn,
+ const _Hash_node<_Ptr2, true>& __rhn)
+ { return __lhn._M_hash_code == __rhn._M_hash_code; }
};
protected:
{ }
bool
- _M_equals(const _Key& __k, __hash_code __c, __node_type* __n) const
+ _M_equals(const _Key& __k, __hash_code __c, const __node_type* __n) const
{
static_assert(__is_invocable<const _Equal&, const _Key&, const _Key&>{},
"key equality predicate must be invocable with two arguments of "
&& _M_eq()(__k, this->_M_extract()(__n->_M_v()));
}
+ bool
+ _M_node_equals(const __node_type* __lhn, const __node_type* __rhn) const
+ {
+ return _Equal_hash_code<__node_type>::_S_node_equals(*__lhn, *__rhn)
+ && _M_eq()(this->_M_extract()(__lhn->_M_v()),
+ this->_M_extract()(__rhn->_M_v()));
+ }
+
void
_M_swap(_Hashtable_base& __x)
{
return false;
__node_type* __y_n = static_cast<__node_type*>(__y_prev_n->_M_nxt);
- for (;; __y_n = __y_n->_M_next())
+ for (;;)
{
if (__this->key_eq()(_ExtractKey()(__y_n->_M_v()),
_ExtractKey()(*__itx)))
break;
- if (!__y_n->_M_nxt
- || __other._M_bucket_index(__y_n->_M_next()) != __ybkt)
+ __node_type* __y_ref_n = __y_n;
+ for (__y_n = __y_n->_M_next(); __y_n; __y_n = __y_n->_M_next())
+ if (!__other._M_node_equals(__y_ref_n, __y_n))
+ break;
+
+ if (!__y_n || __other._M_bucket_index(__y_n) != __ybkt)
return false;
}