Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_lhash.H
Go to the documentation of this file.
2/*
3 Aleph_w
4
5 Data structures & Algorithms
6 version 2.0.0b
7 https://github.com/lrleon/Aleph-w
8
9 This file is part of Aleph-w library
10
11 Copyright (c) 2002-2026 Leandro Rabindranath Leon
12
13 Permission is hereby granted, free of charge, to any person obtaining a copy
14 of this software and associated documentation files (the "Software"), to deal
15 in the Software without restriction, including without limitation the rights
16 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 copies of the Software, and to permit persons to whom the Software is
18 furnished to do so, subject to the following conditions:
19
20 The above copyright notice and this permission notice shall be included in all
21 copies or substantial portions of the Software.
22
23 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
26 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
29 SOFTWARE.
30*/
31
32
102# ifndef TPL_LHASH_H
103# define TPL_LHASH_H
104
105# include <iostream>
106# include <primes.H>
107# include <dlink.H>
108# include <htlist.H>
109# include <tpl_dynArray.H>
110# include <hashDry.H>
111# include <hash-fct.H>
112# include <tpl_dynArray.H>
113# include <hash-dry.H>
114# include <ah-errors.H>
115
116# ifdef N
117# define NBACKUP N
118# undef N
119# endif
120
121# ifdef M
122# define MBACKUP M
123# undef M
124# endif
125
126using namespace Primes;
127
128using namespace Aleph;
129
130namespace Aleph
131{
149 template <typename Key, class BucketType, class Cmp>
150 class GenLhashTable : public HashStats<GenLhashTable<Key, BucketType, Cmp>>
151 {
152 friend class HashStats<GenLhashTable<Key, BucketType, Cmp>>;
153
154 public:
156
157 using Hash_Fct = std::function<size_t(const Key &)>;
158
159 using Hash_Fct_Ptr = size_t (*)(const Key &);
160
161 using Key_Type = Key;
162
163 using Item_Type = Key;
164
165 protected:
167
168 private:
169 using BucketList = Dnode<Key>; // Bucket list type
170 using BucketItor = typename Dnode<Key>::Iterator; // Bucket iterator
171 using Node = Dnode<Key>; // Node alias
172
174
175 protected:
176 size_t len; // Table size
177 Cmp cmp;
180
181 private:
182 size_t N; // Number of elements in the table
183 size_t busy_slots_counter; // Number of occupied entries
184 bool remove_all_buckets; // free buckets in destructor
186
187 public:
188 Cmp &get_compare() { return cmp; }
189
190 const Cmp &get_compare() const { return cmp; }
191
192 protected:
194 const float lower, const float upper,
195 const bool remove_all, const bool resize)
199 N(0), busy_slots_counter(0), remove_all_buckets(remove_all),
201 {
202 table = new BucketList [len];
203 }
204
205 public:
229
230 void swap(GenLhashTable & other) noexcept
231 {
232 std::swap(hash_fct, other.hash_fct);
233 std::swap(table, other.table);
234 std::swap(len, other.len);
235 std::swap(cmp, other.cmp);
236 std::swap(N, other.N);
237 std::swap(busy_slots_counter, other.busy_slots_counter);
238 std::swap(remove_all_buckets, other.remove_all_buckets);
239 std::swap(with_resize, other.with_resize);
240 }
241
242 GenLhashTable(const GenLhashTable &) = delete;
243
245
247 : hash_fct(std::move(other.hash_fct)),
248 table(other.table),
249 len(other.len),
250 cmp(std::move(other.cmp)),
251 lower_alpha(other.lower_alpha),
252 upper_alpha(other.upper_alpha),
253 N(other.N),
254 busy_slots_counter(other.busy_slots_counter),
255 remove_all_buckets(other.remove_all_buckets),
256 with_resize(other.with_resize)
257 {
258 other.table = nullptr;
259 other.len = 0;
260 other.N = 0;
261 other.busy_slots_counter = 0;
262 }
263
265 {
266 if (this != &other)
267 {
268 if (remove_all_buckets && table != nullptr)
269 empty();
270 delete [] table;
271
272 hash_fct = std::move(other.hash_fct);
273 table = other.table;
274 len = other.len;
275 cmp = std::move(other.cmp);
276 lower_alpha = other.lower_alpha;
277 upper_alpha = other.upper_alpha;
278 N = other.N;
279 busy_slots_counter = other.busy_slots_counter;
280 remove_all_buckets = other.remove_all_buckets;
281 with_resize = other.with_resize;
282
283 other.table = nullptr;
284 other.len = 0;
285 other.N = 0;
286 other.busy_slots_counter = 0;
287 }
288 return *this;
289 }
290
293 {
294 for (size_t i = 0; i < len; ++i)
295 for (BucketItor itor(table[i]); itor.has_curr(); /* nothing */)
296 delete static_cast<Bucket *>(itor.del_ne());
297 busy_slots_counter = N = 0;
298 }
299
300 private:
301 Bucket *
302 search_in_bucket_list(BucketList & list, const Key & key) const
303 {
304 for (BucketItor it(list); it.has_curr(); it.next_ne())
305 if (auto *bucket = static_cast<Bucket *>(it.get_curr()); cmp(key, bucket->get_key()))
306 return bucket;
307
308 return nullptr;
309 }
310
311 protected:
334 template <typename HashFunc, typename SearchKey>
336 const SearchKey & search_key) const noexcept
337 {
338 const auto bucket_idx = hash_func(search_key) % len;
339
340 for (BucketItor it(table[bucket_idx]); it.has_curr(); it.next_ne())
341 if (auto *bucket = static_cast<Bucket *>(it.get_curr());
342 cmp(bucket->get_key(), search_key))
343 return bucket;
344
345 return nullptr;
346 }
347
348 public:
350
352 void set_hash_fct(Hash_Fct fct) noexcept
353 {
354 hash_fct = fct;
355 }
356
358 {
360 }
361
363 float current_alpha() const noexcept { return 1.0 * N / len; }
364
368 {
369 const auto i = hash_fct(bucket->get_key()) % len;
370 auto & list = table[i];
371
372 if (list.is_empty()) // is table[i] list empty?
373 ++busy_slots_counter; // yes ==> update occupied counter
374
375 if (search_in_bucket_list(list, bucket->get_key()) != nullptr)
376 return nullptr;
377
378 list.append(bucket); // insert bucket at the end
379 ++N;
380
382 resize(next_prime(2 * len));
383
384 return bucket;
385 }
386
387 // Search bucket->key. If found, returns the bucket address inside the table.
388 // Otherwise, inserts and returns bucket.
390 {
391 const auto i = hash_fct(bucket->get_key()) % len;
392 auto & list = table[i];
393
394 if (list.is_empty()) // is table[i] list empty?
395 ++busy_slots_counter; // yes ==> update occupied counter
396
397 auto *p = search_in_bucket_list(list, bucket->get_key());
398 if (p != nullptr)
399 return p;
400
401 list.append(bucket); // insert bucket at the end
402 ++N;
403
405 resize(next_prime(2 * len));
406
407 return bucket;
408 }
409
412 Bucket * search(const Key & key) const noexcept
413 {
414 const auto i = hash_fct(key) % len;
415 return search_in_bucket_list(table[i], key);
416 }
417
418 private:
419 // Remove without perform resizing. This is strictly required inside
420 // the del() method of Iterator. In addition, dries the code
421 Bucket * remove_bucket(Bucket *bucket) noexcept
422 {
423 const auto idx = hash_fct(bucket->get_key()) % len;
424 bucket->del(); // remove from its collision list
425
426 if (table[idx].is_empty()) // did the list become empty?
427 --busy_slots_counter; // yes ==> update occupied lists counter
428
429 --N;
430
431 return bucket;
432 }
433
434 public:
437 Bucket * remove(Bucket *bucket) noexcept
438 { // save next collision
439 remove_bucket(bucket);
440
442 resize(next_prime(len / 2));
443
444 return bucket;
445 }
446
449 size_t resize(const size_t new_size)
450 {
451 assert(len > 0);
452
453 if (new_size == 0)
454 return len;
455
456 auto *new_table = new BucketList [new_size];
457 BucketList *old_table = table; // save current table state
458 const size_t old_size = len;
459 table = new_table; // empty table with new array
460 len = new_size;
461 busy_slots_counter = N = 0;
462
463 for (size_t i = 0; i < old_size; ++i) // reinsert buckets
464 // traverse collision list in old_table[i]
465 for (BucketItor it(old_table[i]); it.has_curr(); /* Nothing */)
466 insert(static_cast<Bucket *>(it.del_ne())); // remove and insert into table[]
467
468 delete [] old_table; // free old table memory
469
470 return len;
471 }
472
476 {
478 empty();
479
480 delete [] table;
481 }
482
485 Bucket * search_next(Bucket *bucket) const
486 {
487 assert(bucket != nullptr);
488
489 const auto i = hash_fct(bucket->get_key()) % len;
490
492 itor.set(bucket);
493
494 while (true)
495 {
496 itor.next_ne();
497
498 if (not itor.has_curr())
499 return nullptr;
500
501 if (auto *node = static_cast<Bucket *>(itor.get_curr()); cmp(bucket->get_key(), node->get_key()))
502 return node;
503 }
504 }
505
507 const size_t &capacity() const noexcept { return len; }
508
510 const size_t &size() const noexcept { return N; }
511
513 const size_t &
515
516 [[nodiscard]] constexpr bool is_empty() const noexcept { return N == 0; }
517
524 {
525 long curr_index = -1; // index in table
526 long curr_pos = 0;
527 BucketItor curr_itor; // Iterator over table[curr_index]
529
530 // Advance to the next available entry in table
532 {
533 while (true)
534 {
535 if (curr_index == hash_table->len - 1)
536 { // remain in overflow state
538 return;
539 }
540
541 ++curr_index;
542
544 {
546 curr_itor = itor;
547 return;
548 }
549 }
550 }
551
553 {
554 while (true)
555 {
557 << "hash table iterator overflow";
558
559 if (curr_index == hash_table->len - 1)
560 { // remain in overflow state
562 return;
563 }
564
565 ++curr_index;
566
568 {
570 curr_itor = itor;
571 return;
572 }
573 }
574 }
575
577 {
578 curr_itor.next_ne();
579 if (not curr_itor.has_curr())
581 curr_pos++;
582 }
583
585 {
586 curr_itor.next();
587 if (not curr_itor.has_curr())
589 curr_pos++;
590 }
591
593 {
594 while (true)
595 {
596 if (curr_index == 0)
597 { // remain in underflow state
598 curr_index = -1;
599 return;
600 }
601
602 --curr_index;
603
605 {
607 curr_itor = itor;
608 curr_itor.reset_last();
609 return;
610 }
611 }
612 }
613
615 {
616 while (true)
617 {
619 << "hash table iterator underflow";
620
621 if (curr_index == 0)
622 { // remain in underflow state
623 curr_index = -1;
624 return;
625 }
626
627 --curr_index;
628
630 {
632 curr_itor = itor;
633 curr_itor.reset_last();
634 return;
635 }
636 }
637 }
638
640 {
641 curr_itor.prev_ne();
642 if (not curr_itor.has_curr())
644 curr_pos--;
645 }
646
648 {
649 curr_itor.prev();
650 if (not curr_itor.has_curr())
652 curr_pos--;
653 }
654
655 public:
658
660 using Item_Type = Bucket *;
661
664 : hash_table(&const_cast<GenLhashTable &>(table))
665 {
666 try
667 {
669 }
670 catch (const std::overflow_error &)
671 { /* nothing to do */
672 }
673 }
674
676 Iterator() = default;
677
680 {
681 curr_index = -1;
682 curr_pos = 0;
684 }
685
688 {
689 if (hash_table->is_empty())
690 {
691 curr_index = -1;
692 curr_pos = -1;
693 return;
694 }
696 curr_pos = static_cast<long>(hash_table->N) - 1;
698 }
699
701 {
702 put_itor_at_the_end(*this);
703 }
704
707 {
708 return curr_index >= 0 and curr_index < hash_table->len;
709 }
710
712 {
713 return static_cast<Bucket *>(curr_itor.get_curr_ne());
714 }
715
718 {
720 << "hash table iterator underflow";
721
723 << "hash table iterator overflow";
724
725 return static_cast<Bucket *>(curr_itor.get_curr());
726 }
727
728 long get_pos() const noexcept { return curr_pos; }
729
735
736 void next()
737 {
739 << "hash table iterator overflow";
740 next_ne();
741 }
742
748
749 void prev()
750 {
752 << "hash table iterator underflow";
754 }
755
757 {
759 next();
761 return ret_val;
762 }
763 };
764 };
765
773 template <typename Key>
775
776
784 template <typename Key>
785 struct LhashBucketVtl : public Dnode<Key>
786 {
788 using Base::Base;
789
791 virtual ~LhashBucketVtl() = default;
792 };
793
807 template <typename Key, class Cmp = Aleph::equal_to<Key>>
808 struct LhashTable : public GenLhashTable<Key, LhashBucket<Key>, Cmp>
809 {
811 using Base::Base;
812 };
813
826 template <typename Key, class Cmp = Aleph::equal_to<Key>>
827 struct LhashTableVtl : public GenLhashTable<Key, LhashBucketVtl<Key>, Cmp>
828 {
830 using Base::Base;
831 };
832} // end namespace Aleph
833
834# ifdef NBACKUP
835# define N NBACKUP
836# undef NBACKUP
837# endif
838
839# ifdef MBACKUP
840# define M MBACKUP
841# undef MBACKUP
842# endif
843
844# endif/* TPL_LHASH_H */
Exception handling system with formatted messages for Aleph-w.
#define ah_underflow_error_if(C)
Throws std::underflow_error if condition holds.
Definition ah-errors.H:368
#define ah_overflow_error_if(C)
Throws std::overflow_error if condition holds.
Definition ah-errors.H:463
void put_itor_at_the_end(Itor &it) noexcept
Definition aleph.H:54
Iterator on a list of Dnode objects.
Definition tpl_dnode.H:261
Iterator over a GenLhashTable hash table.
Definition tpl_lhash.H:524
void reset_last() noexcept
Reset the iterator to the last bucket.
Definition tpl_lhash.H:687
void reset_first() noexcept
Reset the iterator to the first bucket.
Definition tpl_lhash.H:679
Iterator()=default
Instantiate an empty iterator.
Bucket * get_curr()
Returns the current bucket.
Definition tpl_lhash.H:717
void locate_next_available_bucket_ne() noexcept
Definition tpl_lhash.H:576
void locate_prev_available_bucket_ne() noexcept
Definition tpl_lhash.H:639
void locate_next_available_entry_ne() noexcept
Definition tpl_lhash.H:531
void prev_ne() noexcept
Moves the iterator back by one bucket.
Definition tpl_lhash.H:744
Bucket * Item_Type
Item type returned by get_curr().
Definition tpl_lhash.H:660
void next_ne() noexcept
Advances the iterator by one bucket.
Definition tpl_lhash.H:731
Bucket * get_curr_ne() noexcept
Definition tpl_lhash.H:711
Iterator(const GenLhashTable &table) noexcept
Instantiate an iterator over the hash table.
Definition tpl_lhash.H:663
void locate_prev_available_entry_ne() noexcept
Definition tpl_lhash.H:592
bool has_curr() const noexcept
Returns true if the iterator has a current bucket.
Definition tpl_lhash.H:706
long get_pos() const noexcept
Definition tpl_lhash.H:728
Generic hash table with collision resolution by separate chaining.
Definition tpl_lhash.H:151
Bucket * remove(Bucket *bucket) noexcept
Removes bucket from the table.
Definition tpl_lhash.H:437
GenLhashTable & operator=(const GenLhashTable &)=delete
GenLhashTable(size_t table_size=Primes::DefaultPrime, Hash_Fct_Ptr hash_fct=Aleph::dft_hash_fct< Key >, Cmp cmp=Cmp(), float lower_alpha=hash_default_lower_alpha, float upper_alpha=hash_default_upper_alpha, bool remove_all_buckets=true, bool with_resize=true)
Instantiate a generic hash table.
Definition tpl_lhash.H:219
Bucket * insert(Bucket *bucket)
Inserts bucket into the table and returns its address if the key is not already in the table; otherwi...
Definition tpl_lhash.H:367
Hash_Fct get_hash_fct() const noexcept
Definition tpl_lhash.H:349
size_t(*)(const Key &) Hash_Fct_Ptr
Definition tpl_lhash.H:159
GenLhashTable(GenLhashTable &&other) noexcept
Definition tpl_lhash.H:246
Bucket * search_in_bucket_list(BucketList &list, const Key &key) const
Definition tpl_lhash.H:302
typename Dnode< Key >::Iterator BucketItor
Definition tpl_lhash.H:170
const size_t & get_num_busy_slots() const noexcept
Returns the number of occupied entries in the array.
Definition tpl_lhash.H:514
void empty() noexcept
Empties the hash table; frees memory of all buckets.
Definition tpl_lhash.H:292
const Cmp & get_compare() const
Definition tpl_lhash.H:190
float current_alpha() const noexcept
return the current table load
Definition tpl_lhash.H:363
Bucket * remove_bucket(Bucket *bucket) noexcept
Definition tpl_lhash.H:421
const size_t & size() const noexcept
Returns the number of elements contained in the table.
Definition tpl_lhash.H:510
Bucket * search_or_insert(Bucket *bucket)
Definition tpl_lhash.H:389
void set_hash_fct(Hash_Fct fct) noexcept
Set the internal hash function.
Definition tpl_lhash.H:352
virtual ~GenLhashTable()
Frees the table memory and, if remove_all_buckets is true (specified in the constructor),...
Definition tpl_lhash.H:475
const size_t & capacity() const noexcept
Returns the table capacity.
Definition tpl_lhash.H:507
std::function< size_t(const Key &)> Hash_Fct
Definition tpl_lhash.H:157
void swap(GenLhashTable &other) noexcept
Definition tpl_lhash.H:230
GenLhashTable(const GenLhashTable &)=delete
GenLhashTable(const size_t table_size, Hash_Fct hash_f, Cmp cpm_fct, const float lower, const float upper, const bool remove_all, const bool resize)
Definition tpl_lhash.H:193
Bucket * search_next(Bucket *bucket) const
Returns the next bucket that collides with bucket.
Definition tpl_lhash.H:485
Bucket * search(const Key &key) const noexcept
Search in the table for a bucket with key.
Definition tpl_lhash.H:412
constexpr bool is_empty() const noexcept
Definition tpl_lhash.H:516
GenLhashTable & operator=(GenLhashTable &&other) noexcept
Definition tpl_lhash.H:264
BucketList * table
Definition tpl_lhash.H:173
Bucket * search_with_custom_hash(HashFunc hash_func, const SearchKey &search_key) const noexcept
Helper method for derived classes to perform custom heterogeneous searches.
Definition tpl_lhash.H:335
size_t resize(const size_t new_size)
Resizes the hash table to new_size and re-locates keys.
Definition tpl_lhash.H:449
void set_hash_fct(Hash_Fct_Ptr fct) noexcept
Definition tpl_lhash.H:357
CRTP mixin providing statistics and configuration for chained hash tables.
Definition hashDry.H:985
Common hash table utilities and base classes.
Collection of general-purpose hash functions.
Common operations for open addressing hash tables (CRTP mixin).
Singly linked list implementations with head-tail access.
Table::Bucket Bucket
Definition lin-hash.cc:54
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
const float hash_default_upper_alpha
Definition hash-dry.C:40
const float hash_default_lower_alpha
Definition hash-dry.C:38
DynList< T > maps(const C &c, Op op)
Classic map operation.
const unsigned long DefaultPrime
Default prime number used when no specific size is requested.
Definition primes.C:381
size_t next_prime(unsigned long n)
Find the smallest prime number >= n from the database.
Definition primes.C:383
Prime number utilities for hash tables and mathematical operations.
Bucket with virtual destructor for a hash table with collision resolution by separate chaining.
Definition tpl_lhash.H:786
virtual ~LhashBucketVtl()=default
Virtual destructor.
Generic hash table with collision resolution by separate chaining and buckets with virtual destructor...
Definition tpl_lhash.H:828
Generic hash table with collision resolution by separate chaining and buckets without virtual destruc...
Definition tpl_lhash.H:809
Lazy and scalable dynamic array implementation.