00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifndef HashTable_C
00027 #define HashTable_C
00028
00029 #include "HashTable.H"
00030 #include <OpenFOAM/List.H>
00031
00032
00033
00034 template<class T, class Key, class Hash>
00035 Foam::label Foam::HashTable<T, Key, Hash>::canonicalSize(const label size)
00036 {
00037 if (size < 1)
00038 {
00039 return 0;
00040 }
00041
00042
00043 unsigned int goodSize = size;
00044
00045 if (goodSize & (goodSize - 1))
00046 {
00047
00048 goodSize = 1;
00049 while (goodSize < unsigned(size))
00050 {
00051 goodSize <<= 1;
00052 }
00053 }
00054
00055 return goodSize;
00056 }
00057
00058
00059
00060
00061 template<class T, class Key, class Hash>
00062 Foam::HashTable<T, Key, Hash>::HashTable(const label size)
00063 :
00064 HashTableName(),
00065 nElmts_(0),
00066 tableSize_(canonicalSize(size)),
00067 table_(NULL),
00068 endIter_(*this, NULL, 0),
00069 endConstIter_(*this, NULL, 0)
00070 {
00071 if (tableSize_)
00072 {
00073 table_ = new hashedEntry*[tableSize_];
00074
00075 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
00076 {
00077 table_[hashIdx] = 0;
00078 }
00079 }
00080 }
00081
00082
00083 template<class T, class Key, class Hash>
00084 Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
00085 :
00086 HashTableName(),
00087 nElmts_(0),
00088 tableSize_(ht.tableSize_),
00089 table_(NULL),
00090 endIter_(*this, NULL, 0),
00091 endConstIter_(*this, NULL, 0)
00092 {
00093 if (tableSize_)
00094 {
00095 table_ = new hashedEntry*[tableSize_];
00096
00097 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
00098 {
00099 table_[hashIdx] = 0;
00100 }
00101
00102 for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
00103 {
00104 insert(iter.key(), *iter);
00105 }
00106 }
00107 }
00108
00109 template<class T, class Key, class Hash>
00110 Foam::HashTable<T, Key, Hash>::HashTable
00111 (
00112 const Xfer<HashTable<T, Key, Hash> >& ht
00113 )
00114 :
00115 HashTableName(),
00116 nElmts_(0),
00117 tableSize_(0),
00118 table_(NULL),
00119 endIter_(*this, NULL, 0),
00120 endConstIter_(*this, NULL, 0)
00121 {
00122 transfer(ht());
00123 }
00124
00125
00126
00127
00128 template<class T, class Key, class Hash>
00129 Foam::HashTable<T, Key, Hash>::~HashTable()
00130 {
00131 if (table_)
00132 {
00133 clear();
00134 delete[] table_;
00135 }
00136 }
00137
00138
00139
00140
00141 template<class T, class Key, class Hash>
00142 bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
00143 {
00144 if (nElmts_)
00145 {
00146 const label hashIdx = hashKeyIndex(key);
00147
00148 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
00149 {
00150 if (key == ep->key_)
00151 {
00152 return true;
00153 }
00154 }
00155 }
00156
00157 # ifdef FULLDEBUG
00158 if (debug)
00159 {
00160 Info<< "HashTable<T, Key, Hash>::found(const Key& key) : "
00161 << "Entry " << key << " not found in hash table\n";
00162 }
00163 # endif
00164
00165 return false;
00166 }
00167
00168
00169 template<class T, class Key, class Hash>
00170 typename Foam::HashTable<T, Key, Hash>::iterator
00171 Foam::HashTable<T, Key, Hash>::find
00172 (
00173 const Key& key
00174 )
00175 {
00176 if (nElmts_)
00177 {
00178 const label hashIdx = hashKeyIndex(key);
00179
00180 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
00181 {
00182 if (key == ep->key_)
00183 {
00184 return iterator(*this, ep, hashIdx);
00185 }
00186 }
00187 }
00188
00189 # ifdef FULLDEBUG
00190 if (debug)
00191 {
00192 Info<< "HashTable<T, Key, Hash>::find(const Key& key) : "
00193 << "Entry " << key << " not found in hash table\n";
00194 }
00195 # endif
00196
00197 return end();
00198 }
00199
00200
00201 template<class T, class Key, class Hash>
00202 typename Foam::HashTable<T, Key, Hash>::const_iterator
00203 Foam::HashTable<T, Key, Hash>::find
00204 (
00205 const Key& key
00206 ) const
00207 {
00208 if (nElmts_)
00209 {
00210 const label hashIdx = hashKeyIndex(key);
00211
00212 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
00213 {
00214 if (key == ep->key_)
00215 {
00216 return const_iterator(*this, ep, hashIdx);
00217 }
00218 }
00219 }
00220
00221 # ifdef FULLDEBUG
00222 if (debug)
00223 {
00224 Info<< "HashTable<T, Key, Hash>::find(const Key& key) const : "
00225 << "Entry " << key << " not found in hash table\n";
00226 }
00227 # endif
00228
00229 return cend();
00230 }
00231
00232
00233
00234 template<class T, class Key, class Hash>
00235 Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
00236 {
00237 List<Key> tofc(nElmts_);
00238 label i = 0;
00239
00240 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
00241 {
00242 tofc[i++] = iter.key();
00243 }
00244
00245 return tofc;
00246 }
00247
00248
00249 template<class T, class Key, class Hash>
00250 Foam::List<Key> Foam::HashTable<T, Key, Hash>::sortedToc() const
00251 {
00252 List<Key> sortedLst = this->toc();
00253 sort(sortedLst);
00254
00255 return sortedLst;
00256 }
00257
00258
00259 template<class T, class Key, class Hash>
00260 bool Foam::HashTable<T, Key, Hash>::set
00261 (
00262 const Key& key,
00263 const T& newEntry,
00264 const bool protect
00265 )
00266 {
00267 if (!tableSize_)
00268 {
00269 resize(2);
00270 }
00271
00272 const label hashIdx = hashKeyIndex(key);
00273
00274 hashedEntry* existing = 0;
00275 hashedEntry* prev = 0;
00276
00277 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
00278 {
00279 if (key == ep->key_)
00280 {
00281 existing = ep;
00282 break;
00283 }
00284 prev = ep;
00285 }
00286
00287
00288 if (!existing)
00289 {
00290 table_[hashIdx] = new hashedEntry(key, table_[hashIdx], newEntry);
00291 nElmts_++;
00292
00293 if (double(nElmts_)/tableSize_ > 0.8)
00294 {
00295 # ifdef FULLDEBUG
00296 if (debug)
00297 {
00298 Info<< "HashTable<T, Key, Hash>::set"
00299 "(const Key& key, T newEntry) : "
00300 "Doubling table size\n";
00301 }
00302 # endif
00303
00304 resize(2*tableSize_);
00305 }
00306 }
00307 else if (protect)
00308 {
00309
00310
00311 # ifdef FULLDEBUG
00312 if (debug)
00313 {
00314 Info<< "HashTable<T, Key, Hash>::set"
00315 "(const Key& key, T newEntry, true) : "
00316 "Cannot insert " << key << " already in hash table\n";
00317 }
00318 # endif
00319 return false;
00320 }
00321 else
00322 {
00323
00324
00325 hashedEntry* ep = new hashedEntry(key, existing->next_, newEntry);
00326
00327
00328 if (prev)
00329 {
00330 prev->next_ = ep;
00331 }
00332 else
00333 {
00334 table_[hashIdx] = ep;
00335 }
00336
00337 delete existing;
00338 }
00339
00340 return true;
00341 }
00342
00343
00344 template<class T, class Key, class Hash>
00345 bool Foam::HashTable<T, Key, Hash>::erase(const iterator& cit)
00346 {
00347 if (cit.elmtPtr_)
00348 {
00349 iterator& it = const_cast<iterator&>(cit);
00350
00351
00352 hashedEntry* prev = 0;
00353
00354 for (hashedEntry* ep = table_[it.hashIndex_]; ep; ep = ep->next_)
00355 {
00356 if (ep == it.elmtPtr_)
00357 {
00358 break;
00359 }
00360 prev = ep;
00361 }
00362
00363 if (prev)
00364 {
00365
00366 prev->next_ = it.elmtPtr_->next_;
00367 delete it.elmtPtr_;
00368 it.elmtPtr_ = prev;
00369 }
00370 else
00371 {
00372
00373 table_[it.hashIndex_] = it.elmtPtr_->next_;
00374 delete it.elmtPtr_;
00375
00376
00377 while (--it.hashIndex_ >= 0 && !table_[it.hashIndex_])
00378 {}
00379
00380 if (it.hashIndex_ >= 0)
00381 {
00382
00383 it.elmtPtr_ = table_[it.hashIndex_];
00384
00385 while (it.elmtPtr_ && it.elmtPtr_->next_)
00386 {
00387 it.elmtPtr_ = it.elmtPtr_->next_;
00388 }
00389 }
00390 else
00391 {
00392
00393
00394
00395 it.elmtPtr_ = reinterpret_cast<hashedEntry*>(this);
00396 it.hashIndex_ = -1;
00397 }
00398 }
00399
00400 nElmts_--;
00401
00402 # ifdef FULLDEBUG
00403 if (debug)
00404 {
00405 Info<< "HashTable<T, Key, Hash>::erase(iterator&) : "
00406 << "hashedEntry " << it.elmtPtr_->key_ << " removed.\n";
00407 }
00408 # endif
00409
00410 return true;
00411 }
00412 else
00413 {
00414 # ifdef FULLDEBUG
00415 if (debug)
00416 {
00417 Info<< "HashTable<T, Key, Hash>::erase(iterator&) : "
00418 << "cannot remove hashedEntry from hash table\n";
00419 }
00420 # endif
00421
00422 return false;
00423 }
00424 }
00425
00426
00427 template<class T, class Key, class Hash>
00428 bool Foam::HashTable<T, Key, Hash>::erase(const Key& key)
00429 {
00430 iterator fnd = find(key);
00431
00432 if (fnd != end())
00433 {
00434 return erase(fnd);
00435 }
00436 else
00437 {
00438 return false;
00439 }
00440 }
00441
00442
00443 template<class T, class Key, class Hash>
00444 Foam::label Foam::HashTable<T, Key, Hash>::erase(const UList<Key>& keys)
00445 {
00446 label count = 0;
00447
00448
00449 if (this->size())
00450 {
00451 forAll(keys, keyI)
00452 {
00453 if (erase(keys[keyI]))
00454 {
00455 count++;
00456 }
00457 }
00458 }
00459
00460 return count;
00461 }
00462
00463
00464 template<class T, class Key, class Hash>
00465 template<class AnyType, class AnyHash>
00466 Foam::label Foam::HashTable<T, Key, Hash>::erase
00467 (
00468 const HashTable<AnyType, Key, AnyHash>& rhs
00469 )
00470 {
00471 label count = 0;
00472
00473
00474
00475 for (iterator iter = begin(); iter != end(); ++iter)
00476 {
00477 if (rhs.found(iter.key()) && erase(iter))
00478 {
00479 count++;
00480 }
00481 }
00482
00483 return count;
00484 }
00485
00486
00487 template<class T, class Key, class Hash>
00488 void Foam::HashTable<T, Key, Hash>::resize(const label sz)
00489 {
00490 label newSize = canonicalSize(sz);
00491
00492 if (newSize == tableSize_)
00493 {
00494 # ifdef FULLDEBUG
00495 if (debug)
00496 {
00497 Info<< "HashTable<T, Key, Hash>::resize(const label) : "
00498 << "new table size == old table size\n";
00499 }
00500 # endif
00501
00502 return;
00503 }
00504
00505 HashTable<T, Key, Hash>* newTable = new HashTable<T, Key, Hash>(newSize);
00506
00507 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
00508 {
00509 newTable->insert(iter.key(), *iter);
00510 }
00511
00512 label oldTableSize = tableSize_;
00513 tableSize_ = newTable->tableSize_;
00514 newTable->tableSize_ = oldTableSize;
00515
00516 hashedEntry** oldTable = table_;
00517 table_ = newTable->table_;
00518 newTable->table_ = oldTable;
00519
00520 delete newTable;
00521 }
00522
00523
00524 template<class T, class Key, class Hash>
00525 void Foam::HashTable<T, Key, Hash>::clear()
00526 {
00527 if (nElmts_)
00528 {
00529 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
00530 {
00531 if (table_[hashIdx])
00532 {
00533 hashedEntry* ep = table_[hashIdx];
00534 while (hashedEntry* next = ep->next_)
00535 {
00536 delete ep;
00537 ep = next;
00538 }
00539 delete ep;
00540 table_[hashIdx] = 0;
00541 }
00542 }
00543 nElmts_ = 0;
00544 }
00545 }
00546
00547
00548 template<class T, class Key, class Hash>
00549 void Foam::HashTable<T, Key, Hash>::clearStorage()
00550 {
00551 clear();
00552 resize(0);
00553 }
00554
00555
00556 template<class T, class Key, class Hash>
00557 void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
00558 {
00559
00560 if (table_)
00561 {
00562 clear();
00563 delete[] table_;
00564 }
00565
00566 tableSize_ = ht.tableSize_;
00567 ht.tableSize_ = 0;
00568
00569 table_ = ht.table_;
00570 ht.table_ = NULL;
00571
00572 nElmts_ = ht.nElmts_;
00573 ht.nElmts_ = 0;
00574 }
00575
00576
00577
00578
00579 template<class T, class Key, class Hash>
00580 void Foam::HashTable<T, Key, Hash>::operator=
00581 (
00582 const HashTable<T, Key, Hash>& rhs
00583 )
00584 {
00585
00586 if (this == &rhs)
00587 {
00588 FatalErrorIn
00589 (
00590 "HashTable<T, Key, Hash>::operator="
00591 "(const HashTable<T, Key, Hash>&)"
00592 ) << "attempted assignment to self"
00593 << abort(FatalError);
00594 }
00595
00596
00597 if (!tableSize_)
00598 {
00599 resize(rhs.tableSize_);
00600 }
00601 else
00602 {
00603 clear();
00604 }
00605
00606 for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
00607 {
00608 insert(iter.key(), *iter);
00609 }
00610 }
00611
00612
00613 template<class T, class Key, class Hash>
00614 bool Foam::HashTable<T, Key, Hash>::operator==
00615 (
00616 const HashTable<T, Key, Hash>& rhs
00617 ) const
00618 {
00619
00620 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
00621 {
00622 const_iterator fnd = rhs.find(iter.key());
00623
00624 if (fnd == rhs.cend() || fnd() != iter())
00625 {
00626 return false;
00627 }
00628 }
00629
00630
00631 for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
00632 {
00633 const_iterator fnd = find(iter.key());
00634
00635 if (fnd == cend() || fnd() != iter())
00636 {
00637 return false;
00638 }
00639 }
00640 return true;
00641 }
00642
00643
00644 template<class T, class Key, class Hash>
00645 bool Foam::HashTable<T, Key, Hash>::operator!=
00646 (
00647 const HashTable<T, Key, Hash>& rhs
00648 ) const
00649 {
00650 return !(operator==(rhs));
00651 }
00652
00653
00654
00655
00656 #include <OpenFOAM/HashTableIO.C>
00657
00658
00659
00660 #endif
00661
00662