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
FastHashMap.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 <optional>
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 // FastHashMap class
57 //=====================================================================
58
68 template <typename TKey,
69 typename TValue,
70 hashing::Hash32or64 HashType = uint32_t,
71 HashType Seed = ( sizeof( HashType ) == 4 ? hashing::constants::FNV_OFFSET_BASIS_32 : hashing::constants::FNV_OFFSET_BASIS_64 ),
72 typename THasher = hashing::Hasher<HashType, Seed>,
73 typename KeyEqual = std::equal_to<>>
74 class FastHashMap final
75 {
76 //----------------------------------------------
77 // Compile-time type constraints
78 //----------------------------------------------
79
80 static_assert( std::is_same_v<HashType, uint32_t> || std::is_same_v<HashType, uint64_t>,
81 "HashType must be uint32_t or uint64_t" );
82
83 static_assert( std::is_invocable_r_v<HashType, THasher, TKey>,
84 "THasher must be callable with TKey and return HashType" );
85
86 static_assert( std::is_invocable_r_v<bool, KeyEqual, TKey, TKey>,
87 "KeyEqual must be callable with two TKey arguments and return bool" );
88
89 public:
90 //----------------------------------------------
91 // Forward declarations for iterator support
92 //----------------------------------------------
93
94 class Iterator;
95 class ConstIterator;
96
97 //----------------------------------------------
98 // STL-compatible type aliases
99 //----------------------------------------------
100
102 using key_type = TKey;
103
105 using mapped_type = TValue;
106
108 using value_type = std::pair<const TKey, TValue>;
109
111 using hasher = THasher;
112
114 using key_equal = KeyEqual;
115
117 using hash_type = HashType;
118
120 using size_type = size_t;
121
123 using difference_type = std::ptrdiff_t;
124
127
130
131 //----------------------------------------------
132 // Construction
133 //----------------------------------------------
134
138 inline FastHashMap();
139
144 inline FastHashMap( std::initializer_list<std::pair<TKey, TValue>> init );
145
152 template <typename InputIt>
153 inline FastHashMap( InputIt first, InputIt last );
154
159 inline explicit FastHashMap( size_t initialCapacity );
160
165
170 FastHashMap& operator=( FastHashMap&& ) noexcept;
171
175 FastHashMap( const FastHashMap& ) = default;
176
181 FastHashMap& operator=( const FastHashMap& ) = default;
182
186 ~FastHashMap() = default;
187
188 //----------------------------------------------
189 // Core operations
190 //----------------------------------------------
191
198 template <typename KeyType = TKey>
199 [[nodiscard]] inline TValue* find( const KeyType& key ) noexcept;
200
207 template <typename KeyType = TKey>
208 [[nodiscard]] inline const TValue* find( const KeyType& key ) const noexcept;
209
217 template <typename KeyType = TKey>
218 [[nodiscard]] inline bool contains( const KeyType& key ) const noexcept;
219
226 inline TValue& at( const TKey& key );
227
234 inline const TValue& at( const TKey& key ) const;
235
244 inline TValue& operator[]( const TKey& key );
245
254 inline TValue& operator[]( TKey&& key );
255
263 template <typename KeyType = TKey>
264 inline TValue& at( const KeyType& key );
265
273 template <typename KeyType = TKey>
274 inline const TValue& at( const KeyType& key ) const;
275
276 //----------------------------------------------
277 // Insertion
278 //----------------------------------------------
279
287 inline bool insert( const TKey& key, const TValue& value );
288
296 inline bool insert( const TKey& key, TValue&& value );
297
305 inline bool insert( TKey&& key, TValue&& value );
306
312 inline void insertOrAssign( const TKey& key, TValue&& value );
313
319 inline void insertOrAssign( const TKey& key, const TValue& value );
320
326 inline void insertOrAssign( TKey&& key, TValue&& value );
327
328 //----------------------------------------------
329 // Emplace operations
330 //----------------------------------------------
331
338 template <typename... Args>
339 inline void emplace( const TKey& key, Args&&... args );
340
347 template <typename... Args>
348 inline void emplace( TKey&& key, Args&&... args );
349
358 template <typename... Args>
359 inline std::pair<Iterator, bool> tryEmplace( const TKey& key, Args&&... args );
360
369 template <typename... Args>
370 inline std::pair<Iterator, bool> tryEmplace( TKey&& key, Args&&... args );
371
372 //----------------------------------------------
373 // Capacity and memory management
374 //----------------------------------------------
379 inline void reserve( size_t minCapacity );
380
387 template <typename KeyType = TKey>
388 inline bool erase( const KeyType& key ) noexcept;
389
396 inline Iterator erase( ConstIterator pos ) noexcept;
397
404 inline Iterator erase( ConstIterator first, ConstIterator last ) noexcept;
405
409 inline void clear() noexcept;
410
420 template <typename KeyType = TKey>
421 [[nodiscard]] inline std::optional<std::pair<TKey, TValue>> extract( const KeyType& key );
422
430 inline void merge( FastHashMap& other );
431
437 inline void merge( FastHashMap&& other );
438
439 //----------------------------------------------
440 // State inspection
441 //----------------------------------------------
442
447 [[nodiscard]] inline size_t size() const noexcept;
448
453 [[nodiscard]] inline size_t capacity() const noexcept;
454
459 [[nodiscard]] inline bool isEmpty() const noexcept;
460
466 inline void swap( FastHashMap& other ) noexcept;
467
468 //----------------------------------------------
469 // STL-compatible iteration support
470 //----------------------------------------------
471
477 [[nodiscard]] Iterator begin() noexcept;
478
484 [[nodiscard]] ConstIterator begin() const noexcept;
485
491 [[nodiscard]] Iterator end() noexcept;
492
498 [[nodiscard]] ConstIterator end() const noexcept;
499
505 [[nodiscard]] ConstIterator cbegin() const noexcept;
506
512 [[nodiscard]] ConstIterator cend() const noexcept;
513
520 [[nodiscard]] bool operator==( const FastHashMap& other ) const noexcept;
521
522 private:
523 //----------------------------------------------
524 // Robin Hood Hashing bucket structure
525 //----------------------------------------------
526
530 struct Bucket
531 {
532 std::optional<std::pair<TKey, TValue>> data;
533 HashType hash{};
534 uint32_t distance{};
535 bool occupied{};
536 };
537
541 static constexpr size_t INITIAL_CAPACITY = 32;
542
546 static constexpr size_t MAX_LOAD_FACTOR_PERCENT = 75;
547
551 std::vector<Bucket> m_buckets;
552
553 size_t m_size{};
554 size_t m_capacity{ INITIAL_CAPACITY };
555 size_t m_mask{ INITIAL_CAPACITY - 1 };
556
560 NFX_CONTAINERS_NO_UNIQUE_ADDRESS hasher m_hasher;
561
565 NFX_CONTAINERS_NO_UNIQUE_ADDRESS KeyEqual m_keyEqual;
566
567 //----------------------------------------------
568 // Internal implementation
569 //----------------------------------------------
570
577 template <typename ValueType>
578 inline void insertOrAssignInternal( const TKey& key, ValueType&& value );
579
586 template <typename ValueType>
587 inline void insertOrAssignInternal( TKey&& key, ValueType&& value );
588
593 inline bool shouldResize() const noexcept;
594
598 inline void resize();
599
604 inline void eraseAtPosition( size_t pos ) noexcept;
605
614 template <typename KeyType1, typename KeyType2>
615 inline bool keysEqual( const KeyType1& k1, const KeyType2& k2 ) const noexcept;
616
617 public:
618 //----------------------------------------------
619 // FastHashMap::Iterator class
620 //----------------------------------------------
621
626 {
627 friend class ConstIterator;
628
629 public:
631 using iterator_category = std::forward_iterator_tag;
632
634 using value_type = std::pair<const TKey, TValue>;
635
637 using difference_type = std::ptrdiff_t;
638
641
644
645 //---------------------------
646 // Construction
647 //---------------------------
648
652 Iterator() = default;
653
659 inline Iterator( Bucket* bucket, Bucket* end );
660
661 //---------------------------
662 // Operations
663 //---------------------------
664
669 inline reference operator*() const;
670
675 inline pointer operator->() const;
676
682
687 inline Iterator operator++( int );
688
689 //---------------------------
690 // Comparison
691 //---------------------------
692
698 inline bool operator==( const Iterator& other ) const;
699
705 inline bool operator!=( const Iterator& other ) const;
706
707 private:
708 //---------------------------
709 // Private methods
710 //---------------------------
711
716 inline void skipToOccupied();
717
718 //---------------------------
719 // Private members
720 //---------------------------
721
722 Bucket* m_bucket = nullptr;
723 Bucket* m_end = nullptr;
724 };
725
726 //----------------------------------------------
727 // FastHashMap::ConstIterator class
728 //----------------------------------------------
729
734 {
735 friend class FastHashMap;
736
737 public:
739 using iterator_category = std::forward_iterator_tag;
740
742 using value_type = std::pair<const TKey, TValue>;
743
745 using difference_type = std::ptrdiff_t;
746
748 using pointer = const value_type*;
749
751 using reference = const value_type&;
752
753 //---------------------------
754 // Construction
755 //---------------------------
756
760 ConstIterator() = default;
761
767 inline ConstIterator( const Bucket* bucket, const Bucket* end );
768
773 inline ConstIterator( const Iterator& it );
774
775 //---------------------------
776 // Operations
777 //---------------------------
778
783 inline reference operator*() const;
784
789 inline pointer operator->() const;
790
796
802
803 //---------------------------
804 // Comparison
805 //---------------------------
806
812 inline bool operator==( const ConstIterator& other ) const;
813
819 inline bool operator!=( const ConstIterator& other ) const;
820
821 private:
822 //---------------------------
823 // Private methods
824 //---------------------------
825
830 inline void skipToOccupied();
831
832 //---------------------------
833 // Private members
834 //---------------------------
835
836 const Bucket* m_bucket = nullptr;
837 const Bucket* m_end = nullptr;
838 };
839 };
840} // namespace nfx::containers
841
842#include "nfx/detail/containers/FastHashMap.inl"
std::pair< Iterator, bool > tryEmplace(const TKey &key, Args &&... args)
Try to emplace a value if key doesn't exist.
ConstIterator cend() const noexcept
Get const iterator to end (explicit const).
bool insert(const TKey &key, const TValue &value)
Insert a key-value pair only if key doesn't exist (copy semantics).
void merge(FastHashMap &other)
Merge another FastHashMap into this one.
void insertOrAssign(const TKey &key, TValue &&value)
Insert or update a key-value pair (move semantics).
TValue & at(const TKey &key)
Checked element access with bounds checking.
Iterator begin() noexcept
Get iterator to beginning of occupied buckets.
KeyEqual key_equal
Type alias for key equality comparator.
HashType hash_type
Type alias for hash type (uint32_t or uint64_t).
TValue * find(const KeyType &key) noexcept
Fast lookup with heterogeneous key types (C++ idiom: pointer return).
THasher hasher
Type alias for hasher type.
std::optional< std::pair< TKey, TValue > > extract(const KeyType &key)
Extract a key-value pair from the map without destroying it.
size_t capacity() const noexcept
Get the current capacity of the hash table.
bool erase(const KeyType &key) noexcept
Remove a key-value pair from the map.
void emplace(const TKey &key, Args &&... args)
Emplace a value in-place for the given key.
std::ptrdiff_t difference_type
Type alias for difference type.
void clear() noexcept
Clear all elements from the map.
ConstIterator const_iterator
Type alias for const iterator.
bool isEmpty() const noexcept
Check if the map is empty.
ConstIterator cbegin() const noexcept
Get const iterator to beginning of occupied buckets (explicit const).
TValue mapped_type
Type alias for mapped value type.
std::pair< const TKey, TValue > value_type
Type alias for key-value pair type.
size_t size_type
Type alias for size type.
void swap(FastHashMap &other) noexcept
Swap contents with another map.
Iterator end() noexcept
Get iterator to end (past last occupied bucket).
Iterator iterator
Type alias for iterator.
FastHashMap(InputIt first, InputIt last)
Construct map from iterator range.
void reserve(size_t minCapacity)
Reserve capacity for at least the specified number of elements.
bool contains(const KeyType &key) const noexcept
Check if a key exists in the map.
FastHashMap(FastHashMap &&) noexcept
Move constructor.
FastHashMap()
Default constructor with initial capacity of 32 elements.
TKey key_type
Type alias for key type.
FastHashMap(size_t initialCapacity)
Constructor with specified initial capacity.
size_t size() const noexcept
Get the number of elements in the map.
FastHashMap(std::initializer_list< std::pair< TKey, TValue > > init)
Construct map from initializer_list.
Iterator for HashMap that skips empty buckets.
Iterator & operator++()
Pre-increment operator to advance to next occupied bucket.
Iterator()=default
Default constructor creates an invalid iterator.
std::forward_iterator_tag iterator_category
STL iterator category (forward iterator).
std::ptrdiff_t difference_type
STL iterator difference type.
reference operator*() const
Dereference operator to access key-value pair.
Iterator(Bucket *bucket, Bucket *end)
Construct iterator from bucket range.
Iterator operator++(int)
Post-increment operator to advance to next occupied bucket.
bool operator==(const Iterator &other) const
Equality comparison operator.
value_type * pointer
STL iterator pointer type.
std::pair< const TKey, TValue > value_type
STL iterator value type (key-value pair).
pointer operator->() const
Arrow operator to access key-value pair members.
bool operator!=(const Iterator &other) const
Inequality comparison operator.
value_type & reference
STL iterator reference type.
Const iterator for HashMap that skips empty buckets.
bool operator!=(const ConstIterator &other) const
Inequality comparison operator.
ConstIterator(const Iterator &it)
Convert from non-const iterator.
std::pair< const TKey, TValue > value_type
STL iterator value type (const key-value pair).
ConstIterator(const Bucket *bucket, const Bucket *end)
Construct const iterator from bucket range.
std::forward_iterator_tag iterator_category
STL iterator category (forward iterator).
std::ptrdiff_t difference_type
STL iterator difference type.
pointer operator->() const
Arrow operator to access key-value pair members.
bool operator==(const ConstIterator &other) const
Equality comparison operator.
const value_type * pointer
STL iterator pointer type.
ConstIterator()=default
Default constructor creates an invalid iterator.
ConstIterator operator++(int)
Post-increment operator to advance to next occupied bucket.
const value_type & reference
STL iterator reference type.
reference operator*() const
Dereference operator to access key-value pair.
ConstIterator & operator++()
Pre-increment operator to advance to next occupied bucket.