/*---------------------------------------------------------------------------*\ ========= | \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 1991-2009 OpenCFD Ltd. \\/ M anipulation | ------------------------------------------------------------------------------- License This file is part of OpenFOAM. OpenFOAM is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. OpenFOAM is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenFOAM; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA \*---------------------------------------------------------------------------*/ #ifndef StaticHashTable_C #define StaticHashTable_C #include "StaticHashTable.H" #include "List.H" #include "IOstreams.H" // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * // Foam::label Foam::StaticHashTableCore::canonicalSize(const label size) { if (size < 1) { return 0; } // enforce power of two unsigned int goodSize = size; if (goodSize & (goodSize - 1)) { // brute-force is fast enough goodSize = 1; while (goodSize < unsigned(size)) { goodSize <<= 1; } } return goodSize; } // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // Construct given initial table size template Foam::StaticHashTable::StaticHashTable(const label size) : StaticHashTableCore(), keys_(StaticHashTableCore::canonicalSize(size)), objects_(keys_.size()), nElmts_(0), endIter_(*this, keys_.size(), 0), endConstIter_(*this, keys_.size(), 0) { if (size < 1) { FatalErrorIn ( "StaticHashTable::StaticHashTable(const label size)" ) << "Illegal size " << size << " for StaticHashTable." << " Minimum size is 1" << abort(FatalError); } } // Construct as copy template Foam::StaticHashTable::StaticHashTable ( const StaticHashTable& ht ) : StaticHashTableCore(), keys_(ht.keys_), objects_(ht.objects_), nElmts_(ht.nElmts_), endIter_(*this, keys_.size(), 0), endConstIter_(*this, keys_.size(), 0) {} template Foam::StaticHashTable::StaticHashTable ( const Xfer >& ht ) : StaticHashTableCore(), keys_(0), objects_(0), nElmts_(0), endIter_(*this, 0, 0), endConstIter_(*this, 0, 0) { transfer(ht()); } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // template Foam::StaticHashTable::~StaticHashTable() {} // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template bool Foam::StaticHashTable::found(const Key& key) const { if (nElmts_) { const label hashIdx = hashKeyIndex(key); const List& localKeys = keys_[hashIdx]; forAll(localKeys, elemIdx) { if (key == localKeys[elemIdx]) { return true; } } } # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::found(const Key&) : " << "Entry " << key << " not found in hash table\n"; } # endif return false; } template typename Foam::StaticHashTable::iterator Foam::StaticHashTable::find ( const Key& key ) { if (nElmts_) { const label hashIdx = hashKeyIndex(key); const List& localKeys = keys_[hashIdx]; forAll(localKeys, elemIdx) { if (key == localKeys[elemIdx]) { return iterator(*this, hashIdx, elemIdx); } } } # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::find(const Key&) : " << "Entry " << key << " not found in hash table\n"; } # endif return end(); } template typename Foam::StaticHashTable::const_iterator Foam::StaticHashTable::find ( const Key& key ) const { if (nElmts_) { const label hashIdx = hashKeyIndex(key); const List& localKeys = keys_[hashIdx]; forAll(localKeys, elemIdx) { if (key == localKeys[elemIdx]) { return const_iterator(*this, hashIdx, elemIdx); } } } # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::find(const Key&) const : " << "Entry " << key << " not found in hash table\n"; } # endif return cend(); } // Return the table of contents template Foam::List Foam::StaticHashTable::toc() const { List keys(nElmts_); label keyI = 0; for (const_iterator iter = cbegin(); iter != cend(); ++iter) { keys[keyI++] = iter.key(); } return keys; } template bool Foam::StaticHashTable::set ( const Key& key, const T& newEntry, const bool protect ) { const label hashIdx = hashKeyIndex(key); List& localKeys = keys_[hashIdx]; label existing = localKeys.size(); forAll(localKeys, elemIdx) { if (key == localKeys[elemIdx]) { existing = elemIdx; break; } } if (existing == localKeys.size()) { // not found, append List& localObjects = objects_[hashIdx]; localKeys.setSize(existing+1); localObjects.setSize(existing+1); localKeys[existing] = key; localObjects[existing] = newEntry; nElmts_++; } else if (protect) { // found - but protected from overwriting // this corresponds to the STL 'insert' convention # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::set" "(const Key& key, T newEntry, true) : " "Cannot insert " << key << " already in hash table\n"; } # endif return false; } else { // found - overwrite existing entry // this corresponds to the Perl convention objects_[hashIdx][existing] = newEntry; } return true; } template bool Foam::StaticHashTable::erase(const iterator& cit) { if (cit != end()) { List& localKeys = keys_[cit.hashIndex_]; List& localObjects = objects_[cit.hashIndex_]; // Copy down for (label i = cit.elemIndex_+1; i < localKeys.size(); i++) { localKeys[i-1] = localKeys[i]; localObjects[i-1] = localObjects[i]; } localKeys.setSize(localKeys.size()-1); localObjects.setSize(localObjects.size()-1); // adjust iterator after erase iterator& it = const_cast(cit); it.elemIndex_--; if (it.elemIndex_ < 0) { // No previous element in the local list // Mark with as special value (see notes in HashTable) it.hashIndex_ = -it.hashIndex_ - 1; it.elemIndex_ = 0; } nElmts_--; # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::erase(iterator&) : " << "hashedEntry removed.\n"; } # endif return true; } else { # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::erase(iterator&) : " << "cannot remove hashedEntry from hash table\n"; } # endif return false; } } template bool Foam::StaticHashTable::erase(const Key& key) { iterator it = find(key); if (it != end()) { return erase(it); } else { return false; } } template Foam::label Foam::StaticHashTable::erase ( const StaticHashTable& rhs ) { label count = 0; // Remove rhs elements from this table // NOTE: could optimize depending on which hash is smaller for (iterator iter = this->begin(); iter != this->end(); ++iter) { if (rhs.found(iter.key()) && erase(iter)) { count++; } } return count; } template void Foam::StaticHashTable::resize(const label sz) { label newSize = StaticHashTableCore::canonicalSize(sz); if (newSize == keys_.size()) { # ifdef FULLDEBUG if (debug) { Info<< "StaticHashTable::resize(const label) : " << "new table size == old table size\n"; } # endif return; } if (newSize < 1) { FatalErrorIn ( "StaticHashTable::resize(const label)" ) << "Illegal size " << newSize << " for StaticHashTable." << " Minimum size is 1" << abort(FatalError); } StaticHashTable newTable(newSize); for (const_iterator iter = cbegin(); iter != cend(); ++iter) { newTable.insert(iter.key(), *iter); } transfer(newTable); // Adapt end() iterators endIter_.hashIndex_ = keys_.size(); endConstIter_.hashIndex_ = keys_.size(); } template void Foam::StaticHashTable::clear() { forAll(keys_, hashIdx) { keys_[hashIdx].clear(); objects_[hashIdx].clear(); } nElmts_ = 0; } template void Foam::StaticHashTable::clearStorage() { clear(); resize(1); } template void Foam::StaticHashTable::transfer ( StaticHashTable& ht ) { // Remove existing elements clear(); // Copy data from ht keys_.transfer(ht.keys_); objects_.transfer(ht.objects_); nElmts_ = ht.nElmts_; ht.nElmts_ = 0; // Adapt end() iterators endIter_.hashIndex_ = keys_.size(); endConstIter_.hashIndex_ = keys_.size(); ht.endIter_.hashIndex_ = 0; ht.endConstIter_.hashIndex_ = 0; } // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template void Foam::StaticHashTable::operator= ( const StaticHashTable& rhs ) { // Check for assignment to self if (this == &rhs) { FatalErrorIn ( "StaticHashTable::operator=" "(const StaticHashTable&)" ) << "attempted assignment to self" << abort(FatalError); } // keys could be empty from a previous transfer() if (keys_.empty()) { keys_.setSize(rhs.keys_.size()); objects_.setSize(keys_.size()); // Adapt end() iterators endIter_.hashIndex_ = keys_.size(); endConstIter_.hashIndex_ = keys_.size(); } else { clear(); // keys_.size() does not change so neither does end() iterator. } for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter) { insert(iter.key(), *iter); } } template bool Foam::StaticHashTable::operator== ( const StaticHashTable& rhs ) const { // sizes (number of keys) must match for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter) { const_iterator fnd = find(iter.key()); if (fnd == cend() || fnd() != iter()) { return false; } } return true; } template bool Foam::StaticHashTable::operator!= ( const StaticHashTable& rhs ) const { return !(operator==(rhs)); } // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // #include "StaticHashTableIO.C" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #endif // ************************************************************************* //