SleakEngine 1.0.0
C++23 multi-backend game engine
Loading...
Searching...
No Matches
HashTable.hpp
Go to the documentation of this file.
1#ifndef _HASH_TABLE_H_
2#define _HASH_TABLE_H_
3
4#include <cstdint> // For uint64_t
5#include <utility> // For std::move (can be removed if unwanted)
6
7namespace Sleak
8{
9 /**
10 * @class HashTable
11 * @brief Implements a hash table (or map) for efficient key-value storage and retrieval.
12 *
13 * The HashTable class provides fast access to values based on their associated keys.
14 * It is suitable for scenarios where you need to quickly look up data using unique
15 * identifiers. Use this class when you need to store and retrieve data based on keys,
16 * such as symbol tables, dictionaries, or caching systems.
17 *
18 * Example Use Cases:
19 * - Implementing a symbol table in a compiler.
20 * - Creating a dictionary or vocabulary lookup system.
21 * - Caching frequently accessed data.
22 * - Storing user preferences or configuration settings.
23 *
24 * Implementation Details:
25 * - Uses a hash function to map keys to indices in an internal array.
26 * - Handles collisions using chaining or open addressing (specify which one you used).
27 * - Provides methods for inserting, deleting, and retrieving key-value pairs.
28 * @ingroup utility
29 */
30 template <typename Key, typename Value>
32 {
33 private:
34 /// One slot: key/value plus occupied and tombstone-deleted flags.
35 struct Entry
36 {
37 Key key;
38 Value value;
39 bool occupied;
40 bool deleted; // To handle tombstones in deletion
41
42 Entry() : occupied(false), deleted(false) {}
43 };
44
45 Entry* table;
46 size_t capacity;
47 size_t size;
48 float loadFactor;
49
50 static constexpr size_t DEFAULT_CAPACITY = 16;
51 static constexpr float DEFAULT_LOAD_FACTOR = 0.7f;
52
53 /// Maps a key to a starting slot index via linear probing.
54 size_t hash(const Key& key) const
55 {
56 return reinterpret_cast<uintptr_t>(&key) % capacity;
57 }
58
59 /// Doubles capacity and rehashes every live entry into the new table.
60 void resize()
61 {
62 size_t newCapacity = capacity * 2;
63 Entry* newTable = new Entry[newCapacity];
64
65 for (size_t i = 0; i < capacity; ++i)
66 {
67 if (table[i].occupied && !table[i].deleted)
68 {
69 size_t index = hash(table[i].key) % newCapacity;
70 while (newTable[index].occupied)
71 {
72 index = (index + 1) % newCapacity;
73 }
74 newTable[index] = std::move(table[i]);
75 }
76 }
77
78 delete[] table;
79 table = newTable;
80 capacity = newCapacity;
81 }
82
83 public:
84 HashTable(size_t initCapacity = DEFAULT_CAPACITY, float loadFactor = DEFAULT_LOAD_FACTOR)
85 : capacity(initCapacity), size(0), loadFactor(loadFactor)
86 {
87 table = new Entry[capacity];
88 }
89
91 {
92 delete[] table;
93 }
94
95 /// Inserts or updates the value for key, resizing first if over the load factor.
96 void insert(const Key& key, const Value& value)
97 {
98 if (size >= capacity * loadFactor)
99 {
100 resize();
101 }
102
103 size_t index = hash(key) % capacity;
104 while (table[index].occupied && !table[index].deleted && table[index].key != key)
105 {
106 index = (index + 1) % capacity;
107 }
108
109 if (!table[index].occupied || table[index].deleted)
110 {
111 table[index].key = key;
112 table[index].value = value;
113 table[index].occupied = true;
114 table[index].deleted = false;
115 ++size;
116 }
117 else
118 {
119 table[index].value = value;
120 }
121 }
122
123 /// Tombstones the entry for key; returns false if it wasn't present.
124 bool remove(const Key& key)
125 {
126 size_t index = hash(key) % capacity;
127 while (table[index].occupied)
128 {
129 if (!table[index].deleted && table[index].key == key)
130 {
131 table[index].deleted = true;
132 --size;
133 return true;
134 }
135 index = (index + 1) % capacity;
136 }
137 return false;
138 }
139
140 /// Looks up key and writes its value into outValue; returns false if not found.
141 bool get(const Key& key, Value& outValue) const
142 {
143 size_t index = hash(key) % capacity;
144 while (table[index].occupied)
145 {
146 if (!table[index].deleted && table[index].key == key)
147 {
148 outValue = table[index].value;
149 return true;
150 }
151 index = (index + 1) % capacity;
152 }
153 return false;
154 }
155
156 /// True if key currently has a live entry.
157 bool contains(const Key& key) const
158 {
159 size_t index = hash(key) % capacity;
160 while (table[index].occupied)
161 {
162 if (!table[index].deleted && table[index].key == key)
163 {
164 return true;
165 }
166 index = (index + 1) % capacity;
167 }
168 return false;
169 }
170
171 /// Drops every entry and reallocates the table at its current capacity.
172 void clear()
173 {
174 delete[] table;
175 table = new Entry[capacity];
176 size = 0;
177 }
178
179 size_t getSize() const { return size; }
180 size_t getCapacity() const { return capacity; }
181 };
182}
183
184#endif // _HASH_TABLE_H_
size_t getSize() const
bool contains(const Key &key) const
True if key currently has a live entry.
void insert(const Key &key, const Value &value)
Inserts or updates the value for key, resizing first if over the load factor.
Definition HashTable.hpp:96
void clear()
Drops every entry and reallocates the table at its current capacity.
size_t getCapacity() const
bool remove(const Key &key)
Tombstones the entry for key; returns false if it wasn't present.
bool get(const Key &key, Value &outValue) const
Looks up key and writes its value into outValue; returns false if not found.
HashTable(size_t initCapacity=DEFAULT_CAPACITY, float loadFactor=DEFAULT_LOAD_FACTOR)
Definition HashTable.hpp:84
Root namespace for everything the engine exposes.
Definition Camera.hpp:10