Arcane  v3.14.10.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-2024 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/* 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/*---------------------------------------------------------------------------*/
20/*---------------------------------------------------------------------------*/
21
22namespace Arcane
23{
24
25/*---------------------------------------------------------------------------*/
26/*---------------------------------------------------------------------------*/
27
28template <typename KeyType, typename ValueType>
29class HashTableMapEnumeratorT;
30
31/*---------------------------------------------------------------------------*/
32/*---------------------------------------------------------------------------*/
51template <typename KeyType, typename ValueType, typename KeyTraitsType = HashTraitsT<KeyType>>
53: public HashTableBase
54{
55 public:
56
57 typedef typename KeyTraitsType::KeyTypeConstRef KeyTypeConstRef;
58 typedef typename KeyTraitsType::KeyTypeValue KeyTypeValue;
59 typedef typename KeyTraitsType::Printable Printable;
60 typedef typename KeyTraitsType::HashValueType HashValueType;
63
64 public:
65
66 struct Data
67 {
68 public:
69
70 Data()
71 : m_key(KeyTypeValue())
72 , m_value(ValueType())
73 {}
74
75 public:
76
77 Data* next() { return m_next; }
78 void setNext(Data* anext) { this->m_next = anext; }
79 KeyTypeConstRef key() { return m_key; }
80 const ValueType& value() const { return m_value; }
81 ValueType& value() { return m_value; }
83 void setValue(const ValueType& avalue) { m_value = avalue; }
89 void setKey(const KeyType& new_key)
90 {
91 m_key = new_key;
92 }
93
94 public:
95
96 KeyTypeValue m_key;
97 ValueType m_value;
98 Data* m_next = nullptr;
99 };
100
101 public:
102
110 , m_first_free(0)
111 , m_nb_collision(0)
112 , m_nb_direct(0)
113 , m_max_count(0)
114 {
116 m_buckets.resize(m_nb_bucket);
117 m_buckets.fill(0);
118 _computeMaxCount();
119 }
120
128 , m_first_free(0)
129 , m_nb_collision(0)
130 , m_nb_direct(0)
131 {
133 m_buckets.resize(m_nb_bucket);
134 m_buckets.fill(0);
135 _computeMaxCount();
136 }
137
139 {
140 delete m_buffer;
141 }
142
145 {
146 if (&from == this)
147 return *this;
148 //cout << "** OPERATOR= this=" << this << '\n';
149 Integer nb_bucket = from.m_nb_bucket;
150 m_first_free = 0;
151 // Remet à zéro le compteur.
152 m_count = 0;
153 m_buckets.resize(nb_bucket);
154 m_buckets.fill(0);
155 _computeMaxCount();
156 delete m_buffer;
159 for (Integer i = 0; i < nb_bucket; ++i)
160 for (Data* data = from_buckets[i]; data; data = data->next())
161 _add(i, data->key(), data->value());
162 this->m_nb_bucket = nb_bucket;
163 return *this;
164 }
165
166 public:
167
169 bool hasKey(KeyTypeConstRef id)
170 {
171 Integer hf = _keyToBucket(id);
172 for (Data* i = m_buckets[hf]; i; i = i->m_next) {
173 if (i->key() == id)
174 return true;
175 }
176 return false;
177 }
178
180 void clear()
181 {
182 m_buckets.fill(0);
183 m_count = 0;
184 }
185
191 Data* lookup(KeyTypeConstRef id)
192 {
193 return _lookup(id);
194 }
195
201 const Data* lookup(KeyTypeConstRef id) const
202 {
203 return _lookup(id);
204 }
205
211 ValueType& lookupValue(KeyTypeConstRef id)
212 {
213 Data* ht = _lookup(id);
214 if (!ht) {
215 this->_throwNotFound(id, Printable());
216 }
217 return ht->value();
218 }
219
225 ValueType& operator[](KeyTypeConstRef id)
226 {
227 return lookupValue(id);
228 }
229
235 const ValueType& lookupValue(KeyTypeConstRef id) const
236 {
237 const Data* ht = _lookup(id);
238 if (!ht) {
239 this->_throwNotFound(id, Printable());
240 }
241 return ht->m_value;
242 }
243
249 const ValueType& operator[](KeyTypeConstRef id) const
250 {
251 return lookupValue(id);
252 }
253
262 bool add(KeyTypeConstRef id, const ValueType& value)
263 {
264 Integer hf = _keyToBucket(id);
265 Data* ht = _lookupBucket(hf, id);
266 if (ht) {
267 ht->m_value = value;
268 return false;
269 }
270 _add(hf, id, value);
271 _checkResize();
272 return true;
273 }
274
278 void remove(KeyTypeConstRef id)
279 {
280 Integer hf = _keyToBucket(id);
281 Data* ht = _removeBucket(hf, id);
282 ht->setNext(m_first_free);
284 }
285
296 Data* lookupAdd(KeyTypeConstRef id, const ValueType& value, bool& is_add)
297 {
298 HashValueType hf = _applyHash(id);
299 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
300 if (ht) {
301 is_add = false;
302 return ht;
303 }
304 is_add = true;
305 // Toujours faire le resize avant de retourner le add
306 // car cela peut invalider le Data*
307 _checkResize();
308 ht = _add(_hashValueToBucket(hf), id, value);
309 return ht;
310 }
311
322 Data* lookupAdd(KeyTypeConstRef id)
323 {
324 HashValueType hf = _applyHash(id);
325 Data* ht = _lookupBucket(_hashValueToBucket(hf), id);
326 if (!ht) {
327 // Toujours faire le resize avant de retourner le add
328 // car cela peut invalider le Data*
329 _checkResize();
330 // Le resize provoque change le bucket associé à une clé
331 ht = _add(_hashValueToBucket(hf), id, ValueType());
332 }
333 return ht;
334 }
335
342 void nocheckAdd(KeyTypeConstRef id, const ValueType& value)
343 {
344 _checkResize();
345 Integer hf = _keyToBucket(id);
346 _add(hf, id, value);
347 }
348
349 ArrayView<Data*> buckets()
350 {
351 return m_buckets;
352 }
353
354 ConstArrayView<Data*> buckets() const
355 {
356 return m_buckets;
357 }
358
360 void resize(Integer new_size, bool use_prime = false)
361 {
362 if (use_prime)
363 new_size = this->nearestPrimeNumber(new_size);
364 if (new_size == 0) {
366 clear();
367 return;
368 }
369 if (new_size == m_nb_bucket)
370 return;
372 }
373
375 void rehash()
376 {
378 }
379
380 public:
381
383 template <class Lambda> void
385 {
386 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
387 Data* nbid = m_buckets[k];
388 for (; nbid; nbid = nbid->next()) {
389 lambda(nbid);
390 }
391 }
392 }
393
398 template <class Lambda> void
400 {
401 for (Integer k = 0, n = m_buckets.size(); k < n; ++k) {
402 Data* nbid = m_buckets[k];
403 for (; nbid; nbid = nbid->next()) {
404 lambda(nbid->value());
405 }
406 }
407 }
408
409 private:
410
412 void _rehash(Integer new_size)
413 {
414 //todo: supprimer l'allocation de ce tableau
416 m_count = 0;
418 m_buckets.resize(new_size);
419 m_buckets.fill(0);
421 m_first_free = 0;
423 for (Integer z = 0, zs = old_buckets.size(); z < zs; ++z) {
424 for (Data* i = old_buckets[z]; i; i = i->next()) {
425 Data* current = i;
426 {
427 _add(_keyToBucket(current->key()), current->key(), current->value());
428 //Data* new_data = m_buffer->allocOne();
429 //new_data->setValue(current->value());
430 //_baseAdd(_hash(current->key()),current->key(),new_data);
431 }
432 }
433 }
434 delete old_buffer;
435 _computeMaxCount();
436 }
437
438 private:
439
441 Data* m_first_free = nullptr;
442
443 public:
444
445 mutable Int64 m_nb_collision = 0;
446 mutable Int64 m_nb_direct = 0;
447
448 private:
449
450 Data* _add(Integer bucket, KeyTypeConstRef key, const ValueType& value)
451 {
452 Data* hd = 0;
453 if (m_first_free) {
455 m_first_free = m_first_free->next();
456 }
457 else
458 hd = m_buffer->allocOne();
459 hd->setValue(value);
460 _baseAdd(bucket, key, hd);
461 return hd;
462 }
463
464 HashValueType _applyHash(KeyTypeConstRef id) const
465 {
466 //return (Integer)(KeyTraitsType::hashFunction(id) % m_nb_bucket);
467 return KeyTraitsType::hashFunction(id);
468 }
469
470 Integer _keyToBucket(KeyTypeConstRef id) const
471 {
472 return (Integer)(_applyHash(id) % m_nb_bucket);
473 }
474
475 Integer _hashValueToBucket(KeyTypeValue id) const
476 {
477 return (Integer)(id % m_nb_bucket);
478 }
479
480 Data* _baseLookupBucket(Integer bucket, KeyTypeConstRef id) const
481 {
482 for (Data* i = m_buckets[bucket]; i; i = i->next()) {
483 if (!(i->key() == id)) {
484 ++m_nb_collision;
485 continue;
486 }
487 ++m_nb_direct;
488 return i;
489 }
490 return 0;
491 }
492
493 Data* _baseRemoveBucket(Integer bucket, KeyTypeConstRef id)
494 {
495 Data* i = m_buckets[bucket];
496 if (i) {
497 if (i->m_key == id) {
498 m_buckets[bucket] = i->next();
499 --m_count;
500 return i;
501 }
502 for (; i->next(); i = i->next()) {
503 if (i->next()->key() == id) {
504 Data* r = i->next();
505 i->setNext(i->next()->next());
506 --m_count;
507 return r;
508 }
509 }
510 }
511 this->_throwNotFound(id, Printable());
512 return 0;
513 }
514
515 inline Data* _baseLookup(KeyTypeConstRef id) const
516 {
517 return _baseLookupBucket(_keyToBucket(id), id);
518 }
519
520 inline Data* _baseRemove(KeyTypeConstRef id)
521 {
522 return _baseRemoveBucket(_keyToBucket(id), id);
523 }
524
525 void _baseAdd(Integer bucket, KeyTypeConstRef id, Data* hd)
526 {
527 Data* buck = m_buckets[bucket];
528 hd->m_key = id;
529 hd->m_next = buck;
530 m_buckets[bucket] = hd;
531 ++m_count;
532 }
533
534 Data* _lookup(KeyTypeConstRef id)
535 {
536 return _baseLookup(id);
537 }
538
539 const Data* _lookup(KeyTypeConstRef id) const
540 {
541 return _baseLookup(id);
542 }
543
544 Data* _lookupBucket(Integer bucket, KeyTypeConstRef id) const
545 {
546 return _baseLookupBucket(bucket, id);
547 }
548
549 Data* _removeBucket(Integer bucket, KeyTypeConstRef id)
550 {
551 return _baseRemoveBucket(bucket, id);
552 }
553
554 void _checkResize()
555 {
556 // Retaille si besoin.
557 if (m_count > m_max_count) {
558 //cout << "** BEFORE BUCKET RESIZE this=" << this << " count=" << m_count
559 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
560 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
561 //_print(Printable());
562 // Pour les grosses tables, augmente moins vite pour limiter la
563 // consommation memoire
564 if (m_nb_bucket > 200000) {
565 resize((Integer)(1.3 * m_nb_bucket), true);
566 }
567 else if (m_nb_bucket > 10000) {
568 resize((Integer)(1.5 * m_nb_bucket), true);
569 }
570 else
571 resize(2 * m_nb_bucket, true);
572 //cout << "** AFTER BUCKET RESIZE this=" << this << " count=" << m_count
573 // << " bucket=" << m_nb_bucket << " m_max_count=" << m_max_count
574 // << " memory=" << (m_buckets.capacity()*sizeof(Data*)) << '\n';
575 //_print(Printable());
576 std::cout.flush();
577 }
578 }
579
580 void _print(FalseType)
581 {
582 }
583
584 void _print(TrueType)
585 {
586 for (Integer z = 0, zs = m_buckets.size(); z < zs; ++z) {
587 for (Data* i = m_buckets[z]; i; i = i->next()) {
588 cout << "* KEY=" << i->key() << " bucket=" << z << '\n';
589 }
590 }
591 }
592
593 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef, FalseType) const
594 {
595 HashTableBase::_throwNotFound();
596 }
597
598 void _throwNotFound ARCANE_NORETURN(KeyTypeConstRef id, TrueType) const
599 {
600 std::cout << "ERROR: can not find key=" << id << " bucket=" << _keyToBucket(id) << "\n";
601 std::cout.flush();
602 HashTableBase::_throwNotFound();
603 }
604
605 void _computeMaxCount()
606 {
607 m_max_count = (Integer)(m_nb_bucket * 0.85);
608 }
609
610 private:
611
613 Integer m_max_count = 0;
614 UniqueArray<Data*> m_buckets;
615};
616
617/*---------------------------------------------------------------------------*/
618/*---------------------------------------------------------------------------*/
623template <typename KeyType, typename ValueType>
625{
627 typedef typename HashType::Data Data;
628
629 public:
630
632 : m_buckets(rhs.buckets())
633 , m_current_data(0)
634 , m_current_bucket(-1)
635 {}
636
637 public:
638
639 bool operator++()
640 {
641 if (m_current_data)
642 m_current_data = m_current_data->next();
643 if (!m_current_data) {
644 while (m_current_data == 0 && (m_current_bucket + 1) < m_buckets.size()) {
645 ++m_current_bucket;
646 m_current_data = m_buckets[m_current_bucket];
647 }
648 }
649 return m_current_data != 0;
650 }
651 ValueType& operator*() { return m_current_data->value(); }
652 const ValueType& operator*() const { return m_current_data->value(); }
653 Data* data() { return m_current_data; }
654 const Data* data() const { return m_current_data; }
655
656 public:
657
658 ConstArrayView<Data*> m_buckets;
659 Data* m_current_data;
660 Integer m_current_bucket;
661};
662
663/*---------------------------------------------------------------------------*/
664/*---------------------------------------------------------------------------*/
665
666} // namespace Arcane
667
668/*---------------------------------------------------------------------------*/
669/*---------------------------------------------------------------------------*/
670
671#endif
Classe de base d'une table de hachage simple pour les entités.
Definition HashTable.h:37
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
Enumerateur sur 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.
MultiBufferT< Data > * m_buffer
Tampon d'allocation des valeurs.
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.
Data * m_first_free
Pointeur vers le premier Data utilisable.
bool hasKey(KeyTypeConstRef id)
true si une valeur avec la clé id est présente
Integer m_max_count
Nombre maximal d'élément avant retaillage.
Lecteur des fichiers de maillage via la bibliothèque LIMA.
Definition Lima.cc:120
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
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é.