ORIGINAL
Loading...
Searching...
No Matches
hashTable.h
Go to the documentation of this file.
1#ifndef HASHTABLE_H
2#define HASHTABLE_H
3
4#include "allocator.h"
5#include "couple.h"
6#include "hash.h"
7#include "vector.h"
8#include "wrapper.h"
9
10
28namespace original {
29
53 template<typename K_TYPE, typename V_TYPE, typename ALLOC = allocator<K_TYPE>, typename HASH = hash<K_TYPE>>
54 class hashTable{
55 public:
56
70 class hashNode final : public wrapper<couple<const K_TYPE, V_TYPE>> {
72 hashNode* next_;
73
74 public:
81 explicit hashNode(const K_TYPE& key = K_TYPE{}, const V_TYPE& value = V_TYPE{}, hashNode* next = nullptr);
82
87 hashNode(const hashNode& other);
88
95
101
106 const couple<const K_TYPE, V_TYPE>& getVal() const override;
107
112 const K_TYPE& getKey() const;
113
118 const V_TYPE& getValue() const;
119
124 V_TYPE& getValue();
125
129 void setVal(couple<const K_TYPE, V_TYPE> data) override;
130
135 void setValue(const V_TYPE& value);
136
140 hashNode* getPPrev() const override;
141
146 hashNode* getPNext() const override;
147
153
160 static void connect(hashNode* prev, hashNode* next);
161 };
162
168
174
180
184 static constexpr floating LOAD_FACTOR_MIN = 0.25;
185
189 static constexpr floating LOAD_FACTOR_MAX = 0.75;
190
195 static constexpr u_integer BUCKETS_SIZES_COUNT = 30;
196
228 static constexpr u_integer BUCKETS_SIZES[] = {
229 17, 29, 53, 97, 193,
230 389, 769, 1543, 3079, 6151,
231 12289, 24593, 49157, 98317, 196613,
232
233 393241, 786433, 1572869, 3145739, 6291469,
234 12582917, 25165843, 50331653, 100663319, 201326611,
235
236 402653189, 805306457, 1610612741, 3221225473, 4294967291
237 };
238
239 u_integer size_;
240 buckets_type buckets;
241 HASH hash_;
242 mutable rebind_alloc_node rebind_alloc{};
243
260 class Iterator {
261 protected:
263 mutable u_integer cur_bucket;
264 mutable hashNode* p_node;
265
275
285
293 explicit Iterator(vector<hashNode*, rebind_alloc_pointer>* buckets = nullptr,
294 u_integer bucket = 0, hashNode* node = nullptr);
295
300 Iterator(const Iterator& other);
301
308 public:
313 [[nodiscard]] bool hasNext() const;
314
319 void next() const;
320
326 void operator+=(integer steps) const;
327
334
341
346 [[nodiscard]] bool isValid() const;
347 };
348
376
385 hashNode* createNode(const K_TYPE& key = K_TYPE{}, const V_TYPE& value = V_TYPE{}, hashNode* next = nullptr) const;
386
392 void destroyNode(hashNode* node) noexcept;
393
399 u_integer getHashCode(const K_TYPE& key) const;
400
405 u_integer getBucketCount() const;
406
412 hashNode* getBucket(const K_TYPE& key) const;
413
418 floating loadFactor() const;
419
425 u_integer getNextSize() const;
426
431 u_integer getPrevSize() const;
432
442 void rehash(u_integer new_bucket_count);
443
450 void adjust();
451
456 explicit hashTable(HASH hash = HASH{});
457
463 hashNode* find(const K_TYPE& key) const;
464
471 bool modify(const K_TYPE& key, const V_TYPE& value);
472
480 bool insert(const K_TYPE& key, const V_TYPE& value);
481
488 bool erase(const K_TYPE& key);
489
494 virtual ~hashTable();
495 };
496}
497
498template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
500 : data_({key, value}), next_(next) {}
501
502template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
506
507template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
510 if (this == &other)
511 return *this;
512 this->data_ = other.data_;
513 this->next_ = other.next_;
514 return *this;
515}
516
517template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
522
523template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
528
529template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
531 return this->getVal().first();
532}
533
534template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
536 return this->getVal().second();
537}
538
539template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
543
544template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
548
549template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
551 this->data_.template set<1>(value);
552}
553
554template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
559
560template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
565
566template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
570
571template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
573 if (prev != nullptr) prev->setPNext(next);
574}
575
576template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
580 for (u_integer i = bucket + 1; i < buckets->size(); i++) {
581 if ((*buckets)[i])
582 return i;
583 }
584 return buckets->size();
585}
586
587template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
591 if (bucket == 0) return buckets->size();
592 for (u_integer i = bucket - 1; i > 0; i--) {
593 if ((*buckets)[i])
594 return i;
595 }
596 if ((*buckets)[0]) {
597 return 0;
598 }
599 return buckets->size();
600}
601
602template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
606
607template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
611
612template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
615 if (this == &other)
616 return *this;
617
618 this->p_buckets = other.p_buckets;
619 this->p_node = other.p_node;
620 return *this;
621}
622
623template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
625 if (this->p_node && this->p_node->getPNext()) {
626 return true;
627 }
628
629 return Iterator::findNextValidBucket(this->p_buckets, this->cur_bucket) != this->p_buckets->size();
630}
631
632template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
634 if (!this->isValid()) {
635 throw outOfBoundError();
636 }
637
638 if (this->p_node->getPNext()) {
639 this->p_node = this->p_node->getPNext();
640 return;
641 }
642
643 if (auto next_bucket = Iterator::findNextValidBucket(this->p_buckets, this->cur_bucket);
644 next_bucket != this->p_buckets->size()) {
645 this->cur_bucket = next_bucket;
646 this->p_node = this->p_buckets->get(next_bucket);
647 return;
648 }
649
650 this->cur_bucket = this->p_buckets->size();
651 this->p_node = nullptr;
652}
653
654template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
656 if (steps < 0) {
658 }
659
660 for (integer i = 0; i < steps; ++i) {
661 this->next();
662 }
663}
664
665template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
668 if (!this->isValid()) {
669 throw outOfBoundError();
670 }
671
672 return this->p_node->getVal();
673}
674
675template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
678 if (!this->isValid()) {
679 throw outOfBoundError();
680 }
681
682 return this->p_node->getVal();
683}
684
685template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
689
690template <typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
693{
695 for (u_integer i = 0; i < old_buckets.size(); ++i) {
697 hashNode* prev_new_node = nullptr;
698
699 while (old_node) {
700 hashNode* new_node = this->createNode(old_node->getKey(), old_node->getValue());
701
702 if (!prev_new_node) {
704 } else {
705 prev_new_node->setPNext(new_node);
706 }
707
709 old_node = old_node->getPNext();
710 }
711 }
712 return new_buckets;
713}
714
715template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
718 auto node = this->rebind_alloc.allocate(1);
719 this->rebind_alloc.construct(node, key, value, next);
720 return node;
721}
722
723template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
725 this->rebind_alloc.destroy(node);
726 this->rebind_alloc.deallocate(node, 1);
727}
728
729template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
732 return this->hash_(key) % this->getBucketCount();
733}
734
735template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
738 return this->buckets.size();
739}
740
741template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
744 u_integer code = this->getHashCode(key);
745 return this->buckets[code];
746}
747
748template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
751 return static_cast<floating>(this->size_) / this->getBucketCount();
752}
753
754template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
756 for (u_integer i : BUCKETS_SIZES){
757 if (this->getBucketCount() < i){
758 return i;
759 }
760 }
761 throw outOfBoundError();
762}
763
764template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
766 const u_integer current = this->getBucketCount();
767 for (u_integer i = BUCKETS_SIZES_COUNT - 1; i > 0; --i){
768 if (BUCKETS_SIZES[i] < current){
769 return BUCKETS_SIZES[i];
770 }
771 }
772 return BUCKETS_SIZES[0];
773}
774
775template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
777 if (new_bucket_count == this->getBucketCount())
778 return;
779
781
782 for (hashNode*& old_head : this->buckets) {
783 while (old_head) {
785 old_head = old_head->getPNext();
786
787 cur->setPNext(nullptr);
788 auto code = this->hash_(cur->getKey()) % new_bucket_count;
789
790 cur->setPNext(new_buckets[code]);
792 }
793 }
794
795 this->buckets = std::move(new_buckets);
796}
797
798template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
800 if (this->loadFactor() <= LOAD_FACTOR_MIN){
801 this->rehash(this->getPrevSize());
802 } else if (this->loadFactor() >= LOAD_FACTOR_MAX){
803 this->rehash(this->getNextSize());
804 }
805}
806
807template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
812
813template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
816 if (this->size_ == 0)
817 return nullptr;
818
819 for (auto cur = this->getBucket(key); cur; cur = cur->getPNext()){
820 if (cur->getKey() == key)
821 return cur;
822 }
823 return nullptr;
824}
825
826template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
828 if (auto cur = this->find(key)){
829 cur->setValue(value);
830 return true;
831 }
832 return false;
833}
834
835template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
837 this->adjust();
838
839 auto cur = this->getBucket(key);
840 if (!cur){
841 this->buckets[this->getHashCode(key)] = this->createNode(key, value);
842 } else{
843 if (cur->getKey() == key)
844 return false;
845
846 for (; cur->getPNext(); cur = cur->getPNext()){
847 if (cur->getKey() == key)
848 return false;
849 }
850 hashNode::connect(cur, this->createNode(key, value));
851 }
852
853 this->size_ += 1;
854 return true;
855}
856
857template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
859 if (this->size_ == 0)
860 return false;
861
862 this->adjust();
863
864 u_integer code = this->getHashCode(key);
865 hashNode* cur = this->buckets[code];
866 hashNode* prev = nullptr;
867
868 while (cur){
869 if (cur->getKey() == key) {
870 if (prev) {
871 hashNode::connect(prev, cur->getPNext());
872 } else {
873 this->buckets[code] = cur->getPNext();
874 }
875 this->destroyNode(cur);
876 this->size_ -= 1;
877 return true;
878 }
879 prev = cur;
880 cur = cur->getPNext();
881 }
882
883 return false;
884}
885
886template<typename K_TYPE, typename V_TYPE, typename ALLOC, typename HASH>
888 for (hashNode*& bucket: this->buckets) {
889 while (bucket){
890 auto next = bucket->getPNext();
891 this->destroyNode(bucket);
892 bucket = next;
893 }
894 }
895}
896
897#endif //HASHTABLE_H
Memory allocation interface and implementations.
const TYPE * get() const
Get managed pointer const version.
Definition autoPtr.h:629
Forward iterator for hashTable.
Definition hashTable.h:260
void next() const
Advances to the next element.
Definition hashTable.h:633
couple< const K_TYPE, V_TYPE > & get()
Gets current key-value pair (non-const)
Definition hashTable.h:667
Iterator & operator=(const Iterator &other)
Copy assignment operator.
Definition hashTable.h:614
static u_integer findPrevValidBucket(vector< hashNode *, rebind_alloc_pointer > *buckets, u_integer bucket)
Finds the previous non-empty bucket.
Definition hashTable.h:589
void operator+=(integer steps) const
Advances iterator by steps positions.
Definition hashTable.h:655
bool isValid() const
Checks if iterator points to valid element.
Definition hashTable.h:686
bool hasNext() const
Checks if more elements are available.
Definition hashTable.h:624
Iterator(vector< hashNode *, rebind_alloc_pointer > *buckets=nullptr, u_integer bucket=0, hashNode *node=nullptr)
Constructs an iterator pointing to specific position.
Definition hashTable.h:603
static u_integer findNextValidBucket(vector< hashNode *, rebind_alloc_pointer > *buckets, u_integer bucket)
Finds the next non-empty bucket.
Definition hashTable.h:578
Internal node type for hash table storage.
Definition hashTable.h:70
hashNode * getPNext() const override
Gets next node in chain.
Definition hashTable.h:562
couple< const K_TYPE, V_TYPE > & getVal() override
Gets key-value pair (non-const)
Definition hashTable.h:519
const V_TYPE & getValue() const
Gets the value (const)
Definition hashTable.h:535
hashNode * getPPrev() const override
Not supported (throws unSupportedMethodError)
Definition hashTable.h:556
void setPNext(hashNode *new_next)
Sets next node in chain.
Definition hashTable.h:567
const K_TYPE & getKey() const
Gets the key (const)
Definition hashTable.h:530
hashNode(const K_TYPE &key=K_TYPE{}, const V_TYPE &value=V_TYPE{}, hashNode *next=nullptr)
Constructs a new hash node.
Definition hashTable.h:499
void setValue(const V_TYPE &value)
Sets a new value.
Definition hashTable.h:550
static void connect(hashNode *prev, hashNode *next)
Connects two nodes in chain.
Definition hashTable.h:572
void setVal(couple< const K_TYPE, V_TYPE > data) override
Not supported (throws unSupportedMethodError)
Definition hashTable.h:545
hashNode & operator=(const hashNode &other)
Copy assignment operator.
Definition hashTable.h:509
Hash table implementation with separate chaining.
Definition hashTable.h:54
hashNode * createNode(const K_TYPE &key=K_TYPE{}, const V_TYPE &value=V_TYPE{}, hashNode *next=nullptr) const
Creates a new hash node.
Definition hashTable.h:717
bool modify(const K_TYPE &key, const V_TYPE &value)
Modifies value for existing key.
Definition hashTable.h:827
virtual ~hashTable()
Destroys hashTable.
Definition hashTable.h:887
u_integer getPrevSize() const
Gets previous appropriate bucket size for shrinking.
Definition hashTable.h:765
static constexpr floating LOAD_FACTOR_MAX
Maximum load factor before expanding.
Definition hashTable.h:189
u_integer getHashCode(const K_TYPE &key) const
Computes hash code for a key.
Definition hashTable.h:731
static constexpr u_integer BUCKETS_SIZES_COUNT
Size of BUCKETS_SIZES BUCKETS_SIZES.
Definition hashTable.h:195
static constexpr floating LOAD_FACTOR_MIN
Minimum load factor before shrinking.
Definition hashTable.h:184
void rehash(u_integer new_bucket_count)
Rehashes table to new bucket count.
Definition hashTable.h:776
u_integer getNextSize() const
Gets next appropriate bucket size for expansion.
Definition hashTable.h:755
buckets_type bucketsCopy(const buckets_type &old_buckets) const
Creates a deep copy of the hash table's bucket array.
Definition hashTable.h:692
bool insert(const K_TYPE &key, const V_TYPE &value)
Inserts new key-value pair.
Definition hashTable.h:836
hashNode * find(const K_TYPE &key) const
Finds node for given key.
Definition hashTable.h:815
ALLOC::template rebind_alloc< hashNode * > rebind_alloc_pointer
Rebound allocator type for pointer storage.
Definition hashTable.h:173
hashTable(HASH hash=HASH{})
Constructs empty hashTable.
Definition hashTable.h:808
hashNode * getBucket(const K_TYPE &key) const
Gets bucket head for a key.
Definition hashTable.h:743
void destroyNode(hashNode *node) noexcept
Destroys a hash node.
Definition hashTable.h:724
void adjust()
Adjusts table size based on load factor.
Definition hashTable.h:799
floating loadFactor() const
Calculates current load factor.
Definition hashTable.h:750
vector< hashNode *, rebind_alloc_pointer > buckets_type
Type representing the hash table buckets container.
Definition hashTable.h:179
bool erase(const K_TYPE &key)
Removes key-value pair.
Definition hashTable.h:858
u_integer getBucketCount() const
Gets current number of buckets.
Definition hashTable.h:737
ALLOC::template rebind_alloc< hashNode > rebind_alloc_node
Rebound allocator type for node storage.
Definition hashTable.h:167
static constexpr u_integer BUCKETS_SIZES[]
Predefined bucket sizes for hash table resizing.
Definition hashTable.h:228
Generic hash function object supporting multiple types.
Definition hash.h:62
Exception for container index out-of-range errors.
Definition error.h:192
Unique ownership smart pointer with move semantics.
Definition ownerPtr.h:37
Exception for unimplemented method calls.
Definition error.h:271
Base class for linked value containers with formatted output.
Definition wrapper.h:28
Generic pair container implementation.
double floating
Double-precision floating-point type.
Definition config.h:331
Provides a generic hashing utility and interface for hashable types.
Main namespace for the project Original.
Definition algorithms.h:21
TYPE find(coroutine::generator< TYPE > gen, Callback &&c)
Finds the first element satisfying a predicate.
Definition generators.h:856
Standard namespace extensions for original::alternative.
Definition allocator.h:351
Dynamic array container with automatic resizing.
Abstract polymorphic container with value encapsulation and navigation support.