/*---------------------------------------------------------------------------*\ ========= | \\ / 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 HashTable_C #define HashTable_C #include "HashTable.H" #include "List.H" // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // template Foam::HashTable::HashTable(const label size) : tableSize_(size), table_(NULL), nElmts_(0), endIter_(*this, NULL, 0), endConstIter_(*this, NULL, 0) { if (tableSize_) { table_ = new hashedEntry*[tableSize_]; for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++) { table_[hashIdx] = 0; } } } template Foam::HashTable::HashTable(const HashTable& ht) : HashTableName(), tableSize_(ht.tableSize_), table_(NULL), nElmts_(0), endIter_(*this, NULL, 0), endConstIter_(*this, NULL, 0) { if (tableSize_) { table_ = new hashedEntry*[tableSize_]; for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++) { table_[hashIdx] = 0; } for (const_iterator iter = ht.begin(); iter != ht.end(); ++iter) { insert(iter.key(), *iter); } } } template Foam::HashTable::HashTable ( const xfer >& ht ) : HashTableName(), tableSize_(0), table_(NULL), nElmts_(0), endIter_(*this, NULL, 0), endConstIter_(*this, NULL, 0) { transfer(ht()); } // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * // template Foam::HashTable::~HashTable() { if (table_) { clear(); delete[] table_; } } // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // template bool Foam::HashTable::found(const Key& key) const { if (tableSize_) { label hashIdx = Hash()(key, tableSize_); for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) { if (key == ep->key_) { return true; } } } # ifdef FULLDEBUG if (debug) { Info<< "HashTable::found(const Key& key) : " << "Entry " << key << " not found in hash table\n"; } # endif return false; } template typename Foam::HashTable::iterator Foam::HashTable::find ( const Key& key ) { if (tableSize_) { label hashIdx = Hash()(key, tableSize_); for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) { if (key == ep->key_) { return iterator(*this, ep, hashIdx); } } } # ifdef FULLDEBUG if (debug) { Info<< "HashTable::find(const Key& key) : " << "Entry " << key << " not found in hash table\n"; } # endif return end(); } template typename Foam::HashTable::const_iterator Foam::HashTable::find ( const Key& key ) const { if (tableSize_) { label hashIdx = Hash()(key, tableSize_); for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) { if (key == ep->key_) { return const_iterator(*this, ep, hashIdx); } } } # ifdef FULLDEBUG if (debug) { Info<< "HashTable::find(const Key& key) const : " << "Entry " << key << " not found in hash table\n"; } # endif return end(); } // Return the table of contents template Foam::List Foam::HashTable::toc() const { List tofc(nElmts_); label i = 0; for (const_iterator iter = begin(); iter != end(); ++iter) { tofc[i++] = iter.key(); } return tofc; } template bool Foam::HashTable::set ( const Key& key, const T& newEntry, const bool protect ) { if (tableSize_ == 0) { resize(2); } label hashIdx = Hash()(key, tableSize_); hashedEntry* existing = 0; hashedEntry* prev = 0; for (hashedEntry* ep = table_[hashIdx]; ep; ep = ep->next_) { if (key == ep->key_) { existing = ep; break; } prev = ep; } // not found, insert it at the head if (!existing) { table_[hashIdx] = new hashedEntry(key, table_[hashIdx], newEntry); nElmts_++; if (double(nElmts_)/tableSize_ > 0.8) { # ifdef FULLDEBUG if (debug) { Info<< "HashTable::set" "(const Key& key, T newEntry) : " "Doubling table size\n"; } # endif resize(2*tableSize_); } } else if (protect) { // found - but protected from overwriting // this corresponds to the STL 'insert' convention # ifdef FULLDEBUG if (debug) { Info<< "HashTable::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 hashedEntry* ep = new hashedEntry(key, existing->next_, newEntry); // replace existing element - within list or insert at the head if (prev) { prev->next_ = ep; } else { table_[hashIdx] = ep; } delete existing; } return true; } template bool Foam::HashTable::erase(const iterator& cit) { if (cit.elmtPtr_) // note: endIter_ also has 0 elmtPtr_ { iterator& it = const_cast(cit); // Search element before elmtPtr_ hashedEntry* prev = 0; for (hashedEntry* ep = table_[it.hashIndex_]; ep; ep = ep->next_) { if (ep == it.elmtPtr_) { break; } prev = ep; } if (prev) { // Have element before elmtPtr prev->next_ = it.elmtPtr_->next_; delete it.elmtPtr_; it.elmtPtr_ = prev; } else { // elmtPtr is first element on SLList table_[it.hashIndex_] = it.elmtPtr_->next_; delete it.elmtPtr_; // Search back for previous non-zero table entry while (--it.hashIndex_ >= 0 && !table_[it.hashIndex_]) {} if (it.hashIndex_ >= 0) { // In table entry search for last element it.elmtPtr_ = table_[it.hashIndex_]; while (it.elmtPtr_ && it.elmtPtr_->next_) { it.elmtPtr_ = it.elmtPtr_->next_; } } else { // No previous found. Mark with special value which is // - not end() // - handled by operator++ it.elmtPtr_ = reinterpret_cast(this); it.hashIndex_ = -1; } } nElmts_--; # ifdef FULLDEBUG if (debug) { Info<< "HashTable::erase(iterator&) : " << "hashedEntry " << it.elmtPtr_->key_ << " removed.\n"; } # endif return true; } else { # ifdef FULLDEBUG if (debug) { Info<< "HashTable::erase(iterator&) : " << "cannot remove hashedEntry from hash table\n"; } # endif return false; } } template bool Foam::HashTable::erase(const Key& key) { iterator it = find(key); if (it != end()) { return erase(it); } else { return false; } } template void Foam::HashTable::resize(const label newSize) { if (newSize == tableSize_) { # ifdef FULLDEBUG if (debug) { Info<< "HashTable::resize(const label newSize) : " << "new table size == old table size\n"; } # endif return; } HashTable* newTable = new HashTable(newSize); for (const_iterator iter = begin(); iter != end(); ++iter) { newTable->insert(iter.key(), *iter); } label oldTableSize = tableSize_; tableSize_ = newTable->tableSize_; newTable->tableSize_ = oldTableSize; hashedEntry** oldTable = table_; table_ = newTable->table_; newTable->table_ = oldTable; delete newTable; } template void Foam::HashTable::clear() { if (nElmts_) { for (label hashIdx = 0; hashIdx < tableSize_; hashIdx++) { if (table_[hashIdx]) { hashedEntry* ep = table_[hashIdx]; while (hashedEntry* next = ep->next_) { delete ep; ep = next; } delete ep; table_[hashIdx] = 0; } } nElmts_ = 0; } } template void Foam::HashTable::clearStorage() { clear(); resize(0); } template void Foam::HashTable::transfer(HashTable& ht) { // as per the Destructor if (table_) { clear(); delete[] table_; } tableSize_ = ht.tableSize_; ht.tableSize_ = 0; table_ = ht.table_; ht.table_ = NULL; nElmts_ = ht.nElmts_; ht.nElmts_ = 0; } // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template void Foam::HashTable::operator= ( const HashTable& rhs ) { // Check for assignment to self if (this == &rhs) { FatalErrorIn ( "HashTable::operator=" "(const HashTable&)" ) << "attempted assignment to self" << abort(FatalError); } // could be zero-sized from a previous transfer() if (tableSize_ == 0) { resize(rhs.tableSize_); } else { clear(); } for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) { insert(iter.key(), *iter); } } template bool Foam::HashTable::operator== ( const HashTable& rhs ) const { // Are all my elements in rhs? for (const_iterator iter = begin(); iter != end(); ++iter) { const_iterator fnd = rhs.find(iter.key()); if (fnd == rhs.end() || fnd() != iter()) { return false; } } // Are all rhs elements in me? for (const_iterator iter = rhs.begin(); iter != rhs.end(); ++iter) { const_iterator fnd = find(iter.key()); if (fnd == end() || fnd() != iter()) { return false; } } return true; } template bool Foam::HashTable::operator!= ( const HashTable& rhs ) const { return !(operator==(rhs)); } // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * // #include "HashTableIO.C" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // #endif // ************************************************************************* //