Arcane  4.1.12.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-2024 */
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/*---------------------------------------------------------------------------*/
20/*---------------------------------------------------------------------------*/
21
22namespace Arcane
23{
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28template <typename KeyType, typename ValueType>
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
49template <typename KeyType, typename ValueType, typename KeyTraitsType = HashTraitsT<KeyType>>
51: public HashTableBase
52{
53 public:
54
55 typedef typename KeyTraitsType::KeyTypeConstRef KeyTypeConstRef;
56 typedef typename KeyTraitsType::KeyTypeValue KeyTypeValue;
57 typedef typename KeyTraitsType::Printable Printable;
58 typedef typename KeyTraitsType::HashValueType HashValueType;
61
62 public:
63
64 struct Data
65 {
66 public:
67
68 Data()
69 : m_key(KeyTypeValue())
71 {}
72
73 public:
74
75 Data* next() { return m_next; }
76 void setNext(Data* anext) { this->m_next = anext; }
77 KeyTypeConstRef key() { return m_key; }
78 const ValueType& value() const { return m_value; }
79 ValueType& value() { return m_value; }
81 void setValue(const ValueType& avalue) { m_value = avalue; }
87 void setKey(const KeyType& new_key)
88 {
89 m_key = new_key;
90 }
91
92 public:
93
94 KeyTypeValue m_key;
96 Data* m_next = nullptr;
97 };
98
99 public:
100
106 HashTableMapT(Integer table_size, bool use_prime)
107 : HashTableBase(table_size, use_prime)
108 , m_first_free(0)
109 , m_nb_collision(0)
110 , m_nb_direct(0)
111 , m_max_count(0)
112 {
114 m_buckets.resize(m_nb_bucket);
115 m_buckets.fill(0);
116 _computeMaxCount();
117 }
118
124 HashTableMapT(Integer table_size, bool use_prime, Integer buffer_size)
125 : HashTableBase(table_size, use_prime)
126 , m_first_free(0)
127 , m_nb_collision(0)
128 , m_nb_direct(0)
129 {
130 m_buffer = new MultiBufferT<Data>(buffer_size);
131 m_buckets.resize(m_nb_bucket);
132 m_buckets.fill(0);
133 _computeMaxCount();
134 }
135
137 {
138 delete m_buffer;
139 }
140
142 ThatClass& operator=(const ThatClass& from)
143 {
144 if (&from == this)
145 return *this;
146 //cout << "** OPERATOR= this=" << this << '\n';
147 Integer nb_bucket = from.m_nb_bucket;
148 m_first_free = 0;
149 // Resets the counter.
150 m_count = 0;
151 m_buckets.resize(nb_bucket);
152 m_buckets.fill(0);
153 _computeMaxCount();
154 delete m_buffer;
155 m_buffer = new MultiBufferT<Data>(nb_bucket);
156 ConstArrayView<Data*> from_buckets(from.buckets());
157 for (Integer i = 0; i < nb_bucket; ++i)
158 for (Data* data = from_buckets[i]; data; data = data->next())
159 _add(i, data->key(), data->value());
160 this->m_nb_bucket = nb_bucket;
161 return *this;
162 }
163
164 public:
165
167 bool hasKey(KeyTypeConstRef id)
168 {
169 Integer hf = _keyToBucket(id);
170 for (Data* i = m_buckets[hf]; i; i = i->m_next) {
171 if (i->key() == id)
172 return true;
173 }
174 return false;
175 }
176
178 void clear()
179 {
180 m_buckets.fill(0);
181 m_count = 0;
182 }
183
189 Data* lookup(KeyTypeConstRef id)
190 {
191 return _lookup(id);
192 }
193
199 const Data* lookup(KeyTypeConstRef id) const
200 {
201 return _lookup(id);
202 }
203
209 ValueType& lookupValue(KeyTypeConstRef id)
210 {
211 Data* ht = _lookup(id);
212 if (!ht) {
213 this->_throwNotFound(id, Printable());
214 }
215 return ht->value();
216 }
217
223 ValueType& operator[](KeyTypeConstRef id)
224 {
225 return lookupValue(id);
226 }
227
233 const ValueType& lookupValue(KeyTypeConstRef id) const
234 {
235 const Data* ht = _lookup(id);
236 if (!ht) {
237 this->_throwNotFound(id, Printable());
238 }
239 return ht->m_value;
240 }
241
247 const ValueType& operator[](KeyTypeConstRef id) const
248 {
249 return lookupValue(id);
250 }
251
260 bool add(KeyTypeConstRef id, const ValueType& value)
261 {
262 Integer hf = _keyToBucket(id);
263 Data* ht = _lookupBucket(hf, id);
264 if (ht) {
265 ht->m_value = value;
266 return false;
267 }
268 _add(hf, id, value);
269 _checkResize();
270 return true;
271 }
272
276 void remove(KeyTypeConstRef id)
277 {
278 Integer hf = _keyToBucket(id);
279 Data* ht = _removeBucket(hf, id);
280 ht->setNext(m_first_free);
281 m_first_free = ht;
282 }
283
294 Data* lookupAdd(KeyTypeConstRef id, const ValueType& value, bool& is_add)
295 {
296 HashValueType hf = _applyHash(id);
297 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
298 if (ht) {
299 is_add = false;
300 return ht;
301 }
302 is_add = true;
303 // Always perform the resize before returning the add
304 // because it may invalidate the Data*
305 _checkResize();
306 ht = _add(_hashValueToBucket(hf), id, value);
307 return ht;
308 }
309
320 Data* lookupAdd(KeyTypeConstRef id)
321 {
322 HashValueType hf = _applyHash(id);
323 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
324 if (!ht) {
325 // Always perform the resize before returning the add
326 // because it may invalidate the Data*
327 _checkResize();
328 // The resize changes the bucket associated with a key
329 ht = _add(_hashValueToBucket(hf), id, ValueType());
330 }
331 return ht;
332 }
333
340 void nocheckAdd(KeyTypeConstRef id, const ValueType& value)
341 {
342 _checkResize();
343 Integer hf = _keyToBucket(id);
344 _add(hf, id, value);
345 }
346
347 ArrayView<Data*> buckets()
348 {
349 return m_buckets;
350 }
351
352 ConstArrayView<Data*> buckets() const
353 {
354 return m_buckets;
355 }
356
358 void resize(Integer new_size, bool use_prime = false)
359 {
360 if (use_prime)
361 new_size = this->nearestPrimeNumber(new_size);
362 if (new_size == 0) {
363 m_nb_bucket = new_size;
364 clear();
365 return;
366 }
367 if (new_size == m_nb_bucket)
368 return;
369 _rehash(new_size);
370 }
371
373 void rehash()
374 {
376 }
377
378 public:
379
381 template <class Lambda> void
382 each(const Lambda& lambda)
383 {
384 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
385 Data* nbid = m_buckets[k];
386 for (; nbid; nbid = nbid->next()) {
387 lambda(nbid);
388 }
389 }
390 }
391
396 template <class Lambda> void
397 eachValue(const Lambda& lambda)
398 {
399 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
400 Data* nbid = m_buckets[k];
401 for (; nbid; nbid = nbid->next()) {
402 lambda(nbid->value());
403 }
404 }
405 }
406
407 private:
408
410 void _rehash(Integer new_size)
411 {
412 //todo: delete the allocation of this array
413 UniqueArray<Data*> old_buckets(m_buckets);
414 m_count = 0;
415 m_nb_bucket = new_size;
416 m_buckets.resize(new_size);
417 m_buckets.fill(0);
418 MultiBufferT<Data>* old_buffer = m_buffer;
419 m_first_free = 0;
421 for (Integer z = 0, zs = old_buckets.size(); z < zs; ++z) {
422 for (Data* i = old_buckets[z]; i; i = i->next()) {
423 Data* current = i;
424 {
425 _add(_keyToBucket(current->key()), current->key(), current->value());
426 //Data* new_data = m_buffer->allocOne();
427 //new_data->setValue(current->value());
428 //_baseAdd(_hash(current->key()),current->key(),new_data);
429 }
430 }
431 }
432 delete old_buffer;
433 _computeMaxCount();
434 }
435
436 private:
437
439 Data* m_first_free = nullptr;
440
441 public:
442
443 mutable Int64 m_nb_collision = 0;
444 mutable Int64 m_nb_direct = 0;
445
446 private:
447
448 Data* _add(Integer bucket, KeyTypeConstRef key, const ValueType& value)
449 {
450 Data* hd = 0;
451 if (m_first_free) {
452 hd = m_first_free;
453 m_first_free = m_first_free->next();
454 }
455 else
456 hd = m_buffer->allocOne();
457 hd->setValue(value);
458 _baseAdd(bucket, key, hd);
459 return hd;
460 }
461
462 HashValueType _applyHash(KeyTypeConstRef id) const
463 {
464 //return (Integer)(KeyTraitsType::hashFunction(id) % m_nb_bucket);
465 return KeyTraitsType::hashFunction(id);
466 }
467
468 Integer _keyToBucket(KeyTypeConstRef id) const
469 {
470 return (Integer)(_applyHash(id) % m_nb_bucket);
471 }
472
473 Integer _hashValueToBucket(KeyTypeValue id) const
474 {
475 return (Integer)(id % m_nb_bucket);
476 }
477
478 Data* _baseLookupBucket(Integer bucket, KeyTypeConstRef id) const
479 {
480 for (Data* i = m_buckets[bucket]; i; i = i->next()) {
481 if (!(i->key() == id)) {
482 ++m_nb_collision;
483 continue;
484 }
485 ++m_nb_direct;
486 return i;
487 }
488 return 0;
489 }
490
491 Data* _baseRemoveBucket(Integer bucket, KeyTypeConstRef id)
492 {
493 Data* i = m_buckets[bucket];
494 if (i) {
495 if (i->m_key == id) {
496 m_buckets[bucket] = i->next();
497 --m_count;
498 return i;
499 }
500 for (; i->next(); i = i->next()) {
501 if (i->next()->key() == id) {
502 Data* r = i->next();
503 i->setNext(i->next()->next());
504 --m_count;
505 return r;
506 }
507 }
508 }
509 this->_throwNotFound(id, Printable());
510 return 0;
511 }
512
513 inline Data* _baseLookup(KeyTypeConstRef id) const
514 {
515 return _baseLookupBucket(_keyToBucket(id), id);
516 }
517
518 inline Data* _baseRemove(KeyTypeConstRef id)
519 {
520 return _baseRemoveBucket(_keyToBucket(id), id);
521 }
522
523 void _baseAdd(Integer bucket, KeyTypeConstRef id, Data* hd)
524 {
525 Data* buck = m_buckets[bucket];
526 hd->m_key = id;
527 hd->m_next = buck;
528 m_buckets[bucket] = hd;
529 ++m_count;
530 }
531
532 Data* _lookup(KeyTypeConstRef id)
533 {
534 return _baseLookup(id);
535 }
536
537 const Data* _lookup(KeyTypeConstRef id) const
538 {
539 return _baseLookup(id);
540 }
541
542 Data* _lookupBucket(Integer bucket, KeyTypeConstRef id) const
543 {
544 return _baseLookupBucket(bucket, id);
545 }
546
547 Data* _removeBucket(Integer bucket, KeyTypeConstRef id)
548 {
549 return _baseRemoveBucket(bucket, id);
550 }
551
552 void _checkResize()
553 {
554 // Resize if necessary.
555 if (m_count > m_max_count) {
556 //cout << "** BEFORE BUCKET RESIZE this=" << this << " count=" << m_count
557 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
558 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
559 //_print(Printable());
560 // For large tables, increase less quickly to limit
561 // memory consumption
562 if (m_nb_bucket > 200000) {
563 resize((Integer)(1.3 * m_nb_bucket), true);
564 }
565 else if (m_nb_bucket > 10000) {
566 resize((Integer)(1.5 * m_nb_bucket), true);
567 }
568 else
569 resize(2 * m_nb_bucket, true);
570 //cout << "** AFTER BUCKET RESIZE this=" << this << " count=" << m_count
571 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
572 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
573 //_print(Printable());
574 std::cout.flush();
575 }
576 }
577
578 void _print(FalseType)
579 {
580 }
581
582 void _print(TrueType)
583 {
584 for (Integer z = 0, zs = m_buckets.size(); z < zs; ++z) {
585 for (Data* i = m_buckets[z]; i; i = i->next()) {
586 cout << "* KEY=" << i->key() << " bucket=" << z << '\n';
587 }
588 }
589 }
590
591 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef, FalseType) const
592 {
593 HashTableBase::_throwNotFound();
594 }
595
596 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef id, TrueType) const
597 {
598 std::cout << "ERROR: can not find key=" << id << " bucket=" << _keyToBucket(id) << "\n";
599 std::cout.flush();
600 HashTableBase::_throwNotFound();
601 }
602
603 void _computeMaxCount()
604 {
605 m_max_count = (Integer)(m_nb_bucket * 0.85);
606 }
607
608 private:
609
612 UniqueArray<Data*> m_buckets;
613};
614
615/*---------------------------------------------------------------------------*/
616/*---------------------------------------------------------------------------*/
617
622template <typename KeyType, typename ValueType>
623class HashTableMapEnumeratorT
624{
625 typedef HashTableMapT<KeyType, ValueType> HashType;
626 typedef typename HashType::Data Data;
627
628 public:
629
630 HashTableMapEnumeratorT(const HashType& rhs)
631 : m_buckets(rhs.buckets())
632 , m_current_data(0)
633 , m_current_bucket(-1)
634 {}
635
636 public:
637
638 bool operator++()
639 {
640 if (m_current_data)
641 m_current_data = m_current_data->next();
642 if (!m_current_data) {
643 while (m_current_data == 0 && (m_current_bucket + 1) < m_buckets.size()) {
644 ++m_current_bucket;
645 m_current_data = m_buckets[m_current_bucket];
646 }
647 }
648 return m_current_data != 0;
649 }
650 ValueType& operator*() { return m_current_data->value(); }
651 const ValueType& operator*() const { return m_current_data->value(); }
652 Data* data() { return m_current_data; }
653 const Data* data() const { return m_current_data; }
654
655 public:
656
657 ConstArrayView<Data*> m_buckets;
658 Data* m_current_data;
659 Integer m_current_bucket;
660};
661
662/*---------------------------------------------------------------------------*/
663/*---------------------------------------------------------------------------*/
664
665} // namespace Arcane
666
667/*---------------------------------------------------------------------------*/
668/*---------------------------------------------------------------------------*/
669
670#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.