nfx-containers 0.6.0
Modern C++20 header-only library providing high-performance hash containers with Robin Hood and perfect hashing
Loading...
Searching...
No Matches
FastHashSet.h
Go to the documentation of this file.
1/*
2 * MIT License
3 *
4 * Copyright (c) 2025 nfx
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24
31
32#pragma once
33
34#include "nfx/detail/containers/CompilerSupport.h"
35
36#include <nfx/Hashing.h>
37
38#include <algorithm>
39#include <concepts>
40#include <cstddef>
41#include <cstdint>
42#include <functional>
43#include <initializer_list>
44#include <iterator>
45#include <stdexcept>
46#include <string>
47#include <string_view>
48#include <type_traits>
49#include <utility>
50#include <vector>
51
52namespace nfx::containers
53{
54 //=====================================================================
55 // FastHashSet class
56 //=====================================================================
57
66 template <typename TKey,
67 hashing::Hash32or64 HashType = uint32_t,
68 HashType Seed = ( sizeof( HashType ) == 4 ? hashing::constants::FNV_OFFSET_BASIS_32 : hashing::constants::FNV_OFFSET_BASIS_64 ),
69 typename THasher = hashing::Hasher<HashType, Seed>,
70 typename KeyEqual = std::equal_to<>>
71 class FastHashSet final
72 {
73 //----------------------------------------------
74 // Compile-time type constraints
75 //----------------------------------------------
76
77 static_assert( std::is_same_v<HashType, uint32_t> || std::is_same_v<HashType, uint64_t>,
78 "HashType must be uint32_t or uint64_t" );
79
80 static_assert( std::is_invocable_r_v<HashType, THasher, TKey>,
81 "THasher must be callable with TKey and return HashType" );
82
83 static_assert( std::is_invocable_r_v<bool, KeyEqual, TKey, TKey>,
84 "KeyEqual must be callable with two TKey arguments and return bool" );
85
86 public:
87 //----------------------------------------------
88 // Forward declarations for iterator support
89 //----------------------------------------------
90
91 class Iterator;
92 class ConstIterator;
93
94 //----------------------------------------------
95 // STL-compatible type aliases
96 //----------------------------------------------
97
99 using key_type = TKey;
100
102 using value_type = TKey;
103
105 using hasher = THasher;
106
108 using key_equal = KeyEqual;
109
111 using hash_type = HashType;
112
114 using size_type = size_t;
115
117 using difference_type = std::ptrdiff_t;
118
121
124
125 //----------------------------------------------
126 // Construction
127 //----------------------------------------------
128
134 inline FastHashSet();
135
140 inline FastHashSet( std::initializer_list<TKey> init );
141
148 template <typename InputIt>
149 inline FastHashSet( InputIt first, InputIt last );
150
157 inline explicit FastHashSet( size_t initialCapacity );
158
163 inline FastHashSet( FastHashSet&& other ) noexcept;
164
170 inline FastHashSet& operator=( FastHashSet&& other ) noexcept;
171
175 FastHashSet( const FastHashSet& ) = default;
176
181 FastHashSet& operator=( const FastHashSet& ) = default;
182
186 ~FastHashSet() = default;
187
188 //----------------------------------------------
189 // Core operations
190 //----------------------------------------------
191
199 template <typename KeyType = TKey>
200 [[nodiscard]] inline const TKey* find( const KeyType& key ) const noexcept;
201
209 template <typename KeyType = TKey>
210 [[nodiscard]] inline bool contains( const KeyType& key ) const noexcept;
211
220 template <typename KeyType = TKey>
221 inline const TKey& at( const KeyType& key ) const;
222
223 //----------------------------------------------
224 // Insertion
225 //----------------------------------------------
226
232 inline bool insert( const TKey& key );
233
239 inline bool insert( TKey&& key );
240
241 //----------------------------------------------
242 // Emplace operations
243 //----------------------------------------------
244
252 template <typename... Args>
253 inline bool emplace( Args&&... args );
254
262 template <typename... Args>
263 inline std::pair<Iterator, bool> tryEmplace( Args&&... args );
264
265 //----------------------------------------------
266 // Capacity and memory management
267 //----------------------------------------------
275 inline void reserve( size_t minCapacity );
276
283 template <typename KeyType = TKey>
284 inline bool erase( const KeyType& key ) noexcept;
285
292 inline Iterator erase( ConstIterator pos ) noexcept;
293
300 inline Iterator erase( ConstIterator first, ConstIterator last ) noexcept;
301
305 inline void clear() noexcept;
306
316 template <typename KeyType = TKey>
317 [[nodiscard]] inline std::optional<TKey> extract( const KeyType& key );
318
326 inline void merge( FastHashSet& other );
327
332 inline void merge( FastHashSet&& other );
333
334 //----------------------------------------------
335 // State inspection
336 //----------------------------------------------
337
343 [[nodiscard]] inline size_t size() const noexcept;
344
350 [[nodiscard]] inline size_t capacity() const noexcept;
351
357 [[nodiscard]] inline bool isEmpty() const noexcept;
358
364 inline void swap( FastHashSet& other ) noexcept;
365
366 //----------------------------------------------
367 // STL-compatible iteration support
368 //----------------------------------------------
369
375 [[nodiscard]] Iterator begin() noexcept;
376
382 [[nodiscard]] ConstIterator begin() const noexcept;
383
389 [[nodiscard]] Iterator end() noexcept;
390
396 [[nodiscard]] ConstIterator end() const noexcept;
397
403 [[nodiscard]] ConstIterator cbegin() const noexcept;
404
410 [[nodiscard]] ConstIterator cend() const noexcept;
411
418 [[nodiscard]] bool operator==( const FastHashSet& other ) const noexcept;
419
420 private:
421 //----------------------------------------------
422 // Robin Hood Hashing bucket structure
423 //----------------------------------------------
424
428 struct Bucket
429 {
430 std::optional<TKey> data;
431 HashType hash{};
432 uint32_t distance{};
433 bool occupied{};
434 };
435
441 static constexpr size_t INITIAL_CAPACITY = 32;
442
448 static constexpr size_t MAX_LOAD_FACTOR_PERCENT = 75;
449
455 std::vector<Bucket> m_buckets;
456
457 size_t m_size{};
458 size_t m_capacity{ INITIAL_CAPACITY };
459 size_t m_mask{ INITIAL_CAPACITY - 1 };
460
468 NFX_CONTAINERS_NO_UNIQUE_ADDRESS hasher m_hasher;
469
475 NFX_CONTAINERS_NO_UNIQUE_ADDRESS KeyEqual m_keyEqual;
476
477 //----------------------------------------------
478 // Internal implementation
479 //----------------------------------------------
480
486 inline bool insertInternal( const TKey& key );
487
493 inline bool insertInternal( TKey&& key );
494
499 inline bool shouldResize() const noexcept;
500
504 inline void resize();
505
510 inline void eraseAtPosition( size_t pos ) noexcept;
511
520 template <typename KeyType1, typename KeyType2>
521 inline bool keysEqual( const KeyType1& k1, const KeyType2& k2 ) const noexcept;
522
523 public:
524 //----------------------------------------------
525 // FastHashSet::Iterator class
526 //----------------------------------------------
527
534 {
535 friend class ConstIterator;
536
537 public:
539 using iterator_category = std::forward_iterator_tag;
540
542 using value_type = const TKey;
543
545 using difference_type = std::ptrdiff_t;
546
548 using pointer = const TKey*;
549
551 using reference = const TKey&;
552
553 //---------------------------
554 // Construction
555 //---------------------------
556
560 Iterator() = default;
561
567 inline Iterator( Bucket* bucket, Bucket* end );
568
569 //---------------------------
570 // Operations
571 //---------------------------
572
577 inline reference operator*() const;
578
583 inline pointer operator->() const;
584
590
595 inline Iterator operator++( int );
596
597 //---------------------------
598 // Comparison
599 //---------------------------
600
606 inline bool operator==( const Iterator& other ) const;
607
613 inline bool operator!=( const Iterator& other ) const;
614
615 private:
616 //---------------------------
617 // Private methods
618 //---------------------------
619
624 inline void skipToOccupied();
625
626 //---------------------------
627 // Private members
628 //---------------------------
629
630 Bucket* m_bucket = nullptr;
631 Bucket* m_end = nullptr;
632 };
633
634 //----------------------------------------------
635 // FastHashSet::ConstIterator class
636 //----------------------------------------------
637
644 {
645 friend class FastHashSet;
646
647 public:
649 using iterator_category = std::forward_iterator_tag;
650
652 using value_type = const TKey;
653
655 using difference_type = std::ptrdiff_t;
656
658 using pointer = const TKey*;
659
661 using reference = const TKey&;
662
663 //---------------------------
664 // Construction
665 //---------------------------
666
670 ConstIterator() = default;
671
677 inline ConstIterator( const Bucket* bucket, const Bucket* end );
678
683 inline ConstIterator( const Iterator& it );
684
685 //---------------------------
686 // Operations
687 //---------------------------
688
693 inline reference operator*() const;
694
699 inline pointer operator->() const;
700
706
712
713 //---------------------------
714 // Comparison
715 //---------------------------
716
722 inline bool operator==( const ConstIterator& other ) const;
723
729 inline bool operator!=( const ConstIterator& other ) const;
730
731 private:
732 //---------------------------
733 // Private methods
734 //---------------------------
735
740 inline void skipToOccupied();
741
742 //---------------------------
743 // Private members
744 //---------------------------
745
746 const Bucket* m_bucket = nullptr;
747 const Bucket* m_end = nullptr;
748 };
749 };
750} // namespace nfx::containers
751
752#include "nfx/detail/containers/FastHashSet.inl"
void merge(FastHashSet &other)
Merge elements from another set into this set.
FastHashSet(InputIt first, InputIt last)
Construct set from iterator range.
KeyEqual key_equal
Type alias for key equality comparator.
~FastHashSet()=default
Destructor.
HashType hash_type
Type alias for hash type (uint32_t or uint64_t).
THasher hasher
Type alias for hasher type.
ConstIterator cbegin() const noexcept
Get const iterator to beginning of occupied buckets (explicit const).
Iterator erase(ConstIterator first, ConstIterator last) noexcept
Erase range of elements.
void clear() noexcept
Clear all elements from the set.
Iterator erase(ConstIterator pos) noexcept
Erase element at iterator position.
FastHashSet()
Default constructor with initial capacity of 32 elements.
const TKey & at(const KeyType &key) const
Checked element access with bounds checking.
bool insert(const TKey &key)
Insert a key into the set (copy semantics).
std::pair< Iterator, bool > tryEmplace(Args &&... args)
Try to emplace a key if it doesn't exist.
std::optional< TKey > extract(const KeyType &key)
Extract and remove a key from the set.
Iterator begin() noexcept
Get iterator to beginning of occupied buckets.
TKey value_type
Type alias for value type (same as key for sets).
bool isEmpty() const noexcept
Check if the set is empty.
size_t size() const noexcept
Get the number of elements in the set.
ConstIterator cend() const noexcept
Get const iterator to end (explicit const).
void swap(FastHashSet &other) noexcept
Swap contents with another set.
size_t size_type
Type alias for size type.
ConstIterator const_iterator
Type alias for const iterator.
const TKey * find(const KeyType &key) const noexcept
Fast lookup with heterogeneous key types (C++ idiom: pointer return).
bool contains(const KeyType &key) const noexcept
Check if a key exists in the set.
FastHashSet(size_t initialCapacity)
Constructor with specified initial capacity.
bool insert(TKey &&key)
Insert a key into the set (move semantics).
size_t capacity() const noexcept
Get the current capacity of the hash table.
std::ptrdiff_t difference_type
Type alias for difference type.
bool emplace(Args &&... args)
Construct and insert a key in-place.
TKey key_type
Type alias for key type.
Definition FastHashSet.h:99
FastHashSet & operator=(FastHashSet &&other) noexcept
Move assignment operator.
FastHashSet(FastHashSet &&other) noexcept
Move constructor.
Iterator iterator
Type alias for iterator.
FastHashSet(const FastHashSet &)=default
Copy constructor.
void reserve(size_t minCapacity)
Reserve capacity for at least the specified number of elements.
FastHashSet & operator=(const FastHashSet &)=default
Copy assignment operator.
bool erase(const KeyType &key) noexcept
Remove a key from the set.
Iterator end() noexcept
Get iterator to end (past last occupied bucket).
FastHashSet(std::initializer_list< TKey > init)
Construct set from initializer_list.
Forward iterator for FastHashSet that skips empty buckets.
bool operator==(const Iterator &other) const
Equality comparison operator.
reference operator*() const
Dereference operator to access key.
const TKey value_type
STL iterator value type (key).
const TKey & reference
STL iterator reference type.
bool operator!=(const Iterator &other) const
Inequality comparison operator.
Iterator()=default
Default constructor creates an invalid iterator.
std::forward_iterator_tag iterator_category
STL iterator category (forward iterator).
Iterator(Bucket *bucket, Bucket *end)
Construct iterator from bucket range.
Iterator operator++(int)
Post-increment operator to advance to next occupied bucket.
pointer operator->() const
Arrow operator to access key.
Iterator & operator++()
Pre-increment operator to advance to next occupied bucket.
std::ptrdiff_t difference_type
STL iterator difference type.
const TKey * pointer
STL iterator pointer type.
Const forward iterator for FastHashSet that skips empty buckets.
ConstIterator operator++(int)
Post-increment operator to advance to next occupied bucket.
bool operator!=(const ConstIterator &other) const
Inequality comparison operator.
pointer operator->() const
Arrow operator to access key.
const TKey * pointer
STL iterator pointer type.
std::forward_iterator_tag iterator_category
STL iterator category (forward iterator).
const TKey value_type
STL iterator value type (const key).
bool operator==(const ConstIterator &other) const
Equality comparison operator.
std::ptrdiff_t difference_type
STL iterator difference type.
ConstIterator & operator++()
Pre-increment operator to advance to next occupied bucket.
ConstIterator(const Iterator &it)
Convert from non-const iterator.
reference operator*() const
Dereference operator to access key.
const TKey & reference
STL iterator reference type.
ConstIterator(const Bucket *bucket, const Bucket *end)
Construct const iterator from bucket range.
ConstIterator()=default
Default constructor creates an invalid iterator.