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
OrderedHashSet.h
Go to the documentation of this file.
1/*
2 * MIT License
3 *
4 * Copyright (c) 2026 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
32
33#pragma once
34
35#include "nfx/detail/containers/CompilerSupport.h"
36
37#include <nfx/Hashing.h>
38
39#include <algorithm>
40#include <concepts>
41#include <cstddef>
42#include <cstdint>
43#include <functional>
44#include <initializer_list>
45#include <iterator>
46#include <stdexcept>
47#include <string>
48#include <string_view>
49#include <type_traits>
50#include <utility>
51#include <vector>
52
53namespace nfx::containers
54{
55 //=====================================================================
56 // OrderedHashSet class
57 //=====================================================================
58
71 template <typename TKey,
72 hashing::Hash32or64 HashType = uint32_t,
73 HashType Seed = ( sizeof( HashType ) == 4 ? hashing::constants::FNV_OFFSET_BASIS_32 : hashing::constants::FNV_OFFSET_BASIS_64 ),
74 typename THasher = hashing::Hasher<HashType, Seed>,
75 typename KeyEqual = std::equal_to<>>
76 class OrderedHashSet final
77 {
78 //----------------------------------------------
79 // Compile-time type constraints
80 //----------------------------------------------
81
82 static_assert( std::is_same_v<HashType, uint32_t> || std::is_same_v<HashType, uint64_t>,
83 "HashType must be uint32_t or uint64_t" );
84
85 static_assert( std::is_invocable_r_v<HashType, THasher, TKey>,
86 "THasher must be callable with TKey and return HashType" );
87
88 static_assert( std::is_invocable_r_v<bool, KeyEqual, TKey, TKey>,
89 "KeyEqual must be callable with two TKey arguments and return bool" );
90
91 public:
92 //----------------------------------------------
93 // Forward declarations for iterator support
94 //----------------------------------------------
95
96 class Iterator;
97 class ConstIterator;
98
99 //----------------------------------------------
100 // STL-compatible type aliases
101 //----------------------------------------------
102
104 using key_type = TKey;
105
107 using value_type = TKey;
108
110 using hasher = THasher;
111
113 using key_equal = KeyEqual;
114
116 using hash_type = HashType;
117
119 using size_type = size_t;
120
122 using difference_type = std::ptrdiff_t;
123
126
129
130 //----------------------------------------------
131 // Construction
132 //----------------------------------------------
133
138
143 inline OrderedHashSet( std::initializer_list<TKey> init );
144
151 template <typename InputIt>
152 inline OrderedHashSet( InputIt first, InputIt last );
153
158 inline explicit OrderedHashSet( size_t initialCapacity );
159
164 OrderedHashSet( OrderedHashSet&& other ) noexcept;
165
172
178
185
190
191 //----------------------------------------------
192 // Core operations
193 //----------------------------------------------
194
201 template <typename KeyType = TKey>
202 [[nodiscard]] inline const TKey* find( const KeyType& key ) const noexcept;
203
211 template <typename KeyType = TKey>
212 [[nodiscard]] inline bool contains( const KeyType& key ) const noexcept;
213
222 template <typename KeyType = TKey>
223 inline const TKey& at( const KeyType& key ) const;
224
225 //----------------------------------------------
226 // Insertion
227 //----------------------------------------------
228
235 inline bool insert( const TKey& key );
236
243 inline bool insert( TKey&& key );
244
245 //----------------------------------------------
246 // Emplace operations
247 //----------------------------------------------
248
256 template <typename... Args>
257 inline bool emplace( Args&&... args );
258
267 template <typename... Args>
268 inline std::pair<Iterator, bool> tryEmplace( Args&&... args );
269
270 //----------------------------------------------
271 // Capacity and memory management
272 //----------------------------------------------
273
279 inline void reserve( size_t minCapacity );
280
288 template <typename KeyType = TKey>
289 inline bool erase( const KeyType& key ) noexcept;
290
297 inline Iterator erase( ConstIterator pos ) noexcept;
298
305 inline Iterator erase( ConstIterator first, ConstIterator last ) noexcept;
306
310 inline void clear() noexcept;
311
322 template <typename KeyType = TKey>
323 [[nodiscard]] inline std::optional<TKey> extract( const KeyType& key );
324
333 inline void merge( OrderedHashSet& other );
334
339 inline void merge( OrderedHashSet&& other );
340
341 //----------------------------------------------
342 // State inspection
343 //----------------------------------------------
344
349 [[nodiscard]] inline size_t size() const noexcept;
350
355 [[nodiscard]] inline size_t capacity() const noexcept;
356
361 [[nodiscard]] inline bool isEmpty() const noexcept;
362
368 inline void swap( OrderedHashSet& other ) noexcept;
369
370 //----------------------------------------------
371 // STL-compatible iteration support (insertion order)
372 //----------------------------------------------
373
379 [[nodiscard]] Iterator begin() noexcept;
380
386 [[nodiscard]] ConstIterator begin() const noexcept;
387
393 [[nodiscard]] Iterator end() noexcept;
394
400 [[nodiscard]] ConstIterator end() const noexcept;
401
407 [[nodiscard]] ConstIterator cbegin() const noexcept;
408
414 [[nodiscard]] ConstIterator cend() const noexcept;
415
422 [[nodiscard]] bool operator==( const OrderedHashSet& other ) const noexcept;
423
424 private:
425 //----------------------------------------------
426 // Node structure for doubly-linked list
427 //----------------------------------------------
428
432 struct Node
433 {
434 TKey data;
435 Node* prev{};
436 Node* next{};
437 HashType hash{};
438 };
439
440 //----------------------------------------------
441 // Robin Hood Hashing bucket structure
442 //----------------------------------------------
443
447 struct Bucket
448 {
449 Node* node{};
450 HashType hash{};
451 uint32_t distance{};
452 bool occupied{};
453 };
454
458 static constexpr size_t INITIAL_CAPACITY = 32;
459
463 static constexpr size_t MAX_LOAD_FACTOR_PERCENT = 75;
464
468 std::vector<Bucket> m_buckets;
469
470 Node* m_head{};
471 Node* m_tail{};
472 size_t m_size{};
473 size_t m_capacity{ INITIAL_CAPACITY };
474 size_t m_mask{ INITIAL_CAPACITY - 1 };
475
479 NFX_CONTAINERS_NO_UNIQUE_ADDRESS hasher m_hasher;
480
484 NFX_CONTAINERS_NO_UNIQUE_ADDRESS KeyEqual m_keyEqual;
485
486 //----------------------------------------------
487 // Internal implementation
488 //----------------------------------------------
489
495 inline bool insertInternal( const TKey& key );
496
502 inline bool insertInternal( TKey&& key );
503
508 inline bool shouldResize() const noexcept;
509
514 inline void resize();
515
520 inline void eraseAtPosition( size_t pos ) noexcept;
521
526 inline void unlinkNode( Node* node ) noexcept;
527
532 inline void appendNode( Node* node ) noexcept;
533
542 template <typename KeyType1, typename KeyType2>
543 inline bool keysEqual( const KeyType1& k1, const KeyType2& k2 ) const noexcept;
544
545 public:
546 //----------------------------------------------
547 // OrderedHashSet::Iterator class
548 //----------------------------------------------
549
554 {
555 friend class ConstIterator;
556 friend class OrderedHashSet;
557
558 public:
560 using iterator_category = std::bidirectional_iterator_tag;
561
563 using value_type = const TKey;
564
566 using difference_type = std::ptrdiff_t;
567
569 using pointer = const TKey*;
570
572 using reference = const TKey&;
573
574 //---------------------------
575 // Construction
576 //---------------------------
577
581 Iterator() = default;
582
587 inline explicit Iterator( Node* node );
588
589 //---------------------------
590 // Operations
591 //---------------------------
592
597 inline reference operator*() const;
598
603 inline pointer operator->() const;
604
610
615 inline Iterator operator++( int );
616
622
627 inline Iterator operator--( int );
628
629 //---------------------------
630 // Comparison
631 //---------------------------
632
638 inline bool operator==( const Iterator& other ) const;
639
645 inline bool operator!=( const Iterator& other ) const;
646
647 private:
648 //---------------------------
649 // Private members
650 //---------------------------
651
657 inline Iterator( Node* node, const OrderedHashSet* container );
658
659 Node* m_node = nullptr;
660 const OrderedHashSet* m_container = nullptr;
661 };
662
663 //----------------------------------------------
664 // OrderedHashSet::ConstIterator class
665 //----------------------------------------------
666
671 {
672 friend class OrderedHashSet;
673
674 public:
676 using iterator_category = std::bidirectional_iterator_tag;
677
679 using value_type = const TKey;
680
682 using difference_type = std::ptrdiff_t;
683
685 using pointer = const TKey*;
686
688 using reference = const TKey&;
689
690 //---------------------------
691 // Construction
692 //---------------------------
693
697 ConstIterator() = default;
698
703 inline explicit ConstIterator( const Node* node );
704
709 inline ConstIterator( const Iterator& it );
710
711 //---------------------------
712 // Operations
713 //---------------------------
714
719 inline reference operator*() const;
720
725 inline pointer operator->() const;
726
732
738
744
750
751 //---------------------------
752 // Comparison
753 //---------------------------
754
760 inline bool operator==( const ConstIterator& other ) const;
761
767 inline bool operator!=( const ConstIterator& other ) const;
768
769 private:
770 //---------------------------
771 // Private members
772 //---------------------------
773
779 inline ConstIterator( const Node* node, const OrderedHashSet* container );
780
781 const Node* m_node = nullptr;
782 const OrderedHashSet* m_container = nullptr;
783 };
784 };
785} // namespace nfx::containers
786
787#include "nfx/detail/containers/OrderedHashSet.inl"
ConstIterator cend() const noexcept
Get const iterator to end (explicit const).
void reserve(size_t minCapacity)
Reserve capacity for at least the specified number of elements.
std::optional< TKey > extract(const KeyType &key)
Extract and remove a key from the set.
ConstIterator cbegin() const noexcept
Get const iterator to first element in insertion order (explicit const).
Iterator begin() noexcept
Get iterator to first element in insertion order.
size_t size() const noexcept
Get the number of elements in the set.
std::ptrdiff_t difference_type
Type alias for difference type.
OrderedHashSet(std::initializer_list< TKey > init)
Construct set from initializer_list.
OrderedHashSet(size_t initialCapacity)
Constructor with specified initial capacity.
void swap(OrderedHashSet &other) noexcept
Swap contents with another set.
void merge(OrderedHashSet &other)
Merge elements from another set into this set.
OrderedHashSet(const OrderedHashSet &other)
Copy constructor.
KeyEqual key_equal
Type alias for key equality comparator.
OrderedHashSet(InputIt first, InputIt last)
Construct set from iterator range.
bool erase(const KeyType &key) noexcept
Remove a key from the set.
void clear() noexcept
Clear all elements from the set.
OrderedHashSet()
Default constructor with initial capacity of 32 elements.
HashType hash_type
Type alias for hash type (uint32_t or uint64_t).
bool insert(const TKey &key)
Insert a key into the set (copy semantics).
const TKey * find(const KeyType &key) const noexcept
Fast lookup with heterogeneous key types (C++ idiom: pointer return).
const TKey & at(const KeyType &key) const
Checked element access with bounds checking.
bool insert(TKey &&key)
Insert a key into the set (move semantics).
Iterator erase(ConstIterator pos) noexcept
Erase element at iterator position.
OrderedHashSet(OrderedHashSet &&other) noexcept
Move constructor.
std::pair< Iterator, bool > tryEmplace(Args &&... args)
Try to emplace a key if it doesn't exist.
TKey value_type
Type alias for value type (same as key for sets).
TKey key_type
Type alias for key type.
ConstIterator const_iterator
Type alias for const iterator.
Iterator end() noexcept
Get iterator to end (past last element in insertion order).
Iterator erase(ConstIterator first, ConstIterator last) noexcept
Erase range of elements.
size_t size_type
Type alias for size type.
THasher hasher
Type alias for hasher type.
OrderedHashSet & operator=(const OrderedHashSet &other)
Copy assignment operator.
size_t capacity() const noexcept
Get the current capacity of the hash table.
Iterator iterator
Type alias for iterator.
OrderedHashSet & operator=(OrderedHashSet &&other) noexcept
Move assignment operator.
bool isEmpty() const noexcept
Check if the set is empty.
bool emplace(Args &&... args)
Construct and insert a key in-place.
bool contains(const KeyType &key) const noexcept
Check if a key exists in the set.
Iterator for OrderedHashSet that follows insertion order.
const TKey & reference
STL iterator reference type.
std::bidirectional_iterator_tag iterator_category
STL iterator category (bidirectional iterator).
Iterator & operator--()
Pre-decrement operator to move to previous element in insertion order.
bool operator!=(const Iterator &other) const
Inequality comparison operator.
Iterator operator--(int)
Post-decrement operator to move to previous element in insertion order.
bool operator==(const Iterator &other) const
Equality comparison operator.
std::ptrdiff_t difference_type
STL iterator difference type.
reference operator*() const
Dereference operator to access key.
const TKey * pointer
STL iterator pointer type.
Iterator operator++(int)
Post-increment operator to advance to next element in insertion order.
Iterator()=default
Default constructor creates an invalid iterator.
Iterator(Node *node)
Construct iterator from node.
pointer operator->() const
Arrow operator to access key.
const TKey value_type
STL iterator value type (const key).
Iterator & operator++()
Pre-increment operator to advance to next element in insertion order.
Const iterator for OrderedHashSet that follows insertion order.
ConstIterator()=default
Default constructor creates an invalid iterator.
ConstIterator & operator--()
Pre-decrement operator to move to previous element in insertion order.
bool operator==(const ConstIterator &other) const
Equality comparison operator.
std::ptrdiff_t difference_type
STL iterator difference type.
bool operator!=(const ConstIterator &other) const
Inequality comparison operator.
ConstIterator operator++(int)
Post-increment operator to advance to next element in insertion order.
ConstIterator & operator++()
Pre-increment operator to advance to next element in insertion order.
ConstIterator operator--(int)
Post-decrement operator to move to previous element in insertion order.
const TKey value_type
STL iterator value type (const key).
ConstIterator(const Iterator &it)
Convert from non-const iterator.
const TKey & reference
STL iterator reference type.
pointer operator->() const
Arrow operator to access key.
reference operator*() const
Dereference operator to access key.
std::bidirectional_iterator_tag iterator_category
STL iterator category (bidirectional iterator).
ConstIterator(const Node *node)
Construct const iterator from node.
const TKey * pointer
STL iterator pointer type.