Arcane  4.2.1.0
Developer documentation
Loading...
Searching...
No Matches
HashTableMap.h
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* HashTableMap.h (C) 2000-2026 */
9/* */
10/* Associative array using a hash table. */
11/*---------------------------------------------------------------------------*/
12#ifndef ARCANE_UTILS_HASHTABLEMAP_H
13#define ARCANE_UTILS_HASHTABLEMAP_H
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/utils/HashTable.h"
18
19#include <iostream>
20
21/*---------------------------------------------------------------------------*/
22/*---------------------------------------------------------------------------*/
23
24namespace Arcane
25{
26
27/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30template <typename KeyType, typename ValueType>
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
52template <typename KeyType, typename ValueType, typename KeyTraitsType = HashTraitsT<KeyType>>
54: public HashTableBase
55{
56 public:
57
58 typedef typename KeyTraitsType::KeyTypeConstRef KeyTypeConstRef;
59 typedef typename KeyTraitsType::KeyTypeValue KeyTypeValue;
60 typedef typename KeyTraitsType::Printable Printable;
61 typedef typename KeyTraitsType::HashValueType HashValueType;
64
65 public:
66
67 struct Data
68 {
69 public:
70
71 Data()
72 : m_key(KeyTypeValue())
74 {}
75
76 public:
77
78 Data* next() { return m_next; }
79 void setNext(Data* anext) { this->m_next = anext; }
80 KeyTypeConstRef key() { return m_key; }
81 const ValueType& value() const { return m_value; }
82 ValueType& value() { return m_value; }
84 void setValue(const ValueType& avalue) { m_value = avalue; }
90 void setKey(const KeyType& new_key)
91 {
92 m_key = new_key;
93 }
94
95 public:
96
97 KeyTypeValue m_key;
99 Data* m_next = nullptr;
100 };
101
102 public:
103
109 HashTableMapT(Integer table_size, bool use_prime)
110 : HashTableBase(table_size, use_prime)
111 , m_first_free(0)
112 , m_nb_collision(0)
113 , m_nb_direct(0)
114 , m_max_count(0)
115 {
117 m_buckets.resize(m_nb_bucket);
118 m_buckets.fill(0);
119 _computeMaxCount();
120 }
121
127 HashTableMapT(Integer table_size, bool use_prime, Integer buffer_size)
128 : HashTableBase(table_size, use_prime)
129 , m_first_free(0)
130 , m_nb_collision(0)
131 , m_nb_direct(0)
132 {
133 m_buffer = new MultiBufferT<Data>(buffer_size);
134 m_buckets.resize(m_nb_bucket);
135 m_buckets.fill(0);
136 _computeMaxCount();
137 }
138
140 {
141 delete m_buffer;
142 }
143
145 ThatClass& operator=(const ThatClass& from)
146 {
147 if (&from == this)
148 return *this;
149 //cout << "** OPERATOR= this=" << this << '\n';
150 Integer nb_bucket = from.m_nb_bucket;
151 m_first_free = 0;
152 // Resets the counter.
153 m_count = 0;
154 m_buckets.resize(nb_bucket);
155 m_buckets.fill(0);
156 _computeMaxCount();
157 delete m_buffer;
158 m_buffer = new MultiBufferT<Data>(nb_bucket);
159 ConstArrayView<Data*> from_buckets(from.buckets());
160 for (Integer i = 0; i < nb_bucket; ++i)
161 for (Data* data = from_buckets[i]; data; data = data->next())
162 _add(i, data->key(), data->value());
163 this->m_nb_bucket = nb_bucket;
164 return *this;
165 }
166
167 public:
168
170 bool hasKey(KeyTypeConstRef id)
171 {
172 Integer hf = _keyToBucket(id);
173 for (Data* i = m_buckets[hf]; i; i = i->m_next) {
174 if (i->key() == id)
175 return true;
176 }
177 return false;
178 }
179
181 void clear()
182 {
183 m_buckets.fill(0);
184 m_count = 0;
185 }
186
192 Data* lookup(KeyTypeConstRef id)
193 {
194 return _lookup(id);
195 }
196
202 const Data* lookup(KeyTypeConstRef id) const
203 {
204 return _lookup(id);
205 }
206
212 ValueType& lookupValue(KeyTypeConstRef id)
213 {
214 Data* ht = _lookup(id);
215 if (!ht) {
216 this->_throwNotFound(id, Printable());
217 }
218 return ht->value();
219 }
220
226 ValueType& operator[](KeyTypeConstRef id)
227 {
228 return lookupValue(id);
229 }
230
236 const ValueType& lookupValue(KeyTypeConstRef id) const
237 {
238 const Data* ht = _lookup(id);
239 if (!ht) {
240 this->_throwNotFound(id, Printable());
241 }
242 return ht->m_value;
243 }
244
250 const ValueType& operator[](KeyTypeConstRef id) const
251 {
252 return lookupValue(id);
253 }
254
263 bool add(KeyTypeConstRef id, const ValueType& value)
264 {
265 Integer hf = _keyToBucket(id);
266 Data* ht = _lookupBucket(hf, id);
267 if (ht) {
268 ht->m_value = value;
269 return false;
270 }
271 _add(hf, id, value);
272 _checkResize();
273 return true;
274 }
275
279 void remove(KeyTypeConstRef id)
280 {
281 Integer hf = _keyToBucket(id);
282 Data* ht = _removeBucket(hf, id);
283 ht->setNext(m_first_free);
284 m_first_free = ht;
285 }
286
297 Data* lookupAdd(KeyTypeConstRef id, const ValueType& value, bool& is_add)
298 {
299 HashValueType hf = _applyHash(id);
300 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
301 if (ht) {
302 is_add = false;
303 return ht;
304 }
305 is_add = true;
306 // Always perform the resize before returning the add
307 // because it may invalidate the Data*
308 _checkResize();
309 ht = _add(_hashValueToBucket(hf), id, value);
310 return ht;
311 }
312
323 Data* lookupAdd(KeyTypeConstRef id)
324 {
325 HashValueType hf = _applyHash(id);
326 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
327 if (!ht) {
328 // Always perform the resize before returning the add
329 // because it may invalidate the Data*
330 _checkResize();
331 // The resize changes the bucket associated with a key
332 ht = _add(_hashValueToBucket(hf), id, ValueType());
333 }
334 return ht;
335 }
336
343 void nocheckAdd(KeyTypeConstRef id, const ValueType& value)
344 {
345 _checkResize();
346 Integer hf = _keyToBucket(id);
347 _add(hf, id, value);
348 }
349
350 ArrayView<Data*> buckets()
351 {
352 return m_buckets;
353 }
354
355 ConstArrayView<Data*> buckets() const
356 {
357 return m_buckets;
358 }
359
361 void resize(Integer new_size, bool use_prime = false)
362 {
363 if (use_prime)
364 new_size = this->nearestPrimeNumber(new_size);
365 if (new_size == 0) {
366 m_nb_bucket = new_size;
367 clear();
368 return;
369 }
370 if (new_size == m_nb_bucket)
371 return;
372 _rehash(new_size);
373 }
374
376 void rehash()
377 {
379 }
380
381 public:
382
384 template <class Lambda> void
385 each(const Lambda& lambda)
386 {
387 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
388 Data* nbid = m_buckets[k];
389 for (; nbid; nbid = nbid->next()) {
390 lambda(nbid);
391 }
392 }
393 }
394
399 template <class Lambda> void
400 eachValue(const Lambda& lambda)
401 {
402 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
403 Data* nbid = m_buckets[k];
404 for (; nbid; nbid = nbid->next()) {
405 lambda(nbid->value());
406 }
407 }
408 }
409
410 private:
411
413 void _rehash(Integer new_size)
414 {
415 //todo: delete the allocation of this array
416 UniqueArray<Data*> old_buckets(m_buckets);
417 m_count = 0;
418 m_nb_bucket = new_size;
419 m_buckets.resize(new_size);
420 m_buckets.fill(0);
421 MultiBufferT<Data>* old_buffer = m_buffer;
422 m_first_free = 0;
424 for (Integer z = 0, zs = old_buckets.size(); z < zs; ++z) {
425 for (Data* i = old_buckets[z]; i; i = i->next()) {
426 Data* current = i;
427 {
428 _add(_keyToBucket(current->key()), current->key(), current->value());
429 //Data* new_data = m_buffer->allocOne();
430 //new_data->setValue(current->value());
431 //_baseAdd(_hash(current->key()),current->key(),new_data);
432 }
433 }
434 }
435 delete old_buffer;
436 _computeMaxCount();
437 }
438
439 private:
440
442 Data* m_first_free = nullptr;
443
444 public:
445
446 mutable Int64 m_nb_collision = 0;
447 mutable Int64 m_nb_direct = 0;
448
449 private:
450
451 Data* _add(Integer bucket, KeyTypeConstRef key, const ValueType& value)
452 {
453 Data* hd = 0;
454 if (m_first_free) {
455 hd = m_first_free;
456 m_first_free = m_first_free->next();
457 }
458 else
459 hd = m_buffer->allocOne();
460 hd->setValue(value);
461 _baseAdd(bucket, key, hd);
462 return hd;
463 }
464
465 HashValueType _applyHash(KeyTypeConstRef id) const
466 {
467 //return (Integer)(KeyTraitsType::hashFunction(id) % m_nb_bucket);
468 return KeyTraitsType::hashFunction(id);
469 }
470
471 Integer _keyToBucket(KeyTypeConstRef id) const
472 {
473 return (Integer)(_applyHash(id) % m_nb_bucket);
474 }
475
476 Integer _hashValueToBucket(KeyTypeValue id) const
477 {
478 return (Integer)(id % m_nb_bucket);
479 }
480
481 Data* _baseLookupBucket(Integer bucket, KeyTypeConstRef id) const
482 {
483 for (Data* i = m_buckets[bucket]; i; i = i->next()) {
484 if (!(i->key() == id)) {
485 ++m_nb_collision;
486 continue;
487 }
488 ++m_nb_direct;
489 return i;
490 }
491 return 0;
492 }
493
494 Data* _baseRemoveBucket(Integer bucket, KeyTypeConstRef id)
495 {
496 Data* i = m_buckets[bucket];
497 if (i) {
498 if (i->m_key == id) {
499 m_buckets[bucket] = i->next();
500 --m_count;
501 return i;
502 }
503 for (; i->next(); i = i->next()) {
504 if (i->next()->key() == id) {
505 Data* r = i->next();
506 i->setNext(i->next()->next());
507 --m_count;
508 return r;
509 }
510 }
511 }
512 this->_throwNotFound(id, Printable());
513 return 0;
514 }
515
516 inline Data* _baseLookup(KeyTypeConstRef id) const
517 {
518 return _baseLookupBucket(_keyToBucket(id), id);
519 }
520
521 inline Data* _baseRemove(KeyTypeConstRef id)
522 {
523 return _baseRemoveBucket(_keyToBucket(id), id);
524 }
525
526 void _baseAdd(Integer bucket, KeyTypeConstRef id, Data* hd)
527 {
528 Data* buck = m_buckets[bucket];
529 hd->m_key = id;
530 hd->m_next = buck;
531 m_buckets[bucket] = hd;
532 ++m_count;
533 }
534
535 Data* _lookup(KeyTypeConstRef id)
536 {
537 return _baseLookup(id);
538 }
539
540 const Data* _lookup(KeyTypeConstRef id) const
541 {
542 return _baseLookup(id);
543 }
544
545 Data* _lookupBucket(Integer bucket, KeyTypeConstRef id) const
546 {
547 return _baseLookupBucket(bucket, id);
548 }
549
550 Data* _removeBucket(Integer bucket, KeyTypeConstRef id)
551 {
552 return _baseRemoveBucket(bucket, id);
553 }
554
555 void _checkResize()
556 {
557 // Resize if necessary.
558 if (m_count > m_max_count) {
559 //cout << "** BEFORE BUCKET RESIZE this=" << this << " count=" << m_count
560 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
561 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
562 //_print(Printable());
563 // For large tables, increase less quickly to limit
564 // memory consumption
565 if (m_nb_bucket > 200000) {
566 resize((Integer)(1.3 * m_nb_bucket), true);
567 }
568 else if (m_nb_bucket > 10000) {
569 resize((Integer)(1.5 * m_nb_bucket), true);
570 }
571 else
572 resize(2 * m_nb_bucket, true);
573 //cout << "** AFTER BUCKET RESIZE this=" << this << " count=" << m_count
574 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
575 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
576 //_print(Printable());
577 //std::cout.flush();
578 }
579 }
580
581 void _print(FalseType)
582 {
583 }
584
585 void _print(TrueType)
586 {
587 for (Integer z = 0, zs = m_buckets.size(); z < zs; ++z) {
588 for (Data* i = m_buckets[z]; i; i = i->next()) {
589 std::cout << "* KEY=" << i->key() << " bucket=" << z << '\n';
590 }
591 }
592 }
593
594 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef, FalseType) const
595 {
596 HashTableBase::_throwNotFound();
597 }
598
599 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef id, TrueType) const
600 {
601 std::cout << "ERROR: can not find key=" << id << " bucket=" << _keyToBucket(id) << "\n";
602 std::cout.flush();
603 HashTableBase::_throwNotFound();
604 }
605
606 void _computeMaxCount()
607 {
608 m_max_count = (Integer)(m_nb_bucket * 0.85);
609 }
610
611 private:
612
615 UniqueArray<Data*> m_buckets;
616};
617
618/*---------------------------------------------------------------------------*/
619/*---------------------------------------------------------------------------*/
620
625template <typename KeyType, typename ValueType>
626class HashTableMapEnumeratorT
627{
628 typedef HashTableMapT<KeyType, ValueType> HashType;
629 typedef typename HashType::Data Data;
630
631 public:
632
633 HashTableMapEnumeratorT(const HashType& rhs)
634 : m_buckets(rhs.buckets())
635 , m_current_data(0)
636 , m_current_bucket(-1)
637 {}
638
639 public:
640
641 bool operator++()
642 {
643 if (m_current_data)
644 m_current_data = m_current_data->next();
645 if (!m_current_data) {
646 while (m_current_data == 0 && (m_current_bucket + 1) < m_buckets.size()) {
647 ++m_current_bucket;
648 m_current_data = m_buckets[m_current_bucket];
649 }
650 }
651 return m_current_data != 0;
652 }
653 ValueType& operator*() { return m_current_data->value(); }
654 const ValueType& operator*() const { return m_current_data->value(); }
655 Data* data() { return m_current_data; }
656 const Data* data() const { return m_current_data; }
657
658 public:
659
660 ConstArrayView<Data*> m_buckets;
661 Data* m_current_data;
662 Integer m_current_bucket;
663};
664
665/*---------------------------------------------------------------------------*/
666/*---------------------------------------------------------------------------*/
667
668} // namespace Arcane
669
670/*---------------------------------------------------------------------------*/
671/*---------------------------------------------------------------------------*/
672
673#endif
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
Constant view of an array of type T.
HashTableBase(Integer table_size, bool use_prime)
Creates a table of size table_size.
Definition HashTable.h:46
Integer m_nb_bucket
Number of buckets.
Definition HashTable.h:77
Integer nearestPrimeNumber(Integer n)
Returns the nearest prime number greater than n. The nearest prime number greater than n is returned ...
Definition HashTable.cc:57
Integer m_count
Number of elements.
Definition HashTable.h:76
Enumerator for a HashTableMap.
Hash table for associative arrays.
const ValueType & operator[](KeyTypeConstRef id) const
Searches for the value corresponding to key id.
void rehash()
Rehashes the data after changing key values.
HashTableMapT(Integer table_size, bool use_prime, Integer buffer_size)
Creates a table of size table_size.
void nocheckAdd(KeyTypeConstRef id, const ValueType &value)
Adds the value value corresponding to the key id.
const Data * lookup(KeyTypeConstRef id) const
Searches for the value corresponding to key id.
Data * lookup(KeyTypeConstRef id)
Searches for the value corresponding to key id.
Data * lookupAdd(KeyTypeConstRef id, const ValueType &value, bool &is_add)
Searches for or adds the value corresponding to key id.
void remove(KeyTypeConstRef id)
Removes the value associated with key id.
void _rehash(Integer new_size)
Rehashes the data after changing key values.
void resize(Integer new_size, bool use_prime=false)
Resizes the hash table.
ValueType & lookupValue(KeyTypeConstRef id)
Searches for the value corresponding to key id.
ThatClass & operator=(const ThatClass &from)
Copy assignment operator.
ValueType & operator[](KeyTypeConstRef id)
Searches for the value corresponding to key id.
bool add(KeyTypeConstRef id, const ValueType &value)
Adds the value value corresponding to key id.
void eachValue(const Lambda &lambda)
Applies the functor f to all elements of the collection and uses x->value() (of type ValueType) as an...
void clear()
Deletes all elements from the table.
void each(const Lambda &lambda)
Applies the functor f to all elements of the collection.
const ValueType & lookupValue(KeyTypeConstRef id) const
Searches for the value corresponding to key id.
HashTableMapT(Integer table_size, bool use_prime)
Creates a table of size table_size.
Data * lookupAdd(KeyTypeConstRef id)
Searches for or adds the value corresponding to key id.
bool hasKey(KeyTypeConstRef id)
true if a value with key id is present
Buffer for multiple allocation.
Definition MultiBuffer.h:45
1D data vector with value semantics (STL style).
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
void setValue(const ValueType &avalue)
Modifies the value of the instance.
ValueType m_value
Element value.
KeyTypeValue m_key
Search key.
void setKey(const KeyType &new_key)
Changes the value of the key.