FreeFOAM The Cross-Platform CFD Toolkit
Hosted by SourceForge:
Get FreeFOAM at SourceForge.net.
            Fast, secure and Free Open Source software downloads

HashTable.C

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------------*\
00002   =========                 |
00003   \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
00004    \\    /   O peration     |
00005     \\  /    A nd           | Copyright (C) 1991-2010 OpenCFD Ltd.
00006      \\/     M anipulation  |
00007 -------------------------------------------------------------------------------
00008 License
00009     This file is part of OpenFOAM.
00010 
00011     OpenFOAM is free software: you can redistribute it and/or modify it
00012     under the terms of the GNU General Public License as published by
00013     the Free Software Foundation, either version 3 of the License, or
00014     (at your option) any later version.
00015 
00016     OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
00017     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00018     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
00019     for more details.
00020 
00021     You should have received a copy of the GNU General Public License
00022     along with OpenFOAM.  If not, see <http://www.gnu.org/licenses/>.
00023 
00024 \*---------------------------------------------------------------------------*/
00025 
00026 #ifndef HashTable_C
00027 #define HashTable_C
00028 
00029 #include "HashTable.H"
00030 #include <OpenFOAM/List.H>
00031 
00032 // * * * * * * * * * * * * Private Member Functions  * * * * * * * * * * * * //
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     // enforce power of two
00043     unsigned int goodSize = size;
00044 
00045     if (goodSize & (goodSize - 1))
00046     {
00047         // brute-force is fast enough
00048         goodSize = 1;
00049         while (goodSize < unsigned(size))
00050         {
00051             goodSize <<= 1;
00052         }
00053     }
00054 
00055     return goodSize;
00056 }
00057 
00058 
00059 // * * * * * * * * * * * * * * * * Constructors  * * * * * * * * * * * * * * //
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 // * * * * * * * * * * * * * * * * Destructor  * * * * * * * * * * * * * * * //
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 // * * * * * * * * * * * * * * * Member Functions  * * * * * * * * * * * * * //
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 // Return the table of contents
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     // not found, insert it at the head
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         // found - but protected from overwriting
00310         // this corresponds to the STL 'insert' convention
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         // found - overwrite existing entry
00324         // this corresponds to the Perl convention
00325         hashedEntry* ep = new hashedEntry(key, existing->next_, newEntry);
00326 
00327         // replace existing element - within list or insert at the head
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_)    // note: endIter_ also has 0 elmtPtr_
00348     {
00349         iterator& it = const_cast<iterator&>(cit);
00350 
00351         // Search element before elmtPtr_
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             // Have element before elmtPtr
00366             prev->next_ = it.elmtPtr_->next_;
00367             delete it.elmtPtr_;
00368             it.elmtPtr_ = prev;
00369         }
00370         else
00371         {
00372             // elmtPtr is first element on SLList
00373             table_[it.hashIndex_] = it.elmtPtr_->next_;
00374             delete it.elmtPtr_;
00375 
00376             // Search back for previous non-zero table entry
00377             while (--it.hashIndex_ >= 0 && !table_[it.hashIndex_])
00378             {}
00379 
00380             if (it.hashIndex_ >= 0)
00381             {
00382                 // In table entry search for last element
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                 // No previous found. Mark with special value which is
00393                 // - not end()/cend()
00394                 // - handled by operator++
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     // Remove listed keys from this table
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     // Remove rhs keys from this table - terminates early if possible
00474     // Could optimize depending on which hash is smaller ...
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     // as per the Destructor
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 // * * * * * * * * * * * * * * * Member Operators  * * * * * * * * * * * * * //
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     // Check for assignment to self
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     // could be zero-sized from a previous transfer()
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     // Are all my elements in rhs?
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     // Are all rhs elements in me?
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 // * * * * * * * * * * * * * * * Friend Operators  * * * * * * * * * * * * * //
00655 
00656 #include <OpenFOAM/HashTableIO.C>
00657 
00658 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
00659 
00660 #endif
00661 
00662 // ************************ vim: set sw=4 sts=4 et: ************************ //
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines