libhatchet
Loading...
Searching...
No Matches
hxhash_table.hpp
Go to the documentation of this file.
1#pragma once
2// SPDX-FileCopyrightText: © 2017-2026 Adrian Johnston.
3// SPDX-License-Identifier: MIT
4// This file is licensed under the MIT license found in the LICENSE.md file.
5
9
10#include "libhatchet.h"
11
12// HX_USE_MACROS_WITH_MODULE allows including macros alongside the module.
13#if HX_USE_MACROS_WITH_MODULE
14#error Header does not provide macros alone.
15#endif
16
17#include "hxkey.hpp"
18#include "hxptr.hpp"
19#include "hxallocator.hpp"
20
21HX_NS_BEGIN_
22
23#include "detail/hxpow2_allocator.hpp"
24
25#if HX_CPLUSPLUS >= 202002L
28template<typename node_t_>
30 requires(node_t_& node_, const node_t_& const_node_) {
31 sizeof(node_t_);
32 sizeof(typename node_t_::key_t);
33 node_.set_hash_next(static_cast<node_t_*>(hxnull));
34 { const_node_.hash_next() } -> hxsame_as<node_t_*>;
35 { const_node_.hash_key() } -> hxconvertible_to<const typename node_t_::key_t&>;
36 { const_node_.hash_value() } -> hxconvertible_to<hxhash_t>;
37 };
38#else
39#define hxhash_table_concept_ typename
40#endif
41
47template<typename key_t_>
49public:
50 using key_t = key_t_;
51
54 template<typename ref_t_>
55 hxhash_table_set_node(ref_t_&& key_)
56 : m_hash_next_(hxnull), m_key_(hxforward<ref_t_>(key_)), m_hash_(hxkey_hash(m_key_)) { }
57
60 : m_hash_next_(hxnull), m_key_(src_.m_key_), m_hash_(src_.m_hash_) { }
61
63 hxhash_table_set_node* hash_next(void) const { return m_hash_next_; }
64
67 void set_hash_next(hxhash_table_set_node* next_) { m_hash_next_ = next_; }
68
70 const key_t_& hash_key(void) const { return m_key_; }
71
74 hxhash_t hash_value(void) const { return m_hash_; }
75
79 static hxhash_t hash_value(const key_t_& key_) { return hxkey_hash(key_); }
80
81private:
82 hxhash_table_set_node(void) = delete;
83 // Deleted for being bug prone.
84 hxhash_table_set_node& operator=(const hxhash_table_set_node& n_) = delete;
85
86 hxhash_table_set_node* m_hash_next_;
87 key_t_ m_key_;
88 hxhash_t m_hash_;
89};
90
92template<typename key_t_, typename value_t_>
94public:
95 using key_t = key_t_;
96 using value_t = value_t_;
97
101 hxhash_table_map_node(const key_t_& key_) :
102 hxhash_table_set_node<key_t_>(key_) { }
103
107 template<typename ref_t_>
108 hxhash_table_map_node(const key_t_& key_, ref_t_&& value_) :
109 hxhash_table_set_node<key_t_>(key_), m_value_(hxforward<ref_t_>(value_)) { }
110
116
118 const value_t_& value(void) const { return m_value_; }
119
121 value_t_& value(void) { return m_value_; }
122
123private:
124 value_t_ m_value_;
125};
126
177template<hxhash_table_concept_ node_t_,
178 typename deleter_t_=hxdefault_delete,
179 bool multi_t_ = false,
180 uint32_t table_size_bits_=hxallocator_dynamic_capacity>
181class hxhash_table : private deleter_t_ {
182public:
183 using node_t = node_t_;
184 using key_t = typename node_t_::key_t;
185
192 {
193 public:
195 const_iterator(void) : m_next_bucket_(hxnull), m_bucket_end_(hxnull),
196 m_current_node_(hxnull) { }
197
200 const_iterator operator++(int) { const_iterator t_(*this); operator++(); return t_; }
203 bool operator==(const const_iterator& x_) const;
204#if HX_CPLUSPLUS < 202002L // C++20 defaults != from ==.
207 bool operator!=(const const_iterator& x_) const { return !(*this == x_); }
208#endif
210 const node_t_& operator*(void) const;
212 const node_t_* operator->(void) const;
213 private:
215 friend class hxhash_table;
216 const_iterator(const hxhash_table* table_);
217 const_iterator(const hxhash_table* table_, node_t_* node_);
218 void next_bucket_(void);
219 node_t_** m_next_bucket_;
220 node_t_** m_bucket_end_;
221 protected:
222 node_t_* m_current_node_;
224 };
225
229 {
230 public:
235 iterator(void) { }
239 iterator operator++(int) { iterator t_(*this); const_iterator::operator++(); return t_; }
241 node_t_& operator*(void) const;
243 node_t_* operator->(void) const;
244 private:
245 friend class hxhash_table;
246 iterator(hxhash_table* table_, node_t_* node_) : const_iterator(table_, node_) { }
247 };
248
252 explicit hxhash_table(deleter_t_ deleter_=deleter_t_());
253
255 ~hxhash_table(void) { this->clear(this->deleter()); }
256
258 const_iterator begin(void) const { return const_iterator(this); }
259
261 iterator begin(void) { return iterator(this); }
262
264 hxattr_nodiscard hxsize_t bucket_count(void) const { return m_table_.capacity(); }
265
267 const_iterator cbegin(void) const { return const_iterator(this); }
268
270 const_iterator cend(void) const { return const_iterator(); }
271
275 template<typename deleter_u_>
276 void clear(deleter_u_&& deleter_) noexcept;
277
279 void clear(void) noexcept { this->clear(this->deleter()); }
280
283 hxattr_nodiscard hxsize_t count(const typename node_t_::key_t& key_) const;
284
293 bool multi_=multi_t_, class... args_t_>
294 hxenable_if_t<multi_, iterator> emplace(args_t_&&... args_) noexcept;
295
297 hxattr_nodiscard bool empty(void) const { return m_size_ == 0; }
298
300 const_iterator end(void) const { return const_iterator(); }
301
303 iterator end(void) { return iterator(); }
304
311 template<typename deleter_u_>
312 hxsize_t erase(const typename node_t_::key_t& key_, deleter_u_&& deleter_) noexcept;
313
316 hxsize_t erase(const typename node_t_::key_t& key_) noexcept;
317
321 iterator erase(const const_iterator& it_) noexcept;
322
326 hxptr<node_t_, deleter_t_> extract(const typename node_t_::key_t& key_) noexcept;
327
335 const typename node_t_::key_t& key_, const node_t_* previous_=hxnull);
336
341 const typename node_t_::key_t& key_, const node_t_* previous_=hxnull) const;
342
344 hxattr_nodiscard const deleter_t_& deleter(void) const;
345
347 hxattr_nodiscard deleter_t_& deleter(void);
348
354 iterator insert(node_t_* ptr_) noexcept;
355
361 template<typename deleter_u_>
363
365 hxattr_nodiscard float load_factor(void) const;
366
369
371 void release_all(void);
372
375 hxsize_t release_key(const typename node_t_::key_t& key_);
376
383 hxptr<node_t_, deleter_t_> replace(node_t_* ptr_) noexcept;
384
389
391 hxattr_nodiscard hxsize_t size(void) const { return m_size_; }
392
403 bool multi_=multi_t_, class... args_t_>
404 hxenable_if_t<!multi_, iterator> try_emplace(
405 const typename node_t_::key_t& key_, args_t_&&... args_) noexcept;
406
407private:
408 static_assert(table_size_bits_ < hxhash_bits, "Hash bits must be [0..hxhash_bits)");
409
410 // Deleted for being bug prone.
411 hxhash_table(const hxhash_table&) = delete;
412
413 node_t_** get_bucket_head_(hxhash_t hash_);
414 const node_t_*const* get_bucket_head_(hxhash_t hash_) const;
415
416 hxsize_t m_size_;
417 hxdetail_::hxpow2_allocator_<node_t_*, table_size_bits_, true> m_table_;
418};
419
420#include "detail/hxhash_table.inl"
421HX_NS_END_
hxdefault_delete - A callable that deletes objects of type T using hxdelete.
Definition hxmemory_manager.h:254
const_iterator - A const forward iterator over the elements of the hash table.
Definition hxhash_table.hpp:192
bool operator==(const const_iterator &x_) const
Compares two iterators for equality.
const node_t_ * operator->(void) const
Dereferences the iterator to access the current node_t's pointer.
const_iterator operator++(int)
Advances the iterator to the next element (post-increment).
Definition hxhash_table.hpp:200
const_iterator(void)
Constructs an iterator pointing to the end of the hash table.
Definition hxhash_table.hpp:195
const_iterator & operator++(void)
Advances the iterator to the next element.
const node_t_ & operator*(void) const
Dereferences the iterator to access the current node_t.
iterator - A mutable iterator that can modify the elements of the hash table.
Definition hxhash_table.hpp:229
node_t_ & operator*(void) const
Dereferences the iterator to access the current node_t.
iterator(void)
Constructs an iterator pointing to the end of the hash table.
Definition hxhash_table.hpp:235
friend class hxhash_table
Definition hxhash_table.hpp:245
iterator(hxhash_table *tbl_)
Constructs an iterator pointing to the beginning of the hash table.
Definition hxhash_table.hpp:233
iterator operator++(int)
Advances the iterator to the next element (post-increment).
Definition hxhash_table.hpp:239
iterator & operator++(void)
Advances the iterator to the next element.
Definition hxhash_table.hpp:237
node_t_ * operator->(void) const
Dereferences the iterator to access the current node_t's pointer.
hxhash_table_map_node(const key_t_ &key_)
Default-initializes a node.
Definition hxhash_table.hpp:101
hxhash_table_map_node(const key_t_ &key_, ref_t_ &&value_)
Constructs a node whose value is copy- or move-initialized.
Definition hxhash_table.hpp:108
const value_t_ & value(void) const
Returns the stored value.
Definition hxhash_table.hpp:118
value_t_ & value(void)
Returns the stored value, allowing mutation.
Definition hxhash_table.hpp:121
hxhash_table_map_node * hash_next(void) const
Returns the next node in the table's embedded linked list.
Definition hxhash_table.hpp:112
key_t_ key_t
Definition hxhash_table.hpp:95
value_t_ value_t
Definition hxhash_table.hpp:96
hxhash_table_set_node - Optional base class for unordered set entries.
Definition hxhash_table.hpp:48
hxhash_t hash_value(void) const
Returns the cached hash value for the stored key.
Definition hxhash_table.hpp:74
const key_t_ & hash_key(void) const
The key and hash identify the node_t and should not change once added.
Definition hxhash_table.hpp:70
hxhash_table_set_node(ref_t_ &&key_)
Constructs a node from the key and caches its hash for reuse.
Definition hxhash_table.hpp:55
static hxhash_t hash_value(const key_t_ &key_)
Returns the hash value computed for key.
Definition hxhash_table.hpp:79
key_t_ key_t
Definition hxhash_table.hpp:50
void set_hash_next(hxhash_table_set_node *next_)
Sets the next node in the table's embedded linked list.
Definition hxhash_table.hpp:67
hxhash_table_set_node * hash_next(void) const
Returns the next node in the table's embedded linked list.
Definition hxhash_table.hpp:63
hxhash_table_set_node(const hxhash_table_set_node &src_)
Constructs an unlinked node with the same key.
Definition hxhash_table.hpp:59
const deleter_t_ & deleter(void) const
Returns a const reference to the stored deleter.
const node_t_ * find(const typename node_t_::key_t &key_, const node_t_ *previous_=0) const
const version of find.
void clear(deleter_u_ &&deleter_) noexcept
Removes all nodes and if deleter is true then calls deleter() on every node.
bool empty(void) const
Checks if the hash table is empty.
Definition hxhash_table.hpp:297
~hxhash_table(void)
Destructs the hash table and deletes all resources.
Definition hxhash_table.hpp:255
hxhash_table(deleter_t_ deleter_=deleter_t_())
Constructs an empty hash table with a capacity of 2^table_size_bits and an optional deleter instance.
hxsize_t bucket_count(void) const
Returns the number of buckets in the hash table.
Definition hxhash_table.hpp:264
hxenable_if_t<!multi_, iterator > try_emplace(const typename node_t_::key_t &key_, args_t_ &&... args_) noexcept
try_emplace - Returns an iterator to the node if it was inserted, or an iterator to the existing node...
iterator erase(const const_iterator &it_) noexcept
Removes the node_t referenced by it without invoking the deleter.
hxsize_t erase(const typename node_t_::key_t &key_) noexcept
Removes and calls the stored deleter on nodes with an equivalent key.
hxsize_t count(const typename node_t_::key_t &key_) const
Counts the number of nodes with the given key.
deleter_t_ & deleter(void)
Returns a reference to the stored deleter.
hxptr< node_t_, deleter_t_ > replace(node_t_ *ptr_) noexcept
replace - Replaces the first node_t matching ptr's key, if any, with ptr and returns an hxptr owning ...
iterator insert(hxptr< node_t_, deleter_u_ > &&ptr_) noexcept
insert - Returns an iterator to the inserted node.
hxsize_t release_key(const typename node_t_::key_t &key_)
Removes all nodes matching the given key without deleting them.
hxsize_t size(void) const
Returns the number of elements in the hash table.
Definition hxhash_table.hpp:391
iterator end(void)
Returns an iterator pointing to the end of the hash table.
Definition hxhash_table.hpp:303
hxptr< node_t_, deleter_t_ > extract(const typename node_t_::key_t &key_) noexcept
extract - Returns an hxptr owning the first node_t with the given key, or an empty hxptr if no matchi...
iterator begin(void)
Returns an iterator pointing to the beginning of the hash table.
Definition hxhash_table.hpp:261
const_iterator cbegin(void) const
Returns a const iterator pointing to the beginning of the hash table.
Definition hxhash_table.hpp:267
node_t_ node_t
Definition hxhash_table.hpp:183
iterator insert(node_t_ *ptr_) noexcept
insert - Returns an iterator to the inserted node.
node_t_ * find(const typename node_t_::key_t &key_, const node_t_ *previous_=0)
Returns a node_t matching key if any.
const_iterator end(void) const
Returns a const iterator pointing to the end of the hash table.
Definition hxhash_table.hpp:300
const_iterator begin(void) const
Returns a const iterator pointing to the beginning of the hash table.
Definition hxhash_table.hpp:258
const_iterator cend(void) const
Returns a const iterator pointing to the end of the hash table.
Definition hxhash_table.hpp:270
void release_all(void)
Clears the hash table without deleting any nodes.
hxsize_t erase(const typename node_t_::key_t &key_, deleter_u_ &&deleter_) noexcept
Releases all nodes matching key and calls deleter on every node.
hxsize_t load_max(void) const
Returns the size of the largest bucket.
void set_size_bits(hxhash_t bits_)
Sets the number of hash bits and allocate memory for the table.
void clear(void) noexcept
Removes all nodes and calls the stored deleter on every node.
Definition hxhash_table.hpp:279
typename node_t_::key_t key_t
Definition hxhash_table.hpp:184
float load_factor(void) const
Returns the average number of nodes per bucket.
hxenable_if_t< multi_, iterator > emplace(args_t_ &&... args_) noexcept
emplace - Returns an iterator to the node constructed with hxnew.
hxptr<T, deleter_t> - A unique owning pointer.
Definition hxptr.hpp:30
hxconvertible_to - A concept that requires one type to be convertible to another.
Definition hxkey.hpp:41
hxhash_table_concept - Concept capturing the interface requirements for hxhash_table nodes.
Definition hxhash_table.hpp:29
hxsame_as - A concept that requires two types to be the same.
Definition hxkey.hpp:51
Similar to std::allocator.
HX_NS_BEGIN_ constexpr hxsize_t hxallocator_dynamic_capacity
hxallocator_dynamic_capacity - A capacity value that allows for dynamic allocation.
Definition hxallocator.hpp:20
User-overloadable key-equal, key-less, and key-hash functions.
hxhash_t hxkey_hash(T x_)
hxkey_hash(T) - Returns the xxhash32 of a numeric value cast to 32 bits.
Definition hxkey.hpp:165
@ hxsystem_allocator_current
hxsystem_allocator_current - Use current allocation scope.
Definition hxmemory_manager.h:82
int hxsystem_allocator_t
hxsystem_allocator_t - This is extendable by the application.
Definition hxmemory_manager.h:77
unsigned int hxalignment_t
hxalignment_t - A positive integer power of 2 for aligning allocations.
Definition hxmemory_manager.h:64
constexpr hxalignment_t hxalignment
hxalignment - The default alignment.
Definition hxmemory_manager.h:69
A unique owning pointer.
#define hxattr_nodiscard
hxattr_nodiscard - Indicates the caller should not discard the return value.
Definition hxsettings.h:89
#define hxattr_flatten
hxattr_flatten - Inline every call inside a function's body into it, recursively, regardless of the c...
Definition hxsettings.h:82
constexpr T && hxforward(hxremove_reference_t< T > &&x_)
hxforward - Implements std::forward.
Definition hxutility.h:304
Provides core macros, memory management and feature detection.
constexpr hxhash_t hxhash_bits
hxhash_bits - Number of bits in hxhash_t.
Definition libhatchet.h:282
#define hxnull
hxnull - The null pointer value for a given pointer type represented by the numeric constant 0.
Definition libhatchet.h:277
uint32_t hxhash_t
hxhash_t - Unsigned 32-bit hash value. Expect collisions.
Definition libhatchet.h:212
ptrdiff_t hxsize_t
hxsize_t - A signed size type, same as ssize_t or ptrdiff_t.
Definition libhatchet.h:209