1 /*---------------------------------------------------------------------------*\
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
5 \\ / A nd | Copyright (C) 1991-2009 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 the
13 Free Software Foundation; either version 2 of the License, or (at your
14 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, write to the Free Software Foundation,
23 Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 \*---------------------------------------------------------------------------*/
30 #include "HashTable.H"
33 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
35 template<class T, class Key, class Hash>
36 Foam::label Foam::HashTable<T, Key, Hash>::canonicalSize(const label size)
43 // enforce power of two
44 unsigned int goodSize = size;
46 if (goodSize & (goodSize - 1))
48 // brute-force is fast enough
50 while (goodSize < unsigned(size))
60 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
62 template<class T, class Key, class Hash>
63 Foam::HashTable<T, Key, Hash>::HashTable(const label size)
67 tableSize_(canonicalSize(size)),
69 endIter_(*this, NULL, 0),
70 endConstIter_(*this, NULL, 0)
74 table_ = new hashedEntry*[tableSize_];
76 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
84 template<class T, class Key, class Hash>
85 Foam::HashTable<T, Key, Hash>::HashTable(const HashTable<T, Key, Hash>& ht)
89 tableSize_(ht.tableSize_),
91 endIter_(*this, NULL, 0),
92 endConstIter_(*this, NULL, 0)
96 table_ = new hashedEntry*[tableSize_];
98 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
103 for (const_iterator iter = ht.cbegin(); iter != ht.cend(); ++iter)
105 insert(iter.key(), *iter);
110 template<class T, class Key, class Hash>
111 Foam::HashTable<T, Key, Hash>::HashTable
113 const Xfer<HashTable<T, Key, Hash> >& ht
120 endIter_(*this, NULL, 0),
121 endConstIter_(*this, NULL, 0)
127 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
129 template<class T, class Key, class Hash>
130 Foam::HashTable<T, Key, Hash>::~HashTable()
140 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
142 template<class T, class Key, class Hash>
143 bool Foam::HashTable<T, Key, Hash>::found(const Key& key) const
147 const label hashIdx = hashKeyIndex(key);
149 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
161 Info<< "HashTable<T, Key, Hash>::found(const Key& key) : "
162 << "Entry " << key << " not found in hash table\n";
170 template<class T, class Key, class Hash>
171 typename Foam::HashTable<T, Key, Hash>::iterator
172 Foam::HashTable<T, Key, Hash>::find
179 const label hashIdx = hashKeyIndex(key);
181 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
185 return iterator(*this, ep, hashIdx);
193 Info<< "HashTable<T, Key, Hash>::find(const Key& key) : "
194 << "Entry " << key << " not found in hash table\n";
202 template<class T, class Key, class Hash>
203 typename Foam::HashTable<T, Key, Hash>::const_iterator
204 Foam::HashTable<T, Key, Hash>::find
211 const label hashIdx = hashKeyIndex(key);
213 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
217 return const_iterator(*this, ep, hashIdx);
225 Info<< "HashTable<T, Key, Hash>::find(const Key& key) const : "
226 << "Entry " << key << " not found in hash table\n";
234 // Return the table of contents
235 template<class T, class Key, class Hash>
236 Foam::List<Key> Foam::HashTable<T, Key, Hash>::toc() const
238 List<Key> tofc(nElmts_);
241 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
243 tofc[i++] = iter.key();
250 template<class T, class Key, class Hash>
251 bool Foam::HashTable<T, Key, Hash>::set
263 const label hashIdx = hashKeyIndex(key);
265 hashedEntry* existing = 0;
266 hashedEntry* prev = 0;
268 for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_)
278 // not found, insert it at the head
281 table_[hashIdx] = new hashedEntry(key, table_[hashIdx], newEntry);
284 if (double(nElmts_)/tableSize_ > 0.8)
289 Info<< "HashTable<T, Key, Hash>::set"
290 "(const Key& key, T newEntry) : "
291 "Doubling table size\n";
295 resize(2*tableSize_);
300 // found - but protected from overwriting
301 // this corresponds to the STL 'insert' convention
305 Info<< "HashTable<T, Key, Hash>::set"
306 "(const Key& key, T newEntry, true) : "
307 "Cannot insert " << key << " already in hash table\n";
314 // found - overwrite existing entry
315 // this corresponds to the Perl convention
316 hashedEntry* ep = new hashedEntry(key, existing->next_, newEntry);
318 // replace existing element - within list or insert at the head
325 table_[hashIdx] = ep;
335 template<class T, class Key, class Hash>
336 bool Foam::HashTable<T, Key, Hash>::erase(const iterator& cit)
338 if (cit.elmtPtr_) // note: endIter_ also has 0 elmtPtr_
340 iterator& it = const_cast<iterator&>(cit);
342 // Search element before elmtPtr_
343 hashedEntry* prev = 0;
345 for (hashedEntry* ep = table_[it.hashIndex_]; ep; ep = ep->next_)
347 if (ep == it.elmtPtr_)
356 // Have element before elmtPtr
357 prev->next_ = it.elmtPtr_->next_;
363 // elmtPtr is first element on SLList
364 table_[it.hashIndex_] = it.elmtPtr_->next_;
367 // Search back for previous non-zero table entry
368 while (--it.hashIndex_ >= 0 && !table_[it.hashIndex_])
371 if (it.hashIndex_ >= 0)
373 // In table entry search for last element
374 it.elmtPtr_ = table_[it.hashIndex_];
376 while (it.elmtPtr_ && it.elmtPtr_->next_)
378 it.elmtPtr_ = it.elmtPtr_->next_;
383 // No previous found. Mark with special value which is
384 // - not end()/cend()
385 // - handled by operator++
386 it.elmtPtr_ = reinterpret_cast<hashedEntry*>(this);
396 Info<< "HashTable<T, Key, Hash>::erase(iterator&) : "
397 << "hashedEntry " << it.elmtPtr_->key_ << " removed.\n";
408 Info<< "HashTable<T, Key, Hash>::erase(iterator&) : "
409 << "cannot remove hashedEntry from hash table\n";
418 template<class T, class Key, class Hash>
419 bool Foam::HashTable<T, Key, Hash>::erase(const Key& key)
421 iterator fnd = find(key);
434 template<class T, class Key, class Hash>
435 Foam::label Foam::HashTable<T, Key, Hash>::erase(const UList<Key>& keys)
439 // Remove listed keys from this table
444 if (erase(keys[keyI]))
455 template<class T, class Key, class Hash>
456 template<class AnyType>
457 Foam::label Foam::HashTable<T, Key, Hash>::erase
459 const HashTable<AnyType, Key, Hash>& rhs
464 // Remove rhs elements from this table
467 // NOTE: could further optimize depending on which hash is smaller
468 for (iterator iter = begin(); iter != end(); ++iter)
470 if (rhs.found(iter.key()) && erase(iter))
481 template<class T, class Key, class Hash>
482 void Foam::HashTable<T, Key, Hash>::resize(const label sz)
484 label newSize = canonicalSize(sz);
486 if (newSize == tableSize_)
491 Info<< "HashTable<T, Key, Hash>::resize(const label) : "
492 << "new table size == old table size\n";
499 HashTable<T, Key, Hash>* newTable = new HashTable<T, Key, Hash>(newSize);
501 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
503 newTable->insert(iter.key(), *iter);
506 label oldTableSize = tableSize_;
507 tableSize_ = newTable->tableSize_;
508 newTable->tableSize_ = oldTableSize;
510 hashedEntry** oldTable = table_;
511 table_ = newTable->table_;
512 newTable->table_ = oldTable;
518 template<class T, class Key, class Hash>
519 void Foam::HashTable<T, Key, Hash>::clear()
523 for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++)
527 hashedEntry* ep = table_[hashIdx];
528 while (hashedEntry* next = ep->next_)
542 template<class T, class Key, class Hash>
543 void Foam::HashTable<T, Key, Hash>::clearStorage()
550 template<class T, class Key, class Hash>
551 void Foam::HashTable<T, Key, Hash>::transfer(HashTable<T, Key, Hash>& ht)
553 // as per the Destructor
560 tableSize_ = ht.tableSize_;
566 nElmts_ = ht.nElmts_;
571 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
573 template<class T, class Key, class Hash>
574 void Foam::HashTable<T, Key, Hash>::operator=
576 const HashTable<T, Key, Hash>& rhs
579 // Check for assignment to self
584 "HashTable<T, Key, Hash>::operator="
585 "(const HashTable<T, Key, Hash>&)"
586 ) << "attempted assignment to self"
587 << abort(FatalError);
590 // could be zero-sized from a previous transfer()
593 resize(rhs.tableSize_);
600 for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
602 insert(iter.key(), *iter);
607 template<class T, class Key, class Hash>
608 bool Foam::HashTable<T, Key, Hash>::operator==
610 const HashTable<T, Key, Hash>& rhs
613 // Are all my elements in rhs?
614 for (const_iterator iter = cbegin(); iter != cend(); ++iter)
616 const_iterator fnd = rhs.find(iter.key());
618 if (fnd == rhs.cend() || fnd() != iter())
624 // Are all rhs elements in me?
625 for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
627 const_iterator fnd = find(iter.key());
629 if (fnd == cend() || fnd() != iter())
638 template<class T, class Key, class Hash>
639 bool Foam::HashTable<T, Key, Hash>::operator!=
641 const HashTable<T, Key, Hash>& rhs
644 return !(operator==(rhs));
648 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
650 #include "HashTableIO.C"
652 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
656 // ************************************************************************* //