Arcane  4.2.1.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
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/* Tableau associatif utilisant une table de hachage. */
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/*---------------------------------------------------------------------------*/
53template <typename KeyType, typename ValueType, typename KeyTraitsType = HashTraitsT<KeyType>>
55: public HashTableBase
56{
57 public:
58
59 typedef typename KeyTraitsType::KeyTypeConstRef KeyTypeConstRef;
60 typedef typename KeyTraitsType::KeyTypeValue KeyTypeValue;
61 typedef typename KeyTraitsType::Printable Printable;
62 typedef typename KeyTraitsType::HashValueType HashValueType;
65
66 public:
67
68 struct Data
69 {
70 public:
71
72 Data()
73 : m_key(KeyTypeValue())
75 {}
76
77 public:
78
79 Data* next() { return m_next; }
80 void setNext(Data* anext) { this->m_next = anext; }
81 KeyTypeConstRef key() { return m_key; }
82 const ValueType& value() const { return m_value; }
83 ValueType& value() { return m_value; }
85 void setValue(const ValueType& avalue) { m_value = avalue; }
91 void setKey(const KeyType& new_key)
92 {
93 m_key = new_key;
94 }
95
96 public:
97
98 KeyTypeValue m_key;
100 Data* m_next = nullptr;
101 };
102
103 public:
104
110 HashTableMapT(Integer table_size, bool use_prime)
111 : HashTableBase(table_size, use_prime)
112 , m_first_free(0)
113 , m_nb_collision(0)
114 , m_nb_direct(0)
115 , m_max_count(0)
116 {
118 m_buckets.resize(m_nb_bucket);
119 m_buckets.fill(0);
120 _computeMaxCount();
121 }
122
128 HashTableMapT(Integer table_size, bool use_prime, Integer buffer_size)
129 : HashTableBase(table_size, use_prime)
130 , m_first_free(0)
131 , m_nb_collision(0)
132 , m_nb_direct(0)
133 {
134 m_buffer = new MultiBufferT<Data>(buffer_size);
135 m_buckets.resize(m_nb_bucket);
136 m_buckets.fill(0);
137 _computeMaxCount();
138 }
139
141 {
142 delete m_buffer;
143 }
144
146 ThatClass& operator=(const ThatClass& from)
147 {
148 if (&from == this)
149 return *this;
150 //cout << "** OPERATOR= this=" << this << '\n';
151 Integer nb_bucket = from.m_nb_bucket;
152 m_first_free = 0;
153 // Remet à zéro le compteur.
154 m_count = 0;
155 m_buckets.resize(nb_bucket);
156 m_buckets.fill(0);
157 _computeMaxCount();
158 delete m_buffer;
159 m_buffer = new MultiBufferT<Data>(nb_bucket);
160 ConstArrayView<Data*> from_buckets(from.buckets());
161 for (Integer i = 0; i < nb_bucket; ++i)
162 for (Data* data = from_buckets[i]; data; data = data->next())
163 _add(i, data->key(), data->value());
164 this->m_nb_bucket = nb_bucket;
165 return *this;
166 }
167
168 public:
169
171 bool hasKey(KeyTypeConstRef id)
172 {
173 Integer hf = _keyToBucket(id);
174 for (Data* i = m_buckets[hf]; i; i = i->m_next) {
175 if (i->key() == id)
176 return true;
177 }
178 return false;
179 }
180
182 void clear()
183 {
184 m_buckets.fill(0);
185 m_count = 0;
186 }
187
193 Data* lookup(KeyTypeConstRef id)
194 {
195 return _lookup(id);
196 }
197
203 const Data* lookup(KeyTypeConstRef id) const
204 {
205 return _lookup(id);
206 }
207
213 ValueType& lookupValue(KeyTypeConstRef id)
214 {
215 Data* ht = _lookup(id);
216 if (!ht) {
217 this->_throwNotFound(id, Printable());
218 }
219 return ht->value();
220 }
221
227 ValueType& operator[](KeyTypeConstRef id)
228 {
229 return lookupValue(id);
230 }
231
237 const ValueType& lookupValue(KeyTypeConstRef id) const
238 {
239 const Data* ht = _lookup(id);
240 if (!ht) {
241 this->_throwNotFound(id, Printable());
242 }
243 return ht->m_value;
244 }
245
251 const ValueType& operator[](KeyTypeConstRef id) const
252 {
253 return lookupValue(id);
254 }
255
264 bool add(KeyTypeConstRef id, const ValueType& value)
265 {
266 Integer hf = _keyToBucket(id);
267 Data* ht = _lookupBucket(hf, id);
268 if (ht) {
269 ht->m_value = value;
270 return false;
271 }
272 _add(hf, id, value);
273 _checkResize();
274 return true;
275 }
276
280 void remove(KeyTypeConstRef id)
281 {
282 Integer hf = _keyToBucket(id);
283 Data* ht = _removeBucket(hf, id);
284 ht->setNext(m_first_free);
285 m_first_free = ht;
286 }
287
298 Data* lookupAdd(KeyTypeConstRef id, const ValueType& value, bool& is_add)
299 {
300 HashValueType hf = _applyHash(id);
301 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
302 if (ht) {
303 is_add = false;
304 return ht;
305 }
306 is_add = true;
307 // Toujours faire le resize avant de retourner le add
308 // car cela peut invalider le Data*
309 _checkResize();
310 ht = _add(_hashValueToBucket(hf), id, value);
311 return ht;
312 }
313
324 Data* lookupAdd(KeyTypeConstRef id)
325 {
326 HashValueType hf = _applyHash(id);
327 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
328 if (!ht) {
329 // Toujours faire le resize avant de retourner le add
330 // car cela peut invalider le Data*
331 _checkResize();
332 // Le resize provoque change le bucket associé à une clé
333 ht = _add(_hashValueToBucket(hf), id, ValueType());
334 }
335 return ht;
336 }
337
344 void nocheckAdd(KeyTypeConstRef id, const ValueType& value)
345 {
346 _checkResize();
347 Integer hf = _keyToBucket(id);
348 _add(hf, id, value);
349 }
350
351 ArrayView<Data*> buckets()
352 {
353 return m_buckets;
354 }
355
356 ConstArrayView<Data*> buckets() const
357 {
358 return m_buckets;
359 }
360
362 void resize(Integer new_size, bool use_prime = false)
363 {
364 if (use_prime)
365 new_size = this->nearestPrimeNumber(new_size);
366 if (new_size == 0) {
367 m_nb_bucket = new_size;
368 clear();
369 return;
370 }
371 if (new_size == m_nb_bucket)
372 return;
373 _rehash(new_size);
374 }
375
377 void rehash()
378 {
380 }
381
382 public:
383
385 template <class Lambda> void
386 each(const Lambda& lambda)
387 {
388 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
389 Data* nbid = m_buckets[k];
390 for (; nbid; nbid = nbid->next()) {
391 lambda(nbid);
392 }
393 }
394 }
395
400 template <class Lambda> void
401 eachValue(const Lambda& lambda)
402 {
403 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
404 Data* nbid = m_buckets[k];
405 for (; nbid; nbid = nbid->next()) {
406 lambda(nbid->value());
407 }
408 }
409 }
410
411 private:
412
414 void _rehash(Integer new_size)
415 {
416 //todo: supprimer l'allocation de ce tableau
417 UniqueArray<Data*> old_buckets(m_buckets);
418 m_count = 0;
419 m_nb_bucket = new_size;
420 m_buckets.resize(new_size);
421 m_buckets.fill(0);
422 MultiBufferT<Data>* old_buffer = m_buffer;
423 m_first_free = 0;
425 for (Integer z = 0, zs = old_buckets.size(); z < zs; ++z) {
426 for (Data* i = old_buckets[z]; i; i = i->next()) {
427 Data* current = i;
428 {
429 _add(_keyToBucket(current->key()), current->key(), current->value());
430 //Data* new_data = m_buffer->allocOne();
431 //new_data->setValue(current->value());
432 //_baseAdd(_hash(current->key()),current->key(),new_data);
433 }
434 }
435 }
436 delete old_buffer;
437 _computeMaxCount();
438 }
439
440 private:
441
443 Data* m_first_free = nullptr;
444
445 public:
446
447 mutable Int64 m_nb_collision = 0;
448 mutable Int64 m_nb_direct = 0;
449
450 private:
451
452 Data* _add(Integer bucket, KeyTypeConstRef key, const ValueType& value)
453 {
454 Data* hd = 0;
455 if (m_first_free) {
456 hd = m_first_free;
457 m_first_free = m_first_free->next();
458 }
459 else
460 hd = m_buffer->allocOne();
461 hd->setValue(value);
462 _baseAdd(bucket, key, hd);
463 return hd;
464 }
465
466 HashValueType _applyHash(KeyTypeConstRef id) const
467 {
468 //return (Integer)(KeyTraitsType::hashFunction(id) % m_nb_bucket);
469 return KeyTraitsType::hashFunction(id);
470 }
471
472 Integer _keyToBucket(KeyTypeConstRef id) const
473 {
474 return (Integer)(_applyHash(id) % m_nb_bucket);
475 }
476
477 Integer _hashValueToBucket(KeyTypeValue id) const
478 {
479 return (Integer)(id % m_nb_bucket);
480 }
481
482 Data* _baseLookupBucket(Integer bucket, KeyTypeConstRef id) const
483 {
484 for (Data* i = m_buckets[bucket]; i; i = i->next()) {
485 if (!(i->key() == id)) {
486 ++m_nb_collision;
487 continue;
488 }
489 ++m_nb_direct;
490 return i;
491 }
492 return 0;
493 }
494
495 Data* _baseRemoveBucket(Integer bucket, KeyTypeConstRef id)
496 {
497 Data* i = m_buckets[bucket];
498 if (i) {
499 if (i->m_key == id) {
500 m_buckets[bucket] = i->next();
501 --m_count;
502 return i;
503 }
504 for (; i->next(); i = i->next()) {
505 if (i->next()->key() == id) {
506 Data* r = i->next();
507 i->setNext(i->next()->next());
508 --m_count;
509 return r;
510 }
511 }
512 }
513 this->_throwNotFound(id, Printable());
514 return 0;
515 }
516
517 inline Data* _baseLookup(KeyTypeConstRef id) const
518 {
519 return _baseLookupBucket(_keyToBucket(id), id);
520 }
521
522 inline Data* _baseRemove(KeyTypeConstRef id)
523 {
524 return _baseRemoveBucket(_keyToBucket(id), id);
525 }
526
527 void _baseAdd(Integer bucket, KeyTypeConstRef id, Data* hd)
528 {
529 Data* buck = m_buckets[bucket];
530 hd->m_key = id;
531 hd->m_next = buck;
532 m_buckets[bucket] = hd;
533 ++m_count;
534 }
535
536 Data* _lookup(KeyTypeConstRef id)
537 {
538 return _baseLookup(id);
539 }
540
541 const Data* _lookup(KeyTypeConstRef id) const
542 {
543 return _baseLookup(id);
544 }
545
546 Data* _lookupBucket(Integer bucket, KeyTypeConstRef id) const
547 {
548 return _baseLookupBucket(bucket, id);
549 }
550
551 Data* _removeBucket(Integer bucket, KeyTypeConstRef id)
552 {
553 return _baseRemoveBucket(bucket, id);
554 }
555
556 void _checkResize()
557 {
558 // Retaille si besoin.
559 if (m_count > m_max_count) {
560 //cout << "** AVANT REDIMENSIONNEMENT DU COMPARTIMENT this=" << this << " count=" << m_count
561 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
562 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
563 //_print(Printable());
564 // Pour les grosses tables, augmente moins vite pour limiter la
565 // consommation memoire
566 if (m_nb_bucket > 200000) {
567 resize((Integer)(1.3 * m_nb_bucket), true);
568 }
569 else if (m_nb_bucket > 10000) {
570 resize((Integer)(1.5 * m_nb_bucket), true);
571 }
572 else
573 resize(2 * m_nb_bucket, true);
574 //cout << "** APRÈS REDIMENSIONNEMENT DU COMPARTIMENT this=" << this << " count=" << m_count
575 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
576 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
577 //_print(Printable());
578 //std::cout.flush();
579 }
580 }
581
582 void _print(FalseType)
583 {
584 }
585
586 void _print(TrueType)
587 {
588 for (Integer z = 0, zs = m_buckets.size(); z < zs; ++z) {
589 for (Data* i = m_buckets[z]; i; i = i->next()) {
590 std::cout << "* KEY=" << i->key() << " bucket=" << z << '\n';
591 }
592 }
593 }
594
595 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef, FalseType) const
596 {
597 HashTableBase::_throwNotFound();
598 }
599
600 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef id, TrueType) const
601 {
602 std::cout << "ERROR: can not find key=" << id << " bucket=" << _keyToBucket(id) << "\n";
603 std::cout.flush();
604 HashTableBase::_throwNotFound();
605 }
606
607 void _computeMaxCount()
608 {
609 m_max_count = (Integer)(m_nb_bucket * 0.85);
610 }
611
612 private:
613
616 UniqueArray<Data*> m_buckets;
617};
618
619/*---------------------------------------------------------------------------*/
620/*---------------------------------------------------------------------------*/
621
626template <typename KeyType, typename ValueType>
627class HashTableMapEnumeratorT
628{
629 typedef HashTableMapT<KeyType, ValueType> HashType;
630 typedef typename HashType::Data Data;
631
632 public:
633
634 HashTableMapEnumeratorT(const HashType& rhs)
635 : m_buckets(rhs.buckets())
636 , m_current_data(0)
637 , m_current_bucket(-1)
638 {}
639
640 public:
641
642 bool operator++()
643 {
644 if (m_current_data)
645 m_current_data = m_current_data->next();
646 if (!m_current_data) {
647 while (m_current_data == 0 && (m_current_bucket + 1) < m_buckets.size()) {
648 ++m_current_bucket;
649 m_current_data = m_buckets[m_current_bucket];
650 }
651 }
652 return m_current_data != 0;
653 }
654 ValueType& operator*() { return m_current_data->value(); }
655 const ValueType& operator*() const { return m_current_data->value(); }
656 Data* data() { return m_current_data; }
657 const Data* data() const { return m_current_data; }
658
659 public:
660
661 ConstArrayView<Data*> m_buckets;
662 Data* m_current_data;
663 Integer m_current_bucket;
664};
665
666/*---------------------------------------------------------------------------*/
667/*---------------------------------------------------------------------------*/
668
669} // namespace Arcane
670
671/*---------------------------------------------------------------------------*/
672/*---------------------------------------------------------------------------*/
673
674#endif
Integer size() const
Nombre d'éléments du vecteur.
Vue modifiable d'un tableau d'un type T.
Vue constante d'un tableau de type T.
HashTableBase(Integer table_size, bool use_prime)
Crée une table de taille table_size.
Definition HashTable.h:45
Integer m_nb_bucket
Nombre de buckets.
Definition HashTable.h:75
Integer nearestPrimeNumber(Integer n)
Retourne le nombre premier le plus proche de n par excès. Le nombre premier le plus proche et supérie...
Definition HashTable.cc:57
Integer m_count
Nombre d'éléments.
Definition HashTable.h:74
Énumérateur pour un HashTableMap.
Table de hachage pour tableaux associatifs.
const ValueType & operator[](KeyTypeConstRef id) const
Recherche la valeur correspondant à la clé id.
void rehash()
Repositionne les données après changement de valeur des clés.
HashTableMapT(Integer table_size, bool use_prime, Integer buffer_size)
Crée une table de taille table_size.
void nocheckAdd(KeyTypeConstRef id, const ValueType &value)
Ajoute la valeur value correspondant à la clé id.
const Data * lookup(KeyTypeConstRef id) const
Recherche la valeur correspondant à la clé id.
Data * lookup(KeyTypeConstRef id)
Recherche la valeur correspondant à la clé id.
Data * lookupAdd(KeyTypeConstRef id, const ValueType &value, bool &is_add)
Recherche ou ajoute la valeur correspondant à la clé id.
void remove(KeyTypeConstRef id)
Supprime la valeur associée à la clé id.
void _rehash(Integer new_size)
Repositionne les données après changement de valeur des clés.
void resize(Integer new_size, bool use_prime=false)
Redimensionne la table de hachage.
ValueType & lookupValue(KeyTypeConstRef id)
Recherche la valeur correspondant à la clé id.
ThatClass & operator=(const ThatClass &from)
Opérateur de recopie.
ValueType & operator[](KeyTypeConstRef id)
Recherche la valeur correspondant à la clé id.
bool add(KeyTypeConstRef id, const ValueType &value)
Ajoute la valeur value correspondant à la clé id.
void eachValue(const Lambda &lambda)
Applique le fonctor f à tous les éléments de la collection et utilise x->value() (de type ValueType) ...
void clear()
Supprime tous les éléments de la table.
void each(const Lambda &lambda)
Applique le fonctor f à tous les éléments de la collection.
const ValueType & lookupValue(KeyTypeConstRef id) const
Recherche la valeur correspondant à la clé id.
HashTableMapT(Integer table_size, bool use_prime)
Crée une table de taille table_size.
Data * lookupAdd(KeyTypeConstRef id)
Recherche ou ajoute la valeur correspondant à la clé id.
bool hasKey(KeyTypeConstRef id)
true si une valeur avec la clé id est présente
Tampon pour allocation multiple.
Definition MultiBuffer.h:44
Vecteur 1D de données avec sémantique par valeur (style STL).
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Type entier signé sur 64 bits.
Int32 Integer
Type représentant un entier.
void setValue(const ValueType &avalue)
Modifie la valeur de l'instance.
ValueType m_value
Valeur de l'élément.
KeyTypeValue m_key
Clé de recherche.
void setKey(const KeyType &new_key)
Change la valeur de la clé.