Click
Loading...
Searching...
No Matches
hashcontainer.hh
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>
6#if CLICK_DEBUG_HASHMAP
7# define click_hash_assert(x) assert(x)
8#else
9# define click_hash_assert(x)
10#endif
11CLICK_DECLS
12
13template <typename T> class HashContainer_adapter;
14template <typename T, typename A = HashContainer_adapter<T> > class HashContainer_const_iterator;
15template <typename T, typename A = HashContainer_adapter<T> > class HashContainer_iterator;
16template <typename T, typename A = HashContainer_adapter<T> > class HashContainer;
17
19template <typename T, typename A>
20class HashContainer_rep : public A {
21 T **buckets;
22 uint32_t nbuckets;
23 mutable uint32_t first_bucket;
24 size_t size;
25 libdivide_u32_t bucket_divider;
26#if defined(CLICK_HASH_ITERATOR_EPOCHS)
27 unsigned epoch;
28#endif
29 friend class HashContainer<T, A>;
30 friend class HashContainer_const_iterator<T, A>;
31 friend class HashContainer_iterator<T, A>;
32};
35template <typename T>
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) {
40 return e->_hashnext;
41 }
42 static key_const_reference hashkey(const T *e) {
43 return e->hashkey();
44 }
45 static bool hashkeyeq(const key_type &a, const key_type &b) {
46 return a == b;
47 }
48};
49
84template <typename T, typename A>
85class HashContainer { public:
86
88 typedef typename A::key_type key_type;
89
93 typedef T value_type;
94
96 typedef size_t size_type;
97
99 typedef uint32_t bucket_count_type;
100
101 enum {
102#if CLICK_LINUXMODULE
103 max_bucket_count = 4194303,
104#else
105 max_bucket_count = (bucket_count_type) -1,
106#endif
107 initial_bucket_count = 63
108 };
109
112
115
118
119
121 inline size_type size() const {
122 return _rep.size;
123 }
124
126 inline bool empty() const {
127 return _rep.size == 0;
128 }
129
132 return _rep.nbuckets;
133 }
134
137 click_hash_assert(n < _rep.nbuckets);
138 size_type s = 0;
139 for (T *element = _rep.buckets[n]; element; element = _rep.hashnext(element))
140 ++s;
141 return s;
142 }
143
146
148 inline bool unbalanced() const {
149 return _rep.size > 2 * _rep.nbuckets && _rep.nbuckets < max_bucket_count;
150 }
151
152 typedef HashContainer_const_iterator<T, A> const_iterator;
153 typedef HashContainer_iterator<T, A> iterator;
154
158 inline iterator begin();
160 inline const_iterator begin() const;
161
164 inline iterator end();
166 inline const_iterator end() const;
167
169 inline iterator begin(bucket_count_type n);
171 inline const_iterator begin(bucket_count_type n) const;
172
174 inline bool contains(const key_type& key) const;
176 inline size_type count(const key_type& key) const;
177
186 inline iterator find(const key_type &key);
188 inline const_iterator find(const key_type &key) const;
189
194 inline iterator find_prefer(const key_type &key);
195
200 inline T *get(const key_type &key) const;
201
222 inline void insert_at(iterator &it, T *element);
223
242 T *set(iterator &it, T *element, bool balance = false);
243
252 inline T *set(T *element);
253
259 inline T *erase(iterator &it);
260
265 inline T *erase(const key_type &key);
266
269 void clear();
270
272 inline void swap(HashContainer<T, A> &x);
273
281
285 inline void balance() {
286 if (unbalanced())
287 rehash(bucket_count() + 1);
288 }
289
290 private:
291
292 HashContainer_rep<T, A> _rep;
293
295 HashContainer<T, A> &operator=(const HashContainer<T, A> &);
296
297 friend class HashContainer_iterator<T, A>;
298 friend class HashContainer_const_iterator<T, A>;
299
300};
301
304template <typename T, typename A>
306
307 typedef typename HashContainer<T, A>::size_type size_type;
308 typedef typename HashContainer<T, A>::bucket_count_type bucket_count_type;
309
313
315 T *get() const {
316#if defined(CLICK_HASH_ITERATOR_EPOCHS)
317 assert(!_element || _hc->_rep.epoch == _epoch);
318#endif
319 return _element;
320 }
321
323 T *operator->() const {
324#if defined(CLICK_HASH_ITERATOR_EPOCHS)
325 assert(!_element || _hc->_rep.epoch == _epoch);
326#endif
327 return _element;
328 }
329
332 T &operator*() const {
333#if defined(CLICK_HASH_ITERATOR_EPOCHS)
334 assert(!_element || _hc->_rep.epoch == _epoch);
335#endif
336 return *_element;
337 }
338
340 inline bool live() const {
341#if defined(CLICK_HASH_ITERATOR_EPOCHS)
342 assert(!_element || _hc->_rep.epoch == _epoch);
343#endif
344 return _element;
345 }
346
347 typedef T *(HashContainer_const_iterator::*unspecified_bool_type)() const;
349 inline operator unspecified_bool_type() const {
350#if defined(CLICK_HASH_ITERATOR_EPOCHS)
351 assert(!_element || _hc->_rep.epoch == _epoch);
352#endif
353 return _element ? &HashContainer_const_iterator::get : 0;
354 }
355
358 return _hc;
359 }
360
362 bucket_count_type bucket() const {
363 return _bucket;
364 }
365
367 void operator++() {
368#if defined(CLICK_HASH_ITERATOR_EPOCHS)
369 assert(!_element || _hc->_rep.epoch == _epoch);
370#endif
371 if (_element && _hc->_rep.hashnext(_element)) {
372 _pprev = &_hc->_rep.hashnext(_element);
373 _element = *_pprev;
374 } else if (_bucket != _hc->_rep.nbuckets) {
375 for (++_bucket; _bucket != _hc->_rep.nbuckets; ++_bucket)
376 if (*(_pprev = &_hc->_rep.buckets[_bucket])) {
377 _element = *_pprev;
378 return;
379 }
380 _element = 0;
381 }
382 }
383
385 void operator++(int) {
386 ++*this;
387 }
388
389 private:
390
391 T *_element;
392 T **_pprev;
393 bucket_count_type _bucket;
394 const HashContainer<T, A> *_hc;
395#if defined(CLICK_HASH_ITERATOR_EPOCHS)
396 unsigned _epoch;
397#endif
398
400 : _hc(hc) {
401 _bucket = hc->_rep.first_bucket;
402 _pprev = &hc->_rep.buckets[_bucket];
403#if defined(CLICK_HASH_ITERATOR_EPOCHS)
404 _epoch = hc->_rep.epoch;
405#endif
406 if (unlikely(_bucket == hc->_rep.nbuckets))
407 _element = 0;
408 else if (!(_element = *_pprev)) {
409 (*this)++;
410 hc->_rep.first_bucket = _bucket;
411 }
412 }
413
414 inline HashContainer_const_iterator(const HashContainer<T, A> *hc, bucket_count_type b, T **pprev, T *element)
415 : _element(element), _pprev(pprev), _bucket(b), _hc(hc)
416#if defined(CLICK_HASH_ITERATOR_EPOCHS)
417 , _epoch(hc->_rep.epoch)
418#endif
419 {
420 click_hash_assert((!_pprev && !_element) || *_pprev == _element);
421 }
422
423 friend class HashContainer<T, A>;
424 friend class HashContainer_iterator<T, A>;
425
426};
427
430template <typename T, typename A>
432
434
438
445 bool can_insert() const {
446 return this->_bucket < this->_hc->bucket_count();
447 }
448
451 return const_cast<HashContainer<T, A> *>(this->_hc);
452 }
453
454 private:
455
457 : inherited(hc) {
458 }
459
460 inline HashContainer_iterator(HashContainer<T, A> *hc, typename inherited::bucket_count_type b, T **pprev, T *element)
461 : inherited(hc, b, pprev, element) {
462 }
463
464 friend class HashContainer<T, A>;
465
466};
467
468template <typename T, typename A>
470{
471 _rep.size = 0;
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)
478 _rep.epoch = 0;
479#endif
480 for (bucket_count_type b = 0; b < _rep.nbuckets; ++b)
481 _rep.buckets[b] = 0;
482}
483
484template <typename T, typename A>
486{
487 bucket_count_type b = 1;
488 while (b < nb && b < max_bucket_count)
489 b = ((b + 1) << 1) - 1;
490 _rep.size = 0;
491 _rep.nbuckets = b;
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)
497 _rep.epoch = 0;
498#endif
499 for (b = 0; b < _rep.nbuckets; ++b)
500 _rep.buckets[b] = 0;
501}
502
503template <typename T, typename A>
505{
506 CLICK_LFREE(_rep.buckets, sizeof(T *) * _rep.nbuckets);
507}
508
509template <typename T, typename A>
512{
513 bucket_count_type h = hashcode(key);
514 bucket_count_type d = libdivide_u32_do(h, &_rep.bucket_divider);
515 bucket_count_type r = h - _rep.nbuckets * d;
516 click_hash_assert(_rep.nbuckets == libdivide_u32_recover(&_rep.bucket_divider));
517 click_hash_assert(r == h % _rep.nbuckets);
518 return r;
519}
520
521template <typename T, typename A>
524{
525 return const_iterator(this);
526}
527
528template <typename T, typename A>
529inline typename HashContainer<T, A>::iterator
531{
532 return iterator(this);
533}
534
535template <typename T, typename A>
538{
539 return const_iterator(this, -1, 0, 0);
540}
541
542template <typename T, typename A>
543inline typename HashContainer<T, A>::iterator
545{
546 return iterator(this, -1, 0, 0);
547}
548
549template <typename T, typename A>
550inline typename HashContainer<T, A>::iterator
552{
553 click_hash_assert(b < _rep.nbuckets);
554 return iterator(this, b, &_rep.buckets[b], _rep.buckets[b]);
555}
556
557template <typename T, typename A>
560{
561 click_hash_assert(b < _rep.nbuckets);
562 return const_iterator(this, b, &_rep.buckets[b], _rep.buckets[b]);
563}
564
565template <typename T, typename A>
566inline bool HashContainer<T, A>::contains(const key_type& key) const
567{
568 bucket_count_type b = bucket(key);
569 T **pprev;
570 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
571 if (_rep.hashkeyeq(_rep.hashkey(*pprev), key))
572 return true;
573 return false;
574}
575
576template <typename T, typename A>
577inline typename HashContainer<T, A>::size_type
579{
580 bucket_count_type b = bucket(key);
581 size_t c = 0;
582 T **pprev;
583 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
584 c += _rep.hashkeyeq(_rep.hashkey(*pprev), key);
585 return c;
586}
587
588template <typename T, typename A>
589inline typename HashContainer<T, A>::iterator
591{
592 bucket_count_type b = bucket(key);
593 T **pprev;
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);
598}
599
600template <typename T, typename A>
603{
604 return const_cast<HashContainer<T, A> *>(this)->find(key);
605}
606
607template <typename T, typename A>
608inline typename HashContainer<T, A>::iterator
610{
611 bucket_count_type b = bucket(key);
612 T **pprev;
613 for (pprev = &_rep.buckets[b]; *pprev; pprev = &_rep.hashnext(*pprev))
614 if (_rep.hashkeyeq(_rep.hashkey(*pprev), key)) {
615 T *element = *pprev;
616 *pprev = _rep.hashnext(element);
617 _rep.hashnext(element) = _rep.buckets[b];
618 _rep.buckets[b] = element;
619#if defined(CLICK_HASH_ITERATOR_EPOCHS)
620 ++_rep.epoch;
621#endif
622 return iterator(this, b, &_rep.buckets[b], element);
623 }
624 return iterator(this, b, &_rep.buckets[b], 0);
625}
626
627template <typename T, typename A>
628inline T *HashContainer<T, A>::get(const key_type &key) const
629{
630 return find(key).get();
631}
632
633template <typename T, typename A>
635{
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)));
639 T *old = it.get();
640 if (unlikely(old == element))
641 return old;
642 if (!element) {
643 --_rep.size;
644 if (!(*it._pprev = it._element = _rep.hashnext(old)))
645 ++it;
646#if defined(CLICK_HASH_ITERATOR_EPOCHS)
647 ++_rep.epoch;
648 it._epoch = _rep.epoch;
649#endif
650 return old;
651 }
652 if (old)
653 _rep.hashnext(element) = _rep.hashnext(old);
654 else {
655 ++_rep.size;
656 if (unlikely(unbalanced()) && balance) {
657 rehash(bucket_count() + 1);
658 it._bucket = bucket(_rep.hashkey(element));
659 it._pprev = &_rep.buckets[it._bucket];
660 }
661 if (!(_rep.hashnext(element) = *it._pprev))
662 _rep.first_bucket = 0;
663 }
664 *it._pprev = it._element = element;
665#if defined(CLICK_HASH_ITERATOR_EPOCHS)
666 ++_rep.epoch;
667 it._epoch = _rep.epoch;
668#endif
669 return old;
670}
671
672template <typename T, typename A>
673inline void HashContainer<T, A>::insert_at(iterator &it, T *element)
674{
675 click_hash_assert(it._hc == this && it._bucket < _rep.nbuckets);
676 click_hash_assert(bucket(_rep.hashkey(element)) == it._bucket);
677 ++_rep.size;
678#if defined(CLICK_HASH_ITERATOR_EPOCHS)
679 ++_rep.epoch;
680#endif
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;
687#endif
688}
689
690template <typename T, typename A>
691inline T *HashContainer<T, A>::set(T *element)
692{
693 iterator it = find(_rep.hashkey(element));
694 return set(it, element);
695}
696
697template <typename T, typename A>
699{
700 click_hash_assert(it._hc == this);
701 return set(it, 0);
702}
703
704template <typename T, typename A>
706{
707 iterator it = find(key);
708 return set(it, 0);
709}
710
711template <typename T, typename A>
713{
714#if defined(CLICK_HASH_ITERATOR_EPOCHS)
715 ++_rep.epoch;
716#endif
717 for (bucket_count_type b = 0; b < _rep.nbuckets; ++b)
718 _rep.buckets[b] = 0;
719 _rep.size = 0;
720}
721
722template <typename T, typename A>
724{
725 HashContainer_rep<T, A> rep(_rep);
726 _rep = o._rep;
727 o._rep = rep;
728}
729
730template <typename T, typename A>
732{
733#if defined(CLICK_HASH_ITERATOR_EPOCHS)
734 ++_rep.epoch;
735#endif
736 bucket_count_type new_nbuckets = 1;
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)
741 return;
742
743 T **new_buckets = (T **) CLICK_LALLOC(sizeof(T *) * new_nbuckets);
744 for (bucket_count_type b = 0; b < new_nbuckets; ++b)
745 new_buckets[b] = 0;
746
747 bucket_count_type old_nbuckets = _rep.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));
754
755 for (size_t b = 0; b < old_nbuckets; b++)
756 for (T *element = old_buckets[b]; element; ) {
757 T *next = _rep.hashnext(element);
758 bucket_count_type new_b = bucket(_rep.hashkey(element));
759 _rep.hashnext(element) = new_buckets[new_b];
760 new_buckets[new_b] = element;
761 element = next;
762 }
763
764 CLICK_LFREE(old_buckets, sizeof(T *) * old_nbuckets);
765}
766
767template <typename T, typename A>
768inline bool
770{
771 click_hash_assert(a.hashcontainer() == b.hashcontainer());
772 return a.get() == b.get();
773}
774
775template <typename T, typename A>
776inline bool
778{
779 click_hash_assert(a.hashcontainer() == b.hashcontainer());
780 return a.get() != b.get();
781}
782
783CLICK_ENDDECLS
784#endif
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