Aleph-w 3.0
A C++ Library for Data Structures and Algorithms
Loading...
Searching...
No Matches
tpl_dynSetHash.H
Go to the documentation of this file.
1
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
45# ifndef TPL_DYNSETHASH_H
46# define TPL_DYNSETHASH_H
47
48# include <algorithm>
49# include <typeinfo>
50# include <ahDry.H>
51# include <ahIterator.H>
52# include <primes.H>
53# include <htlist.H>
54# include <tpl_dynArray.H>
55# include <tpl_dynMapOhash.H>
56# include <tpl_dynLhash.H>
57# include <tpl_linHash.H>
58
59
60namespace Aleph
61{
73 template <typename Key,
74 template <typename, class> class HashTable = LhashTable,
75 class Cmp = Aleph::equal_to<Key>>
77 : public HashTable<Key, Cmp>,
78 public GenericTraverse<DynHashTable<Key, HashTable, Cmp>>,
79 public LocateFunctions<DynHashTable<Key, HashTable, Cmp>, Key>,
80 public FunctionalMethods<DynHashTable<Key, HashTable, Cmp>, Key>,
81 public GenericKeys<DynHashTable<Key, HashTable, Cmp>, Key>,
82 public EqualToMethod<DynHashTable<Key, HashTable, Cmp>>,
83 public StlAlephIterator<DynHashTable<Key, HashTable, Cmp>>
84 {
85 protected:
87
88 using Bucket = typename HashTable<Key, Cmp>::Bucket;
89
90 public:
92 using Hash_Fct = typename Base::Hash_Fct;
93
94 using Hash_Fct_Ptr = typename Base::Hash_Fct_Ptr;
95
96 using Key_Type = Key;
97
98 using Item_Type = Key;
99
113 Cmp cmp = Cmp(),
114 float lower_alpha = hash_default_lower_alpha,
115 float upper_alpha = hash_default_upper_alpha)
116 : Base(len, hash_fct, cmp, lower_alpha, upper_alpha, true, true)
117 {
118 // empty
119 }
120
121 DynHashTable(size_t len, Hash_Fct hash_fct, Cmp cmp,
122 float lower_alpha, float upper_alpha)
123 : Base(len, hash_fct, cmp, lower_alpha, upper_alpha, true, true)
124 {
125 // empty
126 }
127
128 private:
129 void copy(const DynHashTable & other)
130 {
131 for (typename Base::Iterator it(other); it.has_curr(); it.next_ne())
132 {
133 auto *bucket = static_cast<Bucket *>(it.get_curr());
134 insert(bucket->get_key());
135 }
136 }
137
138 public:
155 : Base(other.len, other.hash_fct,
156 const_cast<DynHashTable &>(other).get_compare(),
157 other.lower_alpha, other.upper_alpha, true, true)
158 {
159 copy(other);
160 }
161
163 : Base(other.len, other.hash_fct, other.get_compare(),
164 other.lower_alpha, other.upper_alpha, true, true)
165 {
166 this->swap(other);
167 }
168
170
172 {
173 this->empty();
174 }
175
177 {
178 if (this == &other)
179 return *this;
180
181 this->empty();
182 copy(other);
183
184 return *this;
185 }
186
188 {
189 if (this == &other)
190 return *this;
191
192 this->empty();
193 this->swap(other);
194 return *this;
195 }
196
197 protected:
198 Key * insert_bucket(Bucket *bucket)
199 {
200 auto *ret_val = static_cast<Bucket *>(this->Base::insert(bucket));
201 if (ret_val == nullptr) // is the key in the table?
202 { // yes! ==> free bucket
203 delete bucket;
204 return nullptr;
205 }
206
207 return &ret_val->get_key();
208 }
209
210 std::pair<Key *, bool> search_or_insert_bucket(Bucket *bucket)
211 {
212 auto *ret_val = static_cast<Bucket *>(this->Base::search_or_insert(bucket));
213 if (ret_val != bucket) // is the key in the table?
214 { // yes! ==> free bucket
215 delete bucket;
216 return {&ret_val->get_key(), true};
217 }
218
219 return {&ret_val->get_key(), false};
220 }
221
222 public:
225 Key * insert(const Key & key)
226 {
227 return insert_bucket(new Bucket(key));
228 }
229
230 Key * insert(Key && key)
231 {
232 return insert_bucket(new Bucket(std::forward<Key>(key)));
233 }
234
235 Key * search_or_insert(const Key & key)
236 {
237 return get<0>(search_or_insert_bucket(new Bucket(key)));
238 }
239
240 Key * search_or_insert(Key && key)
241 {
242 return get<0>(search_or_insert_bucket(new Bucket(std::forward<Key>(key))));
243 }
244
245 // Returns true if key is already in the table. Otherwise, inserts key and
246 // returns false.
247 std::pair<Key *, bool> contains_or_insert(const Key & key)
248 {
249 return search_or_insert_bucket(new Bucket(key));
250 }
251
252 std::pair<Key *, bool> contains_or_insert(Key && key)
253 {
254 return search_or_insert_bucket(new Bucket(std::forward<Key>(key)));
255 }
256
257 Key * add(const Key & key)
258 {
259 return insert_bucket(new Bucket(key));
260 }
261
262 Key * add(Key && key)
263 {
264 return insert_bucket(new Bucket(std::forward<Key>(key)));
265 }
266
267 Key * append(const Key & key)
268 {
269 return insert_bucket(new Bucket(key));
270 }
271
272 Key * append(Key && key)
273 {
274 return insert_bucket(new Bucket(std::forward<Key>(key)));
275 }
276
284 Key * search(const Key & key) const noexcept
285 {
286 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
287 return bucket != nullptr ? &bucket->get_key() : nullptr;
288 }
289
295 bool has(const Key & key) const noexcept
296 {
297 return this->Base::search(key) != nullptr;
298 }
299
301 bool contains(const Key & key) const noexcept { return has(key); }
302
303 const Key &find(const Key & key) const
304 {
305 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
306 ah_domain_error_if(bucket == nullptr) << "Key not found in hash";
307
308 return bucket->get_key();
309 }
310
311 Key &find(const Key & key)
312 {
313 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
314
315 ah_domain_error_if(bucket == nullptr) << "Key not found in hash";
316
317 return bucket->get_key();
318 }
319
320 protected:
321 static Bucket * key_to_bucket(Key *key)
322 {
323 Bucket *ret_val = 0;
324 const auto offset = reinterpret_cast<size_t>(&ret_val->get_key());
325
326 return reinterpret_cast<Bucket *>(reinterpret_cast<size_t>(key) - offset);
327 }
328
329 public:
344 void remove(Key *key)
345 {
346 Bucket *bucket = key_to_bucket(key);
347 this->Base::remove(bucket);
348 delete bucket;
349 }
350
351 Key remove(const Key & key)
352 {
353 auto *bucket = static_cast<Bucket *>(this->Base::search(key));
354 ah_domain_error_if(bucket == nullptr) << "Key not found in hash table";
355
356 this->Base::remove(bucket);
357 auto ret_val = bucket->get_key();
358 delete bucket;
359 return ret_val;
360 }
361
362 class Iterator : public Base::Iterator
363 {
364 public:
365 using Item_Type = Key;
366
368
371
373
375 {
376 return this->Base::Iterator::get_curr_ne()->get_key();
377 }
378
380 {
381 return const_cast<Iterator *>(this)->get_curr_ne();
382 }
383
384 const Key &get_curr() const
385 {
386 return const_cast<Iterator *>(this)->get_curr();
387 }
388
389 Key &get_curr()
390 {
391 return this->Base::Iterator::get_curr()->get_key();
392 }
393
394 void del() { delete this->Base::Iterator::del(); }
395 };
396
397 const Key &get_first() const
398 {
399 return this->get_it().get_curr();
400 }
401
403 {
404 return this->get_it().get_curr();
405 }
406
407 const Key &get_last() const
408 {
409 auto it = this->get_it();
410 it.reset_last();
411 return it.get_curr();
412 }
413
414 Key &get_last()
415 {
416 auto it = this->get_it();
417 it.reset_last();
418 return it.get_curr();
419 }
420 };
421
426 template <typename Key, class Cmp = Aleph::equal_to<Key>>
427 struct DynSetLhash : public DynHashTable<Key, LhashTable, Cmp>
428 {
430 using Base::Base;
431 };
432
437 template <typename Key, class Cmp = Aleph::equal_to<Key>>
438 struct DynSetLinHash : public DynHashTable<Key, LinearHashTable, Cmp>
439 {
441 using Base::Base;
442 };
443
448 template <typename Key, class Cmp = Aleph::equal_to<Key>>
450
455 template <typename Key, typename Data,
456 template <class, class> class HashTable = LhashTable,
457 class Cmp = Aleph::equal_to<Key>>
459 : public DynHashTable<std::pair<Key, Data>,
460 HashTable, Dft_Pair_Cmp<Key, Data, Cmp>>
461 {
462 using Pair = std::pair<Key, Data>;
463
464 using Base =
466
467 using Bucket = typename Base::Bucket;
468
469 public:
470 using Hash_Fct = std::function<size_t(const Key &)>;
471 using Hash_Fct_Ptr = size_t (*)(const Key &);
472
473 private:
474 // Store the original hash function that works on Key (not Pair)
475 // This allows heterogeneous search without constructing Data()
477
478 static constexpr bool has_search_with_custom_hash =
479 requires(const DynMapHashTable *self, Hash_Fct_Ptr hf, const Key & k)
480 {
481 self->search_with_custom_hash(hf, k);
482 };
483
484 public:
485 static Data &get_data(const Key & key)
486 {
487 return key_to_pair<Key, Data>(&const_cast<Key &>(key))->second;
488 }
489
490 static const Key &get_key(Data *data_ptr)
491 {
492 return data_to_pair<Key, Data>(data_ptr)->first;
493 }
494
496
497 // using Base::Base; // no more need. But I don't remember why I put it
498 using Base::insert; // in this way, insert with a pair is exported
499 using Iterator = typename Base::Iterator;
500
502 Hash_Fct_Ptr hash_fct = dft_hash_fct,
503 Cmp cmp = Cmp(),
504 float lower_alpha = hash_default_lower_alpha,
505 float upper_alpha = hash_default_upper_alpha)
506 : Base(len, std::bind(map_hash_fct<Key, Data, Hash_Fct>,
507 hash_fct, std::placeholders::_1),
508 Dft_Pair_Cmp<Key, Data, Cmp>(cmp), lower_alpha, upper_alpha),
509 original_hash_fct(hash_fct) {}
510
514 Pair * insert(const Key & key, const Data & data)
515 {
516 return this->insert_bucket(new typename Base::Bucket(Pair(key, data)));
517 }
518
519 Pair * insert(const Key & key, Data && data)
520 {
521 return this->insert_bucket
522 (new typename Base::Bucket(Pair(key, std::forward<Data>(data))));
523 }
524
525 Pair * insert(Key && key, Data && data)
526 {
527 return this->insert_bucket
528 (new typename Base::Bucket(Pair(std::forward<Key>(key), std::forward<Data>(data))));
529 }
530
531 Pair * insert(Key && key, const Data & data)
532 {
533 return this->insert_bucket
534 (new typename Base::Bucket(Pair(std::forward<Key>(key), data)));
535 }
536
543 Pair * search(const Key & key) const noexcept
544 {
545 if constexpr (has_search_with_custom_hash)
546 {
547 auto *bucket = static_cast<Bucket *>(
548 this->search_with_custom_hash(original_hash_fct, key));
549 return bucket != nullptr ? &bucket->get_key() : nullptr;
550 }
551 else
552 return Base::search(Pair(key, Data()));
553 }
554
555 Pair * search(Key && key) const noexcept
556 {
557 if constexpr (has_search_with_custom_hash)
558 {
559 auto *bucket = static_cast<Bucket *>(
560 this->search_with_custom_hash(original_hash_fct, key));
561 return bucket != nullptr ? &bucket->get_key() : nullptr;
562 }
563 else
564 return Base::search(Pair(std::forward<Key>(key), Data()));
565 }
566
568 bool has(const Key & key) const noexcept { return search(key) != nullptr; }
569
570 bool has(Key && key) const noexcept { return search(std::forward<Key>(key)) != nullptr; }
571
573 bool contains(const Key & key) const noexcept { return has(key); }
574
575 bool contains(Key && key) const noexcept { return has(std::forward<Key>(key)); }
576
585 Data &find(const Key & key)
586 {
587 auto *pair = search(key);
588 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
589 return pair->second;
590 }
591
592 const Data &find(const Key & key) const
593 {
594 auto *pair = search(key);
595 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
596 return pair->second;
597 }
598
605 Data &operator [](const Key & key)
606 {
607 return this->search_or_insert(Pair(key, Data()))->second;
608 }
609
610 const Data &operator [](const Key & key) const
611 {
612 return this->find(key);
613 }
614
615 Data &operator [](Key && key)
616 {
617 return this->search_or_insert(Pair(std::forward<Key>(key), Data()))->second;
618 }
619
620 const Data &operator [](Key && key) const
621 {
622 return this->find(std::forward<Key>(key));
623 }
624
627 void remove_by_data(Data & data)
628 {
630 }
631
644 Data remove(const Key & key)
645 {
646 auto *pair = search(key);
647 ah_domain_error_if(pair == nullptr) << "Key not found in hash table";
648
649 auto ret_val = std::move(pair->second);
650 auto *bucket = Base::key_to_bucket(pair);
651 this->Base::Base::remove(bucket);
652 delete bucket;
653 return ret_val;
654 }
655
656 Data remove(Key && key)
657 {
658 return remove(key); // Forward to const& version
659 }
660
662 {
663 return this->template maps<Key>([](auto p) { return p.first; });
664 }
665
667 {
668 return this->template maps<Data>([](auto p) { return p.second; });
669 }
670
672 {
674 for (Iterator it(*this); it.has_curr(); it.next_ne())
675 ret.append(&it.get_curr().second);
676 return ret;
677 }
678
680 {
682 for (Iterator it(*this); it.has_curr(); it.next_ne())
683 ret.append(&it.get_curr());
684 return ret;
685 }
686 };
687
692 template <typename Key, typename Data,
693 class Cmp = Aleph::equal_to<Key>>
695
700 template <typename Key, typename Data,
701 class Cmp = Aleph::equal_to<Key>>
703
704
705 // Implementation coming from ahFunctional.H
706
707 template <typename T, template <typename> class Container>
708 inline
710 {
711 DynSetLhash<T> table(c1);
712 c2.for_each([&table](const T & item)
713 {
714 table.insert(item);
715 });
716 return table.keys();
717 }
718
719 template <typename T, template <typename> class Container = DynList>
720 inline
722 {
725 return set1.filter([&set2](const T & i) { return set2.contains(i); });
726 }
727
728 template <typename T, template <typename> class Container>
729 inline
731 {
732 return DynSetLhash<T>(c).keys();
733 }
734
735 template <typename T, template <typename> class Container>
736 inline
738 {
740 DynSetLhash<T> table;
741
742 c.for_each([&table, &ret](const T & i)
743 {
744 auto *ptr = table.insert(i);
745 if (ptr == nullptr)
746 ret.append(i);
747 });
748
749 return ret;
750 }
751
752 template <typename T, template <typename> class Container>
753 inline
755 {
757 DynSetLhash<T> table;
758
759 size_t i = 0;
760 c.for_each([&table, &ret, &i](const T & item)
761 {
762 auto *ptr = table.insert(item);
763 if (ptr == nullptr)
764 ret.append(std::pair<T, size_t>(item, i));
765 ++i;
766 });
767
768 return ret;
769 }
770} // end namespace Aleph
771
772# endif // TPL_DYNSETHASH_H
#define ah_domain_error_if(C)
Throws std::domain_error if condition holds.
Definition ah-errors.H:522
DRY (Don't Repeat Yourself) utilities and macros.
#define Special_Ctors(Set_Type, Type)
Generates special constructors for containers.
Definition ahDry.H:113
Iterator traits and STL-compatible iterator wrappers.
const Key & get_curr_ne() const noexcept
Iterator() noexcept=default
Default constructor creates an "end" iterator.
Self-adjusting dynamic hash table.
Key * add(const Key &key)
Key * search_or_insert(const Key &key)
Key * search(const Key &key) const noexcept
Searches for a key in the hash table.
Key * insert_bucket(Bucket *bucket)
Key * append(const Key &key)
std::pair< Key *, bool > search_or_insert_bucket(Bucket *bucket)
bool contains(const Key &key) const noexcept
Alias for has()
typename HashTable< Key, Cmp >::Bucket Bucket
DynHashTable(DynHashTable &&other) noexcept
void copy(const DynHashTable &other)
DynHashTable(const DynHashTable &other)
Copy constructor.
HashTable< Key, Cmp > Base
void remove(Key *key)
Removes a key from the hash table using its pointer.
const Key & get_last() const
DynHashTable & operator=(const DynHashTable &other)
Key * insert(const Key &key)
Inserts key into the hash set.
static Bucket * key_to_bucket(Key *key)
std::pair< Key *, bool > contains_or_insert(Key &&key)
Key * insert(Key &&key)
const Key & find(const Key &key) const
Key remove(const Key &key)
typename Base::Hash_Fct Hash_Fct
Hash function type.
DynHashTable(size_t len, Hash_Fct hash_fct, Cmp cmp, float lower_alpha, float upper_alpha)
typename Base::Hash_Fct_Ptr Hash_Fct_Ptr
Key * add(Key &&key)
DynHashTable(size_t len=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)
Creates a dynamic linear hash table.
std::pair< Key *, bool > contains_or_insert(const Key &key)
bool has(const Key &key) const noexcept
Checks if a key exists in the hash table.
Key * append(Key &&key)
const Key & get_first() const
Key & find(const Key &key)
Key * search_or_insert(Key &&key)
Dynamic singly linked list with functional programming support.
Definition htlist.H:1423
T & append(const T &item)
Append a new item by copy.
Definition htlist.H:1562
bool has(Key &&key) const noexcept
Data & operator[](const Key &key)
Subscript operator for map access/insertion.
void remove_by_data(Data &data)
Removes from the table the key whose pointer must be the result of a prior insertion or search.
DynMapHashTable(size_t len=Primes::DefaultPrime, Hash_Fct_Ptr hash_fct=dft_hash_fct, Cmp cmp=Cmp(), float lower_alpha=hash_default_lower_alpha, float upper_alpha=hash_default_upper_alpha)
Hash_Fct_Ptr original_hash_fct
size_t(*)(const Key &) Hash_Fct_Ptr
Pair * insert(Key &&key, Data &&data)
static const Key & get_key(Data *data_ptr)
DynList< Data * > values_ptr()
DynList< Key > values() const
bool has(const Key &key) const noexcept
Checks if a key exists in the map.
const Data & find(const Key &key) const
Pair * insert(Key &&key, const Data &data)
std::pair< Key, Data > Pair
Pair * insert(const Key &key, const Data &data)
Inserts into the hash map the pair (key, record) indexed by key.
Data remove(const Key &key)
Removes a key-value pair from the map and returns the value.
bool contains(Key &&key) const noexcept
typename Base::Bucket Bucket
Pair * search(Key &&key) const noexcept
typename Base::Iterator Iterator
bool contains(const Key &key) const noexcept
Alias for has()
DynList< Pair * > items_ptr()
Pair * search(const Key &key) const noexcept
Searches for key and, if found, returns a pointer to the associated pair stored in the table.
std::function< size_t(const Key &)> Hash_Fct
DynList< Key > keys() const
Data & find(const Key &key)
Finds and returns a reference to the value associated with key.
static Data & get_data(const Key &key)
static constexpr bool has_search_with_custom_hash
Pair * insert(const Key &key, Data &&data)
Equality test for containers.
Definition ah-dry.H:1534
Common methods to the Aleph-w ( ) containers.
Definition ah-dry.H:548
Aleph::DynList< T > filter(Operation &operation) const
Filter the elements of a container according to a matching criteria.
Definition ah-dry.H:1135
void for_each(Operation &operation)
Traverse all the container and performs an operation on each element.
Definition ah-dry.H:685
Aleph::DynList< __T > maps(Operation &op) const
Map the elements of the container.
Definition ah-dry.H:904
Common sequential searching methods on containers.
Definition ah-dry.H:164
auto get_it() const
Return a properly initialized iterator positioned at the first item on the container.
Definition ah-dry.H:190
Mixin that adds STL begin()/end() and cbegin()/cend() to Aleph containers.
int cmp(const __gmp_expr< T, U > &expr1, const __gmp_expr< V, W > &expr2)
Definition gmpfrxx.h:4118
Singly linked list implementations with head-tail access.
const long double offset[]
Offset values indexed by symbol string length (bounded by MAX_OFFSET_INDEX)
Main namespace for Aleph-w library functions.
Definition ah-arena.H:89
size_t map_hash_fct(Fct fct, const std::pair< Key, Data > &p) noexcept
Definition hash-fct.H:949
Itor unique(Itor __first, Itor __last, BinaryPredicate __binary_pred=BinaryPredicate())
Remove consecutive duplicates in place.
Definition ahAlgo.H:1058
T & swap(T &t1, T &t2)
Generic swap using object's swap method.
Definition ahTypes.H:121
DynList< T > intercept(const Container< T > &c1, const Container< T > &c2)
DynList< std::pair< T, size_t > > repeated_with_index(const Container< T > &c)
DynList< T > repeated(const Container< T > &c)
const float hash_default_upper_alpha
Definition hash-dry.C:40
std::decay_t< typename HeadC::Item_Type > T
Definition ah-zip.H:107
std::pair< First, Second > pair
Alias to std::pair kept for backwards compatibility.
Definition ahPair.H:89
size_t dft_hash_fct(const Key &key) noexcept
Definition hash-fct.H:931
std::ostream & join(const C &c, const std::string &sep, std::ostream &out)
Join elements of an Aleph-style container into a stream.
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
STL namespace.
Prime number utilities for hash tables and mathematical operations.
Default comparator for pair types in hash maps.
Definition ahDry.H:190
DynHashTable< Key, LhashTable, Cmp > Base
DynHashTable< Key, LinearHashTable, Cmp > Base
Generic hash table with collision resolution by separate chaining and buckets without virtual destruc...
Definition tpl_lhash.H:809
Generic list of items stored in a container.
Definition ah-dry.H:1501
Aleph::DynList< T > keys() const
Definition ah-dry.H:1516
Generic traversal of the container through its iterator.
Definition ah-dry.H:65
Lazy and scalable dynamic array implementation.
Dynamic hash table mapping keys to records with separate chaining.
Dynamic map with open hashing.
Linear hashing with chaining.