@@ -32,17 +32,17 @@ namespace ZEngine::Core::Containers
3232 {
3333 public:
3434 using Entry = HashEntry<K, V>;
35- using ArrayType = std::conditional_t <IsConst, const Array< Entry>, Array< Entry> >;
36- using value_type = std::conditional_t <IsConst, std::pair<const K& , const V& >, std::pair<const K& , V& >>;
35+ using EntryPointer = std::conditional_t <IsConst, const Entry*, Entry* >;
36+ using value_type = std::conditional_t <IsConst, std::pair<const K, const V>, std::pair<const K, V>>;
3737 using reference = value_type;
3838 using pointer = value_type*;
39- using iterator_category = std::forward_iterator_tag ;
39+ using iterator_category = std::input_iterator_tag ;
4040 using difference_type = std::ptrdiff_t ;
4141
4242 // Constructs an iterator for the hash map's entries, starting at the given index.
43- // @param entries Reference to the array of hash map entries.
43+ // @param entries Value to the array of hash map entries.
4444 // @param index Starting index for iteration.
45- HashMapIterator (ArrayType& entries, std::size_t index) : m_entries(entries), m_index(index)
45+ HashMapIterator (EntryPointer entries, std::size_t index, std:: size_t size ) : m_entries(entries), m_index(index), m_size(size )
4646 {
4747 advance_to_valid ();
4848 }
@@ -91,22 +91,22 @@ namespace ZEngine::Core::Containers
9191 // @return A pointer to a temporary key-value pair.
9292 pointer operator ->() const
9393 {
94- static value_type temp = **this ;
95- return &temp;
94+ return std::addressof (**this );
9695 }
9796
9897 private:
9998 // Advances the iterator to the next occupied entry, skipping empty or deleted entries.
10099 void advance_to_valid ()
101100 {
102- while (m_index < m_entries. size () && m_entries[m_index].state != EntryState::Occupied)
101+ while (m_index < m_size && m_entries[m_index].state != EntryState::Occupied)
103102 {
104103 ++m_index;
105104 }
106105 }
107106
108- ArrayType& m_entries;
109- std::size_t m_index;
107+ EntryPointer m_entries;
108+ std::size_t m_index;
109+ std::size_t m_size;
110110 };
111111
112112 template <typename K, typename V>
@@ -122,11 +122,11 @@ namespace ZEngine::Core::Containers
122122 // @param allocator Pointer to the arena allocator for memory management.
123123 // @param initial_capacity Initial number of slots (default: 16).
124124 // @param load_factor Maximum load factor before resizing (default: 0.75).
125- void init (Memory::ArenaAllocator* allocator, size_type initial_capacity = 32 )
125+ void init (Memory::ArenaAllocator* allocator, size_type initial_capacity = 16 )
126126 {
127127 m_allocator = allocator;
128128 m_load_factor = 0 .75f ;
129- m_entries.init (m_allocator, initial_capacity, 0 );
129+ m_entries.init (m_allocator, initial_capacity);
130130 for (size_type i = 0 ; i < initial_capacity; ++i)
131131 {
132132 m_entries.push ({});
@@ -146,12 +146,6 @@ namespace ZEngine::Core::Containers
146146 size_type index = probe_for_insert (key);
147147 auto & entry = m_entries[index];
148148
149- if (entry.state == EntryState::Occupied && key_equals (entry.key , key))
150- {
151- entry.value = value; // Update existing key
152- return ;
153- }
154-
155149 if (entry.state == EntryState::Empty || entry.state == EntryState::Deleted)
156150 {
157151 entry.key = key;
@@ -161,15 +155,10 @@ namespace ZEngine::Core::Containers
161155 }
162156 else
163157 {
164- throw std::runtime_error ( " HashMap insert failed: table full " ) ;
158+ entry. value = value ;
165159 }
166160 }
167161
168- // Accesses or inserts a value for a key, returning a reference to the value.
169- // Inserts a default-constructed value if the key is not found.
170- // @param key The key to access or insert.
171- // @return Reference to the associated value.
172- // @throws std::runtime_error if the table is full and cannot be resized.
173162 V& operator [](const K& key)
174163 {
175164 maybe_grow ();
@@ -184,11 +173,6 @@ namespace ZEngine::Core::Containers
184173 entry.state = EntryState::Occupied;
185174 ++m_size;
186175 }
187- else if (entry.state == EntryState::Occupied && entry.key != key)
188- {
189- throw std::runtime_error (" HashMap insert failed: table full" );
190- }
191-
192176 return entry.value ;
193177 }
194178
@@ -282,29 +266,29 @@ namespace ZEngine::Core::Containers
282266 // @note Iterators are invalidated by insert, remove, or reserve operations.
283267 iterator begin ()
284268 {
285- return iterator (m_entries, 0 );
269+ return iterator (m_entries. data () , 0 , m_entries. size () );
286270 }
287271
288272 // Returns an iterator to the end of the hash map.
289273 // @return Iterator representing the past-the-end position.
290274 iterator end ()
291275 {
292- return iterator (m_entries, m_entries.size ());
276+ return iterator (m_entries. data (), m_entries. size () , m_entries.size ());
293277 }
294278
295279 // Returns a const iterator to the first occupied entry.
296280 // @return Const iterator pointing to the first key-value pair or end() if empty.
297281 // @note Iterators are invalidated by insert, remove, or reserve operations.
298282 const_iterator begin () const
299283 {
300- return const_iterator (m_entries, 0 );
284+ return const_iterator (m_entries. data () , 0 , m_entries. size () );
301285 }
302286
303287 // Returns a const iterator to the end of the hash map.
304288 // @return Const iterator representing the past-the-end position.
305289 const_iterator end () const
306290 {
307- return const_iterator (m_entries, m_entries.size ());
291+ return const_iterator (m_entries. data (), m_entries. size () , m_entries.size ());
308292 }
309293
310294 // Returns a const iterator to the first occupied entry (alias for begin() const).
@@ -339,7 +323,7 @@ namespace ZEngine::Core::Containers
339323 {
340324 if (static_cast <float >(m_size + 1 ) / m_entries.size () > m_load_factor)
341325 {
342- size_type new_capacity = std::max<size_type>(16 , m_entries.size () * 3 / 2 ); // Growth factor 1.5
326+ size_type new_capacity = std::max<size_type>(16 , static_cast <size_type>( m_entries.size () * 1 . 5f ) ); // Growth factor 1.5
343327 rehash (new_capacity);
344328 }
345329 }
@@ -364,18 +348,20 @@ namespace ZEngine::Core::Containers
364348 {
365349 Array<Entry> old_entries = m_entries; // Move to avoid copying
366350 m_entries = Array<Entry>{};
367- m_entries.init (m_allocator, new_capacity, 0 );
351+ m_entries.init (m_allocator, new_capacity);
368352 for (size_type i = 0 ; i < new_capacity; ++i)
369353 {
370354 m_entries.push ({});
371355 }
372356 m_size = 0 ;
373357
374- for (const auto & entry : old_entries)
358+ for (size_type i = 0 ; i < old_entries. size (); ++i )
375359 {
376- if (entry .state == EntryState::Occupied)
360+ if (old_entries[i] .state == EntryState::Occupied)
377361 {
378- insert (entry.key , entry.value );
362+ size_type index = probe_for_insert (old_entries[i].key );
363+ m_entries[index] = old_entries[i]; // Direct assignment
364+ ++m_size;
379365 }
380366 }
381367 }
@@ -386,8 +372,6 @@ namespace ZEngine::Core::Containers
386372 size_type probe_for_key (const K& key) const
387373 {
388374 size_type index = hash (key) % m_entries.size ();
389- size_type step = double_hash (key);
390- size_type start = index;
391375 size_type i = 0 ;
392376
393377 do
@@ -401,9 +385,9 @@ namespace ZEngine::Core::Containers
401385 {
402386 return index;
403387 }
404- index = (index + step) % m_entries.size ();
405388 ++i;
406- } while (index != start && i < m_entries.size ());
389+ index = (index + i) % m_entries.size ();
390+ } while (i < m_entries.size ());
407391
408392 return size_type (-1 );
409393 }
@@ -415,47 +399,36 @@ namespace ZEngine::Core::Containers
415399 size_type probe_for_insert (const K& key)
416400 {
417401 size_type index = hash (key) % m_entries.size ();
418- size_type step = double_hash (key);
419- size_type start = index;
420402 size_type first_deleted = size_type (-1 );
421403 size_type i = 0 ;
422404
423405 do
424406 {
425407 auto & entry = m_entries[index];
408+ if (entry.state == EntryState::Occupied && key_equals (entry.key , key))
409+ {
410+ return index;
411+ }
412+
426413 if (entry.state == EntryState::Empty)
427414 {
428415 return (first_deleted != size_type (-1 )) ? first_deleted : index;
429416 }
417+
430418 if (entry.state == EntryState::Deleted && first_deleted == size_type (-1 ))
431419 {
432420 first_deleted = index;
433421 }
434- else if (entry.state == EntryState::Occupied && key_equals (entry.key , key))
435- {
436- return index;
437- }
438- index = (index + step) % m_entries.size ();
422+
439423 ++i;
440- } while (index != start && i < m_entries.size ());
424+ index = (index + i) % m_entries.size ();
425+ } while (i < m_entries.size ());
441426
442427 if (first_deleted != size_type (-1 ))
443428 {
444429 return first_deleted;
445430 }
446431
447- // Debug table state on failure
448- size_type empty_count = 0 , deleted_count = 0 , occupied_count = 0 ;
449- for (const auto & entry : m_entries)
450- {
451- if (entry.state == EntryState::Empty)
452- ++empty_count;
453- else if (entry.state == EntryState::Deleted)
454- ++deleted_count;
455- else if (entry.state == EntryState::Occupied)
456- ++occupied_count;
457- }
458-
459432 throw std::runtime_error (" HashMap probe failed: table full" );
460433 }
461434
0 commit comments