1#ifndef CLICK_HASHCONTAINER_HH
2#define CLICK_HASHCONTAINER_HH
3#include <click/glue.hh>
4#include <click/hashcode.hh>
5#include <click/libdivide.h>
7# define click_hash_assert(x) assert(x)
9# define click_hash_assert(x)
13template <
typename T>
class HashContainer_adapter;
16template <
typename T,
typename A = HashContainer_adapter<T> >
class HashContainer;
19template <
typename T,
typename A>
20class HashContainer_rep :
public A {
23 mutable uint32_t first_bucket;
25 libdivide_u32_t bucket_divider;
26#if defined(CLICK_HASH_ITERATOR_EPOCHS)
36class HashContainer_adapter {
public:
37 typedef typename T::key_type key_type;
38 typedef typename T::key_const_reference key_const_reference;
39 static T *&hashnext(T *e) {
42 static key_const_reference hashkey(
const T *e) {
45 static bool hashkeyeq(
const key_type &a,
const key_type &b) {
84template <
typename T,
typename A>
103 max_bucket_count = 4194303,
107 initial_bucket_count = 63
127 return _rep.size == 0;
132 return _rep.nbuckets;
137 click_hash_assert(n < _rep.nbuckets);
139 for (T *element = _rep.buckets[n]; element; element = _rep.hashnext(element))
149 return _rep.size > 2 * _rep.nbuckets && _rep.nbuckets < max_bucket_count;
160 inline const_iterator
begin()
const;
166 inline const_iterator
end()
const;
252 inline T *
set(T *element);
292 HashContainer_rep<T, A> _rep;
304template <
typename T,
typename A>
316#if defined(CLICK_HASH_ITERATOR_EPOCHS)
317 assert(!_element || _hc->_rep.epoch == _epoch);
324#if defined(CLICK_HASH_ITERATOR_EPOCHS)
325 assert(!_element || _hc->_rep.epoch == _epoch);
333#if defined(CLICK_HASH_ITERATOR_EPOCHS)
334 assert(!_element || _hc->_rep.epoch == _epoch);
341#if defined(CLICK_HASH_ITERATOR_EPOCHS)
342 assert(!_element || _hc->_rep.epoch == _epoch);
349 inline operator unspecified_bool_type()
const {
350#if defined(CLICK_HASH_ITERATOR_EPOCHS)
351 assert(!_element || _hc->_rep.epoch == _epoch);
368#if defined(CLICK_HASH_ITERATOR_EPOCHS)
369 assert(!_element || _hc->_rep.epoch == _epoch);
371 if (_element && _hc->_rep.hashnext(_element)) {
372 _pprev = &_hc->_rep.hashnext(_element);
374 }
else if (_bucket != _hc->_rep.nbuckets) {
375 for (++_bucket; _bucket != _hc->_rep.nbuckets; ++_bucket)
376 if (*(_pprev = &_hc->_rep.buckets[_bucket])) {
393 bucket_count_type _bucket;
395#if defined(CLICK_HASH_ITERATOR_EPOCHS)
401 _bucket = hc->_rep.first_bucket;
402 _pprev = &hc->_rep.buckets[_bucket];
403#if defined(CLICK_HASH_ITERATOR_EPOCHS)
404 _epoch = hc->_rep.epoch;
406 if (unlikely(_bucket == hc->_rep.nbuckets))
408 else if (!(_element = *_pprev)) {
410 hc->_rep.first_bucket = _bucket;
415 : _element(element), _pprev(pprev), _bucket(b), _hc(hc)
416#if defined(CLICK_HASH_ITERATOR_EPOCHS)
417 , _epoch(hc->_rep.epoch)
420 click_hash_assert((!_pprev && !_element) || *_pprev == _element);
430template <
typename T,
typename A>
461 : inherited(hc, b, pprev, element) {
468template <
typename T,
typename A>
472 _rep.nbuckets = initial_bucket_count;
473 _rep.buckets = (T **) CLICK_LALLOC(
sizeof(T *) * _rep.nbuckets);
474 _rep.first_bucket = _rep.nbuckets;
475 _rep.bucket_divider = libdivide_u32_gen(_rep.nbuckets);
476 click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
477#if defined(CLICK_HASH_ITERATOR_EPOCHS)
484template <
typename T,
typename A>
488 while (b < nb && b < max_bucket_count)
489 b = ((b + 1) << 1) - 1;
492 _rep.buckets = (T **) CLICK_LALLOC(
sizeof(T *) * _rep.nbuckets);
493 _rep.first_bucket = _rep.nbuckets;
494 _rep.bucket_divider = libdivide_u32_gen(_rep.nbuckets);
495 click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
496#if defined(CLICK_HASH_ITERATOR_EPOCHS)
499 for (b = 0; b < _rep.nbuckets; ++b)
503template <
typename T,
typename A>
506 CLICK_LFREE(_rep.buckets,
sizeof(T *) * _rep.nbuckets);
509template <
typename T,
typename A>
516 click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
517 click_hash_assert(r == h % _rep.nbuckets);
521template <
typename T,
typename A>
528template <
typename T,
typename A>
535template <
typename T,
typename A>
542template <
typename T,
typename A>
549template <
typename T,
typename A>
553 click_hash_assert(b < _rep.nbuckets);
554 return iterator(
this, b, &_rep.buckets[b], _rep.buckets[b]);
557template <
typename T,
typename A>
561 click_hash_assert(b < _rep.nbuckets);
562 return const_iterator(
this, b, &_rep.buckets[b], _rep.buckets[b]);
565template <
typename T,
typename A>
570 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
571 if (_rep.hashkeyeq(_rep.hashkey(*pprev), key))
576template <
typename T,
typename A>
583 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
584 c += _rep.hashkeyeq(_rep.hashkey(*pprev), key);
588template <
typename T,
typename A>
594 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
595 if (_rep.hashkeyeq(_rep.hashkey(*pprev), key))
596 return iterator(
this, b, pprev, *pprev);
597 return iterator(
this, b, &_rep.buckets[b], 0);
600template <
typename T,
typename A>
607template <
typename T,
typename A>
613 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
614 if (_rep.hashkeyeq(_rep.hashkey(*pprev), key)) {
616 *pprev = _rep.hashnext(element);
617 _rep.hashnext(element) = _rep.buckets[b];
618 _rep.buckets[b] = element;
619#if defined(CLICK_HASH_ITERATOR_EPOCHS)
622 return iterator(
this, b, &_rep.buckets[b], element);
624 return iterator(
this, b, &_rep.buckets[b], 0);
627template <
typename T,
typename A>
633template <
typename T,
typename A>
636 click_hash_assert(it._hc ==
this && it._bucket < _rep.nbuckets);
637 click_hash_assert(
bucket(_rep.hashkey(element)) == it._bucket);
638 click_hash_assert(!it._element || _rep.hashkeyeq(_rep.hashkey(element), _rep.hashkey(it._element)));
640 if (unlikely(old == element))
644 if (!(*it._pprev = it._element = _rep.hashnext(old)))
646#if defined(CLICK_HASH_ITERATOR_EPOCHS)
648 it._epoch = _rep.epoch;
653 _rep.hashnext(element) = _rep.hashnext(old);
658 it._bucket =
bucket(_rep.hashkey(element));
659 it._pprev = &_rep.buckets[it._bucket];
661 if (!(_rep.hashnext(element) = *it._pprev))
662 _rep.first_bucket = 0;
664 *it._pprev = it._element = element;
665#if defined(CLICK_HASH_ITERATOR_EPOCHS)
667 it._epoch = _rep.epoch;
672template <
typename T,
typename A>
675 click_hash_assert(it._hc ==
this && it._bucket < _rep.nbuckets);
676 click_hash_assert(
bucket(_rep.hashkey(element)) == it._bucket);
678#if defined(CLICK_HASH_ITERATOR_EPOCHS)
681 if (!(_rep.hashnext(element) = *it._pprev))
682 _rep.first_bucket = 0;
683 *it._pprev = element;
684 it._pprev = &_rep.hashnext(element);
685#if defined(CLICK_HASH_ITERATOR_EPOCHS)
686 it._epoch = _rep.epoch;
690template <
typename T,
typename A>
694 return set(it, element);
697template <
typename T,
typename A>
700 click_hash_assert(it._hc ==
this);
704template <
typename T,
typename A>
711template <
typename T,
typename A>
714#if defined(CLICK_HASH_ITERATOR_EPOCHS)
722template <
typename T,
typename A>
725 HashContainer_rep<T, A> rep(_rep);
730template <
typename T,
typename A>
733#if defined(CLICK_HASH_ITERATOR_EPOCHS)
737 while (new_nbuckets < n && new_nbuckets < max_bucket_count)
738 new_nbuckets = ((new_nbuckets + 1) << 1) - 1;
739 click_hash_assert(new_nbuckets > 0 && new_nbuckets <= max_bucket_count);
740 if (_rep.nbuckets == new_nbuckets)
743 T **new_buckets = (T **) CLICK_LALLOC(
sizeof(T *) * new_nbuckets);
748 T **old_buckets = _rep.buckets;
749 _rep.nbuckets = new_nbuckets;
750 _rep.buckets = new_buckets;
751 _rep.first_bucket = 0;
752 _rep.bucket_divider = libdivide_u32_gen(_rep.nbuckets);
753 click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
755 for (
size_t b = 0; b < old_nbuckets; b++)
756 for (T *element = old_buckets[b]; element; ) {
757 T *next = _rep.hashnext(element);
759 _rep.hashnext(element) = new_buckets[new_b];
760 new_buckets[new_b] = element;
764 CLICK_LFREE(old_buckets,
sizeof(T *) * old_nbuckets);
767template <
typename T,
typename A>
772 return a.
get() == b.
get();
775template <
typename T,
typename A>
780 return a.
get() != b.
get();
The const_iterator type for HashContainer.
Definition hashcontainer.hh:305
bucket_count_type bucket() const
Return the bucket number this iterator is in.
Definition hashcontainer.hh:362
void operator++()
Advance this iterator to the next element.
Definition hashcontainer.hh:367
T * get() const
Return a pointer to the element, null if *this == end().
Definition hashcontainer.hh:315
void operator++(int)
Advance this iterator to the next element.
Definition hashcontainer.hh:385
T * operator->() const
Return a pointer to the element, null if *this == end().
Definition hashcontainer.hh:323
HashContainer_const_iterator()
Construct an uninitialized iterator.
Definition hashcontainer.hh:311
T & operator*() const
Return a reference to the element.
Definition hashcontainer.hh:332
bool live() const
Return true iff *this != end().
Definition hashcontainer.hh:340
const HashContainer< T, A > * hashcontainer() const
Return the corresponding HashContainer.
Definition hashcontainer.hh:357
The iterator type for HashContainer.
Definition hashcontainer.hh:431
HashContainer< T, A > * hashcontainer() const
Return the corresponding HashContainer.
Definition hashcontainer.hh:450
bool can_insert() const
Return true iff elements can be inserted here.
Definition hashcontainer.hh:445
HashContainer_iterator()
Construct an uninitialized iterator.
Definition hashcontainer.hh:436
Intrusive hash table template.
Definition hashcontainer.hh:85
T value_type
Value type.
Definition hashcontainer.hh:93
size_type size() const
Return the number of elements stored.
Definition hashcontainer.hh:121
void clear()
Removes all elements from the container.
Definition hashcontainer.hh:712
void swap(HashContainer< T, A > &x)
Swaps the contents of *this and x.
Definition hashcontainer.hh:723
T * set(iterator &it, T *element, bool balance=false)
Replace the element at position it with element.
Definition hashcontainer.hh:634
iterator find_prefer(const key_type &key)
Return an iterator for an element with key key, if any.
Definition hashcontainer.hh:609
iterator end()
Return an iterator for the end of the container.
Definition hashcontainer.hh:544
T * erase(const key_type &key)
Remove an element with hashkey key.
Definition hashcontainer.hh:705
bool empty() const
Return true iff size() == 0.
Definition hashcontainer.hh:126
HashContainer(bucket_count_type n)
Construct an empty HashContainer with at least n buckets.
Definition hashcontainer.hh:485
iterator begin()
Return an iterator for the first element in the container.
Definition hashcontainer.hh:530
~HashContainer()
Destroy the HashContainer.
Definition hashcontainer.hh:504
void balance()
Rehash the table if it is unbalanced.
Definition hashcontainer.hh:285
bool contains(const key_type &key) const
Test if an element with key key exists in the table.
Definition hashcontainer.hh:566
uint32_t bucket_count_type
Type of bucket counts.
Definition hashcontainer.hh:99
size_type bucket_size(bucket_count_type n) const
Return the number of elements in bucket n.
Definition hashcontainer.hh:136
const_iterator find(const key_type &key) const
Definition hashcontainer.hh:602
T * erase(iterator &it)
Remove the element at position it.
Definition hashcontainer.hh:698
HashContainer()
Construct an empty HashContainer.
Definition hashcontainer.hh:469
T * set(T *element)
Replace the element with element->hashkey() with element.
Definition hashcontainer.hh:691
iterator begin(bucket_count_type n)
Return an iterator for the first element in bucket n.
Definition hashcontainer.hh:551
size_t size_type
Type of sizes.
Definition hashcontainer.hh:96
const_iterator begin() const
Definition hashcontainer.hh:523
bucket_count_type bucket(const key_type &key) const
Return the bucket number containing elements with key.
Definition hashcontainer.hh:511
iterator find(const key_type &key)
Return an iterator for an element with key, if any.
Definition hashcontainer.hh:590
size_type count(const key_type &key) const
Return the number of elements with key key in the table.
Definition hashcontainer.hh:578
T * get(const key_type &key) const
Return an element for key, if any.
Definition hashcontainer.hh:628
void rehash(bucket_count_type n)
Rehash the table, ensuring it contains at least n buckets.
Definition hashcontainer.hh:731
A::key_type key_type
Key type.
Definition hashcontainer.hh:88
const_iterator end() const
Definition hashcontainer.hh:537
const_iterator begin(bucket_count_type n) const
Definition hashcontainer.hh:559
void insert_at(iterator &it, T *element)
Insert an element at position it.
Definition hashcontainer.hh:673
bool unbalanced() const
Return true if this HashContainer should be rebalanced.
Definition hashcontainer.hh:148
bucket_count_type bucket_count() const
Return the number of buckets.
Definition hashcontainer.hh:131