1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 2004-2010 OpenCFD Ltd.
7 -------------------------------------------------------------------------------
9 This file is part of OpenFOAM.
11 OpenFOAM is free software: you can redistribute it and/or modify it
12 under the terms of the GNU General Public License as published by
13 the Free Software Foundation, either version 3 of the License, or
14 (at your option) any later version.
16 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21 You should have received a copy of the GNU General Public License
22 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
24 \*---------------------------------------------------------------------------*/
29 #include "HashTable.H"
32 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
34 template<class T, class Key, class Hash>
35 Foam::HashTable<T, Key, Hash>::HashTable(const label size)
39 tableSize_(HashTableCore::canonicalSize(size)),
44 table_ = new hashedEntry*[tableSize_];
46 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
54 template<class T, class Key, class Hash>
55 Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
59 tableSize_(ht.tableSize_),
64 table_ = new hashedEntry*[tableSize_];
66 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
71 for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
73 insert(iter.key(), *iter);
78 template<class T, class Key, class Hash>
79 Foam::HashTable<T, Key, Hash>::HashTable
81 const Xfer<HashTable<T, Key, Hash> >& ht
93 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
95 template<class T, class Key, class Hash>
96 Foam::HashTable<T, Key, Hash>::~HashTable()
106 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
108 template<class T, class Key, class Hash>
109 bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
113 const label hashIdx = hashKeyIndex(key);
115 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
127 Info<< "HashTable<T, Key, Hash>::found(const Key& key) : "
128 << "Entry " << key << " not found in hash table\n";
136 template<class T, class Key, class Hash>
137 typename Foam::HashTable<T, Key, Hash>::iterator
138 Foam::HashTable<T, Key, Hash>::find
145 const label hashIdx = hashKeyIndex(key);
147 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
151 return iterator(this, ep, hashIdx);
159 Info<< "HashTable<T, Key, Hash>::find(const Key& key) : "
160 << "Entry " << key << " not found in hash table\n";
168 template<class T, class Key, class Hash>
169 typename Foam::HashTable<T, Key, Hash>::const_iterator
170 Foam::HashTable<T, Key, Hash>::find
177 const label hashIdx = hashKeyIndex(key);
179 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
183 return const_iterator(this, ep, hashIdx);
191 Info<< "HashTable<T, Key, Hash>::find(const Key& key) const : "
192 << "Entry " << key << " not found in hash table\n";
196 return const_iterator();
200 template<class T, class Key, class Hash>
201 Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
203 List<Key> keys(nElmts_);
206 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
208 keys[keyI++] = iter.key();
215 template<class T, class Key, class Hash>
216 Foam::List<Key> Foam::HashTable<T, Key, Hash>::sortedToc() const
218 List<Key> sortedLst = this->toc();
225 template<class T, class Key, class Hash>
226 bool Foam::HashTable<T, Key, Hash>::set
238 const label hashIdx = hashKeyIndex(key);
240 hashedEntry* existing = 0;
241 hashedEntry* prev = 0;
243 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
253 // not found, insert it at the head
256 table_[hashIdx] = new hashedEntry(key, table_[hashIdx], newEntry);
259 if (double(nElmts_)/tableSize_ > 0.8 && tableSize_ < maxTableSize)
264 Info<< "HashTable<T, Key, Hash>::set"
265 "(const Key& key, T newEntry) : "
266 "Doubling table size\n";
270 resize(2*tableSize_);
275 // found - but protected from overwriting
276 // this corresponds to the STL 'insert' convention
280 Info<< "HashTable<T, Key, Hash>::set"
281 "(const Key& key, T newEntry, true) : "
282 "Cannot insert " << key << " already in hash table\n";
289 // found - overwrite existing entry
290 // this corresponds to the Perl convention
291 hashedEntry* ep = new hashedEntry(key, existing->next_, newEntry);
293 // replace existing element - within list or insert at the head
300 table_[hashIdx] = ep;
310 template<class T, class Key, class Hash>
311 bool Foam::HashTable<T, Key, Hash>::iteratorBase::erase()
313 // note: entryPtr_ is NULL for end(), so this catches that too
316 // Search element before entryPtr_
317 hashedEntry* prev = 0;
321 hashedEntry* ep = hashTable_->table_[hashIndex_];
335 // has an element before entryPtr - reposition to there
336 prev->next_ = entryPtr_->next_;
342 // entryPtr was first element on SLList
343 hashTable_->table_[hashIndex_] = entryPtr_->next_;
346 // assign any non-NULL pointer value so it doesn't look
348 entryPtr_ = reinterpret_cast<hashedEntry*>(this);
350 // Mark with special hashIndex value to signal it has been rewound.
351 // The next increment will bring it back to the present location.
353 // From the current position 'curPos', we wish to continue at
354 // prevPos='curPos-1', which we mark as markPos='-curPos-1'.
355 // The negative lets us notice it is special, the extra '-1'
356 // is needed to avoid ambiguity for position '0'.
357 // To retrieve prevPos, we would later use '-(markPos+1) - 1'
358 hashIndex_ = -hashIndex_ - 1;
361 hashTable_->nElmts_--;
374 // We use (const iterator&) here, but manipulate its contents anyhow.
375 // The parameter should be (iterator&), but then the compiler doesn't find
376 // it correctly and tries to call as (iterator) instead.
378 template<class T, class Key, class Hash>
379 bool Foam::HashTable<T, Key, Hash>::erase(const iterator& iter)
381 // adjust iterator after erase
382 return const_cast<iterator&>(iter).erase();
386 template<class T, class Key, class Hash>
387 bool Foam::HashTable<T, Key, Hash>::erase(const Key& key)
389 return erase(find(key));
393 template<class T, class Key, class Hash>
394 Foam::label Foam::HashTable<T, Key, Hash>::erase(const UList<Key>& keys)
396 const label nTotal = nElmts_;
399 // Remove listed keys from this table - terminates early if possible
400 for (label keyI = 0; count < nTotal && keyI < keys.size(); ++keyI)
402 if (erase(keys[keyI]))
412 template<class T, class Key, class Hash>
413 template<class AnyType, class AnyHash>
414 Foam::label Foam::HashTable<T, Key, Hash>::erase
416 const HashTable<AnyType, Key, AnyHash>& rhs
421 // Remove rhs keys from this table - terminates early if possible
422 // Could optimize depending on which hash is smaller ...
423 for (iterator iter = begin(); iter != end(); ++iter)
425 if (rhs.found(iter.key()) && erase(iter))
435 template<class T, class Key, class Hash>
436 void Foam::HashTable<T, Key, Hash>::resize(const label sz)
438 label newSize = HashTableCore::canonicalSize(sz);
440 if (newSize == tableSize_)
445 Info<< "HashTable<T, Key, Hash>::resize(const label) : "
446 << "new table size == old table size\n";
453 HashTable<T, Key, Hash>* tmpTable = new HashTable<T, Key, Hash>(newSize);
455 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
457 tmpTable->insert(iter.key(), *iter);
460 label oldSize = tableSize_;
461 tableSize_ = tmpTable->tableSize_;
462 tmpTable->tableSize_ = oldSize;
464 hashedEntry** oldTable = table_;
465 table_ = tmpTable->table_;
466 tmpTable->table_ = oldTable;
472 template<class T, class Key, class Hash>
473 void Foam::HashTable<T, Key, Hash>::clear()
477 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
481 hashedEntry* ep = table_[hashIdx];
482 while (hashedEntry* next = ep->next_)
496 template<class T, class Key, class Hash>
497 void Foam::HashTable<T, Key, Hash>::clearStorage()
504 template<class T, class Key, class Hash>
505 void Foam::HashTable<T, Key, Hash>::shrink()
507 const label newSize = HashTableCore::canonicalSize(nElmts_);
509 if (newSize < tableSize_)
511 // avoid having the table disappear on us
512 resize(newSize ? newSize : 2);
517 template<class T, class Key, class Hash>
518 void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
520 // as per the Destructor
527 tableSize_ = ht.tableSize_;
533 nElmts_ = ht.nElmts_;
538 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
540 template<class T, class Key, class Hash>
541 void Foam::HashTable<T, Key, Hash>::operator=
543 const HashTable<T, Key, Hash>& rhs
546 // Check for assignment to self
551 "HashTable<T, Key, Hash>::operator="
552 "(const HashTable<T, Key, Hash>&)"
553 ) << "attempted assignment to self"
554 << abort(FatalError);
557 // could be zero-sized from a previous transfer()
560 resize(rhs.tableSize_);
567 for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
569 insert(iter.key(), *iter);
574 template<class T, class Key, class Hash>
575 bool Foam::HashTable<T, Key, Hash>::operator==
577 const HashTable<T, Key, Hash>& rhs
580 // sizes (number of keys) must match
581 if (size() != rhs.size())
586 for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
588 const_iterator fnd = find(iter.key());
590 if (fnd == cend() || fnd() != iter())
600 template<class T, class Key, class Hash>
601 bool Foam::HashTable<T, Key, Hash>::operator!=
603 const HashTable<T, Key, Hash>& rhs
606 return !(operator==(rhs));
610 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
612 #include "HashTableIO.C"
614 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
618 // ************************************************************************* //