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# include <ah-concepts.H>
116
117# ifdef N
118# define NBACKUP N
119# undef N
120# endif
121
122# ifdef M
123# define MBACKUP M
124# undef M
125# endif
126
127using namespace Primes;
128
129using namespace Aleph;
130
131namespace Aleph
132{
150 template <typename Key, class BucketType, class Cmp>
152 class GenLhashTable : public HashStats<GenLhashTable<Key, BucketType, Cmp>>
153 {
154 friend class HashStats<GenLhashTable<Key, BucketType, Cmp>>;
155
156 public:
158
159 using Hash_Fct = std::function<size_t(const Key &)>;
160
161 using Hash_Fct_Ptr = size_t (*)(const Key &);
162
163 using Key_Type = Key;
164
165 using Item_Type = Key;
166
167 protected:
169
170 private:
171 using BucketList = Dlink; // Bucket list type
172 using BucketItor = typename Dnode<Key>::Iterator; // Bucket iterator
173 using Node = Dnode<Key>; // Node alias
174
176
177 protected:
178 size_t len; // Table size
182
183 private:
184 size_t N; // Number of elements in the table
185 size_t busy_slots_counter; // Number of occupied entries
186 bool remove_all_buckets; // free buckets in destructor
188
189 public:
190 Cmp &get_compare() { return cmp; }
191
192 const Cmp &get_compare() const { return cmp; }
193
194 protected:
196 const float lower, const float upper,
197 const bool remove_all, const bool resize)
201 N(0), busy_slots_counter(0), remove_all_buckets(remove_all),
203 {
204 table = new BucketList [len];
205 }
206
207 public:
231
232 void swap(GenLhashTable & other) noexcept
233 {
234 std::swap(hash_fct, other.hash_fct);
235 std::swap(table, other.table);
236 std::swap(len, other.len);
237 std::swap(cmp, other.cmp);
238 std::swap(N, other.N);
239 std::swap(busy_slots_counter, other.busy_slots_counter);
240 std::swap(remove_all_buckets, other.remove_all_buckets);
241 std::swap(with_resize, other.with_resize);
242 }
243
244 GenLhashTable(const GenLhashTable &) = delete;
245
247
249 : hash_fct(std::move(other.hash_fct)),
250 table(other.table),
251 len(other.len),
252 cmp(std::move(other.cmp)),
253 lower_alpha(other.lower_alpha),
254 upper_alpha(other.upper_alpha),
255 N(other.N),
256 busy_slots_counter(other.busy_slots_counter),
257 remove_all_buckets(other.remove_all_buckets),
258 with_resize(other.with_resize)
259 {
260 other.table = nullptr;
261 other.len = 0;
262 other.N = 0;
263 other.busy_slots_counter = 0;
264 }
265
267 {
268 if (this != &other)
269 {
270 if (remove_all_buckets && table != nullptr)
271 empty();
272 delete [] table;
273
274 hash_fct = std::move(other.hash_fct);
275 table = other.table;
276 len = other.len;
277 cmp = std::move(other.cmp);
278 lower_alpha = other.lower_alpha;
279 upper_alpha = other.upper_alpha;
280 N = other.N;
281 busy_slots_counter = other.busy_slots_counter;
282 remove_all_buckets = other.remove_all_buckets;
283 with_resize = other.with_resize;
284
285 other.table = nullptr;
286 other.len = 0;
287 other.N = 0;
288 other.busy_slots_counter = 0;
289 }
290 return *this;
291 }
292
295 {
296 for (size_t i = 0; i < len; ++i)
297 for (BucketItor itor(table[i]); itor.has_curr(); /* nothing */)
298 delete static_cast<Bucket *>(itor.del_ne());
299 busy_slots_counter = N = 0;
300 }
301
307 void clear() noexcept { empty(); }
308
315 bool contains(const Key & key) const noexcept { return search(key) != nullptr; }
316
317 private:
318 Bucket *
319 search_in_bucket_list(BucketList & list, const Key & key) const
320 {
321 for (BucketItor it(list); it.has_curr(); it.next_ne())
322 if (auto *bucket = static_cast<Bucket *>(it.get_curr()); cmp(key, bucket->get_key()))
323 return bucket;
324
325 return nullptr;
326 }
327
328 protected:
351 template <typename HashFunc, typename SearchKey>
353 const SearchKey & search_key) const noexcept
354 {
355 const auto bucket_idx = hash_func(search_key) % len;
356
357 for (BucketItor it(table[bucket_idx]); it.has_curr(); it.next_ne())
358 if (auto *bucket = static_cast<Bucket *>(it.get_curr());
359 cmp(bucket->get_key(), search_key))
360 return bucket;
361
362 return nullptr;
363 }
364
365 public:
367
369 void set_hash_fct(Hash_Fct fct) noexcept
370 {
371 hash_fct = fct;
372 }
373
375 {
377 }
378
380 float current_alpha() const noexcept { return 1.0 * N / len; }
381
385 {
386 const auto i = hash_fct(bucket->get_key()) % len;
387 auto & list = table[i];
388
389 if (list.is_empty()) // is table[i] list empty?
390 ++busy_slots_counter; // yes ==> update occupied counter
391
392 if (search_in_bucket_list(list, bucket->get_key()) != nullptr)
393 return nullptr;
394
395 list.append(bucket); // insert bucket at the end
396 ++N;
397
399 resize(next_prime(2 * len));
400
401 return bucket;
402 }
403
404 // Search bucket->key. If found, returns the bucket address inside the table.
405 // Otherwise, inserts and returns bucket.
407 {
408 const auto i = hash_fct(bucket->get_key()) % len;
409 auto & list = table[i];
410
411 if (list.is_empty()) // is table[i] list empty?
412 ++busy_slots_counter; // yes ==> update occupied counter
413
414 auto *p = search_in_bucket_list(list, bucket->get_key());
415 if (p != nullptr)
416 return p;
417
418 list.append(bucket); // insert bucket at the end
419 ++N;
420
422 resize(next_prime(2 * len));
423
424 return bucket;
425 }
426
429 Bucket * search(const Key & key) const noexcept
430 {
431 const auto i = hash_fct(key) % len;
432 return search_in_bucket_list(table[i], key);
433 }
434
435 private:
436 // Remove without perform resizing. This is strictly required inside
437 // the del() method of Iterator. In addition, dries the code
438 Bucket * remove_bucket(Bucket *bucket) noexcept
439 {
440 const auto idx = hash_fct(bucket->get_key()) % len;
441 bucket->del(); // remove from its collision list
442
443 if (table[idx].is_empty()) // did the list become empty?
444 --busy_slots_counter; // yes ==> update occupied lists counter
445
446 --N;
447
448 return bucket;
449 }
450
451 public:
454 Bucket * remove(Bucket *bucket) noexcept
455 { // save next collision
456 remove_bucket(bucket);
457
459 resize(next_prime(len / 2));
460
461 return bucket;
462 }
463
466 size_t resize(const size_t new_size)
467 {
468 assert(len > 0);
469
470 if (new_size == 0)
471 return len;
472
473 auto *new_table = new BucketList [new_size];
474 BucketList *old_table = table; // save current table state
475 const size_t old_size = len;
476 table = new_table; // empty table with new array
477 len = new_size;
478 busy_slots_counter = N = 0;
479
480 for (size_t i = 0; i < old_size; ++i) // reinsert buckets
481 // traverse collision list in old_table[i]
482 for (BucketItor it(old_table[i]); it.has_curr(); /* Nothing */)
483 insert(static_cast<Bucket *>(it.del_ne())); // remove and insert into table[]
484
485 delete [] old_table; // free old table memory
486
487 return len;
488 }
489
493 {
495 empty();
496
497 delete [] table;
498 }
499
502 Bucket * search_next(Bucket *bucket) const
503 {
504 assert(bucket != nullptr);
505
506 const auto i = hash_fct(bucket->get_key()) % len;
507
509 itor.set(bucket);
510
511 while (true)
512 {
513 itor.next_ne();
514
515 if (not itor.has_curr())
516 return nullptr;
517
518 if (auto *node = static_cast<Bucket *>(itor.get_curr()); cmp(bucket->get_key(), node->get_key()))
519 return node;
520 }
521 }
522
524 const size_t &capacity() const noexcept { return len; }
525
527 const size_t &size() const noexcept { return N; }
528
530 const size_t &
532
533 [[nodiscard]] constexpr bool is_empty() const noexcept { return N == 0; }
534
541 {
542 long curr_index = -1; // index in table
543 long curr_pos = 0;
544 BucketItor curr_itor; // Iterator over table[curr_index]
546
547 // Advance to the next available entry in table
549 {
550 while (true)
551 {
552 if (curr_index == hash_table->len - 1)
553 { // remain in overflow state
555 return;
556 }
557
558 ++curr_index;
559
561 {
563 curr_itor = itor;
564 return;
565 }
566 }
567 }
568
570 {
571 while (true)
572 {
574 << "hash table iterator overflow";
575
576 if (curr_index == hash_table->len - 1)
577 { // remain in overflow state
579 return;
580 }
581
582 ++curr_index;
583
585 {
587 curr_itor = itor;
588 return;
589 }
590 }
591 }
592
594 {
595 curr_itor.next_ne();
596 if (not curr_itor.has_curr())
598 curr_pos++;
599 }
600
602 {
603 curr_itor.next();
604 if (not curr_itor.has_curr())
606 curr_pos++;
607 }
608
610 {
611 while (true)
612 {
613 if (curr_index == 0)
614 { // remain in underflow state
615 curr_index = -1;
616 return;
617 }
618
619 --curr_index;
620
622 {
624 curr_itor = itor;
625 curr_itor.reset_last();
626 return;
627 }
628 }
629 }
630
632 {
633 while (true)
634 {
636 << "hash table iterator underflow";
637
638 if (curr_index == 0)
639 { // remain in underflow state
640 curr_index = -1;
641 return;
642 }
643
644 --curr_index;
645
647 {
649 curr_itor = itor;
650 curr_itor.reset_last();
651 return;
652 }
653 }
654 }
655
657 {
658 curr_itor.prev_ne();
659 if (not curr_itor.has_curr())
661 curr_pos--;
662 }
663
665 {
666 curr_itor.prev();
667 if (not curr_itor.has_curr())
669 curr_pos--;
670 }
671
672 public:
675
677 using Item_Type = Bucket *;
678
681 : hash_table(&const_cast<GenLhashTable &>(table))
682 {
683 try
684 {
686 }
687 catch (const std::overflow_error &)
688 { /* nothing to do */
689 }
690 }
691
693 Iterator() = default;
694
697 {
698 curr_index = -1;
699 curr_pos = 0;
701 }
702
705 {
706 if (hash_table->is_empty())
707 {
708 curr_index = -1;
709 curr_pos = -1;
710 return;
711 }
713 curr_pos = static_cast<long>(hash_table->N) - 1;
715 }
716
718 {
719 put_itor_at_the_end(*this);
720 }
721
724 {
725 return curr_index >= 0 and curr_index < hash_table->len;
726 }
727
737 {
738 if (not has_curr())
739 return nullptr;
740
741 return static_cast<Bucket *>(curr_itor.get_curr_ne());
742 }
743
746 {
748 << "hash table iterator underflow";
749
751 << "hash table iterator overflow";
752
753 return static_cast<Bucket *>(curr_itor.get_curr());
754 }
755
756 long get_pos() const noexcept { return curr_pos; }
757
763
764 void next()
765 {
767 << "hash table iterator overflow";
768 next_ne();
769 }
770
776
777 void prev()
778 {
780 << "hash table iterator underflow";
782 }
783
785 {
787 next();
789 return ret_val;
790 }
791 };
792 };
793
801 template <typename Key>
803
804
812 template <typename Key>
813 struct LhashBucketVtl : public Dnode<Key>
814 {
816 using Base::Base;
817
819 virtual ~LhashBucketVtl() = default;
820 };
821
835 template <typename Key, class Cmp = Aleph::equal_to<Key>>
837 struct LhashTable : public GenLhashTable<Key, LhashBucket<Key>, Cmp>
838 {
840 using Base::Base;
841 };
842
855 template <typename Key, class Cmp = Aleph::equal_to<Key>>
857 struct LhashTableVtl : public GenLhashTable<Key, LhashBucketVtl<Key>, Cmp>
858 {
860 using Base::Base;
861 };
862} // end namespace Aleph
863
864# ifdef NBACKUP
865# define N NBACKUP
866# undef NBACKUP
867# endif
868
869# ifdef MBACKUP
870# define M MBACKUP
871# undef MBACKUP
872# endif
873
874# endif/* TPL_LHASH_H */
C++20 concepts for constraining comparison functors.
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:541
void reset_last() noexcept
Reset the iterator to the last bucket.
Definition tpl_lhash.H:704
void reset_first() noexcept
Reset the iterator to the first bucket.
Definition tpl_lhash.H:696
Iterator()=default
Instantiate an empty iterator.
Bucket * get_curr()
Returns the current bucket.
Definition tpl_lhash.H:745
void locate_next_available_bucket_ne() noexcept
Definition tpl_lhash.H:593
void locate_prev_available_bucket_ne() noexcept
Definition tpl_lhash.H:656
void locate_next_available_entry_ne() noexcept
Definition tpl_lhash.H:548
void prev_ne() noexcept
Moves the iterator back by one bucket.
Definition tpl_lhash.H:772
Bucket * Item_Type
Item type returned by get_curr().
Definition tpl_lhash.H:677
void next_ne() noexcept
Advances the iterator by one bucket.
Definition tpl_lhash.H:759
Bucket * get_curr_ne() noexcept
Returns the current bucket without exception.
Definition tpl_lhash.H:736
Iterator(const GenLhashTable &table) noexcept
Instantiate an iterator over the hash table.
Definition tpl_lhash.H:680
void locate_prev_available_entry_ne() noexcept
Definition tpl_lhash.H:609
bool has_curr() const noexcept
Returns true if the iterator has a current bucket.
Definition tpl_lhash.H:723
long get_pos() const noexcept
Definition tpl_lhash.H:756
Generic hash table with collision resolution by separate chaining.
Definition tpl_lhash.H:153
Bucket * remove(Bucket *bucket) noexcept
Removes bucket from the table.
Definition tpl_lhash.H:454
GenLhashTable & operator=(const GenLhashTable &)=delete
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:384
Hash_Fct get_hash_fct() const noexcept
Definition tpl_lhash.H:366
bool contains(const Key &key) const noexcept
Checks if a key exists in the table.
Definition tpl_lhash.H:315
size_t(*)(const Key &) Hash_Fct_Ptr
Definition tpl_lhash.H:161
GenLhashTable(GenLhashTable &&other) noexcept
Definition tpl_lhash.H:248
Bucket * search_in_bucket_list(BucketList &list, const Key &key) const
Definition tpl_lhash.H:319
void clear() noexcept
Empties the container.
Definition tpl_lhash.H:307
typename Dnode< Key >::Iterator BucketItor
Definition tpl_lhash.H:172
const size_t & get_num_busy_slots() const noexcept
Returns the number of occupied entries in the array.
Definition tpl_lhash.H:531
void empty() noexcept
Empties the hash table; frees memory of all buckets.
Definition tpl_lhash.H:294
const Cmp & get_compare() const
Definition tpl_lhash.H:192
float current_alpha() const noexcept
return the current table load
Definition tpl_lhash.H:380
Bucket * remove_bucket(Bucket *bucket) noexcept
Definition tpl_lhash.H:438
const size_t & size() const noexcept
Returns the number of elements contained in the table.
Definition tpl_lhash.H:527
GenLhashTable(size_t table_size=Primes::DefaultPrime, Hash_Fct_Ptr hash_fct=Aleph::dft_hash_ptr_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:221
Bucket * search_or_insert(Bucket *bucket)
Definition tpl_lhash.H:406
void set_hash_fct(Hash_Fct fct) noexcept
Set the internal hash function.
Definition tpl_lhash.H:369
virtual ~GenLhashTable()
Frees the table memory and, if remove_all_buckets is true (specified in the constructor),...
Definition tpl_lhash.H:492
const size_t & capacity() const noexcept
Returns the table capacity.
Definition tpl_lhash.H:524
std::function< size_t(const Key &)> Hash_Fct
Definition tpl_lhash.H:159
void swap(GenLhashTable &other) noexcept
Definition tpl_lhash.H:232
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:195
Bucket * search_next(Bucket *bucket) const
Returns the next bucket that collides with bucket.
Definition tpl_lhash.H:502
Bucket * search(const Key &key) const noexcept
Search in the table for a bucket with key.
Definition tpl_lhash.H:429
constexpr bool is_empty() const noexcept
Definition tpl_lhash.H:533
GenLhashTable & operator=(GenLhashTable &&other) noexcept
Definition tpl_lhash.H:266
BucketList * table
Definition tpl_lhash.H:175
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:352
size_t resize(const size_t new_size)
Resizes the hash table to new_size and re-locates keys.
Definition tpl_lhash.H:466
void set_hash_fct(Hash_Fct_Ptr fct) noexcept
Definition tpl_lhash.H:374
CRTP mixin providing statistics and configuration for chained hash tables.
Definition hashDry.H:992
Equivalence relation constraint for equality comparators.
Definition ah-concepts.H:97
Common hash table utilities and base classes.
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
and
Check uniqueness with explicit hash + equality functors.
const float hash_default_upper_alpha
Definition hash-dry.C:40
Divide_Conquer_DP_Result< Cost > divide_and_conquer_partition_dp(const size_t groups, const size_t n, Transition_Cost_Fn transition_cost, const Cost inf=dp_optimization_detail::default_inf< Cost >())
Optimize partition DP using divide-and-conquer optimization.
const float hash_default_lower_alpha
Definition hash-dry.C:38
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:814
virtual ~LhashBucketVtl()=default
Virtual destructor.
Generic hash table with collision resolution by separate chaining and buckets with virtual destructor...
Definition tpl_lhash.H:858
Generic hash table with collision resolution by separate chaining and buckets without virtual destruc...
Definition tpl_lhash.H:838
Lazy and scalable dynamic array implementation.