Simple Application Framework  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Saf/Algo/Struct/HashTable.h
Go to the documentation of this file.
00001 /*
00002     This file is part of Simple Application Framework (Saf) library.
00003     Copyright (C) 2010 - 2012 Ondrej Danek <ondrej.danek@gmail.com>
00004 
00005     This library is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License as published 
00007     by the Free Software Foundation, either version 3 of the License, or
00008     (at your option) any later version.
00009 
00010     Saf is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU General Public License for more details.
00014 
00015     You should have received a copy of the GNU General Public License
00016     along with Simple Application Framework library. If not, 
00017     see <http://www.gnu.org/licenses/>.
00018 */
00019 
00028 #ifndef SAF_ALGO_STRUCT_HASHTABLE_H
00029 #define SAF_ALGO_STRUCT_HASHTABLE_H
00030 
00031 #include "../../Type.h"
00032 #include "../../Mem/Alloc.h"
00033 #include "../../Collection/Pair.h"
00034 #include "../../Collection/Array.h"
00035 #include "../../Collection/List.h"
00036 #include "../Swap.h"
00037 
00038 namespace Saf
00039 {
00040     namespace Algo
00041     {        
00042         namespace Struct
00043         {
00084             template <class KeyType, class RecType, class KeySelectorType, class HashFuncType, 
00085                 class HashPolicyType, class CompType>
00086             class HashTable
00087             {
00088             protected:
00089                 typedef HashTable<KeyType,RecType,KeySelectorType,HashFuncType,HashPolicyType,CompType> MyType;
00090 
00091             public:
00093                 typedef typename Collection::List<RecType>::Iterator Iterator;
00095                 typedef typename Collection::List<RecType>::ConstIterator ConstIterator;
00096 
00097             protected:
00099                 typedef typename Collection::Pair<Iterator,Iterator> BucketType;
00100 
00101             private:
00103                 Collection::List<RecType> m_list;
00105                 Size m_elems;
00107                 Collection::Array<1,BucketType> m_bucket;
00108 
00110                 KeySelectorType m_keyExtractFunc;
00112                 HashFuncType m_hashFunc;
00114                 HashPolicyType m_hashPolicy;
00116                 CompType m_compFunc;
00117 
00118             protected:
00124                 void SafeResizeBuckets(Size buckets)
00125                 {
00126                     if (buckets != Buckets())
00127                     {
00128                         Collection::Array<1,BucketType> newBuckets;
00129 
00130                         newBuckets.Resize(buckets, BucketType(End(), End()));
00131                         Algo::Swap(m_bucket, newBuckets);
00132                     }
00133                 }
00134 
00136                 Size ValBucketIndex(const RecType& val) const
00137                 {
00138                     return KeyBucketIndex(m_keyExtractFunc(val));
00139                 }
00140 
00145                 void BucketInsertUpdate(Iterator it, BucketType& bucket)
00146                 {
00147                     if (bucket.m_first == End())
00148                     {
00149                         bucket.m_first = it;
00150                         bucket.m_second = it;
00151                     }
00152                     else
00153                     {
00154                         bucket.m_first = it;
00155                     }
00156                 }
00157 
00159                 void BucketEraseUpdate(Iterator it, BucketType& bucket)
00160                 {
00161                     if (it == bucket.m_first)
00162                     {                        
00163                         if (it == bucket.m_second)
00164                         {                    
00165                             bucket.m_first = End();
00166                             bucket.m_second = End();
00167                         }
00168                         else
00169                         {
00170                             ++bucket.m_first;
00171                         }
00172                     }
00173                     else
00174                     {
00175                         if (it == bucket.m_second)
00176                         {
00177                             --bucket.m_second;
00178                         }
00179                     }
00180                 }
00181 
00183                 Iterator BucketFind(const KeyType& key, const BucketType& bucket)
00184                 {
00185                     Iterator ipos = bucket.m_first;
00186 
00187                     if (ipos != End())
00188                     {
00189                         Iterator ilast = bucket.m_second;
00190                         ++ilast;
00191 
00192                         while (ipos != ilast)
00193                         {                        
00194                             if (m_compFunc(m_keyExtractFunc(*ipos), key))
00195                             {
00196                                 return ipos;
00197                             }
00198 
00199                             ++ipos;
00200                         }
00201                     }
00202 
00203                     return End();
00204                 }
00205 
00207                 ConstIterator BucketFind(const KeyType& key, const BucketType& bucket) const
00208                 {
00209                     Iterator ipos = bucket.m_first;
00210 
00211                     if (ipos != End())
00212                     {
00213                         Iterator ilast = bucket.m_second;
00214                         ++ilast;
00215 
00216                         while (ipos != ilast)
00217                         {                        
00218                             if (m_compFunc(m_keyExtractFunc(*ipos), key))
00219                             {
00220                                 return ipos;
00221                             }
00222 
00223                             ++ipos;
00224                         }
00225                     }
00226 
00227                     return End();
00228                 }
00229 
00231                 void Reinsert(Iterator last)
00232                 {
00233                     if (last != Begin())
00234                     {
00235                         Iterator icur;
00236                         --last; // Sentinel
00237 
00238                         do
00239                         {
00240                             // Processed element
00241                             icur = Begin();
00242 
00243                             // Find bucket
00244                             BucketType &bucket = m_bucket[ValBucketIndex(*icur)];
00245 
00246                             // Reinsert
00247                             m_list.SpliceBefore(bucket.m_first, icur);
00248                             BucketInsertUpdate(icur, bucket);
00249                         } while (icur != last);
00250                     }
00251                 }
00252 
00254                 void ResizeTable(Size buckets)
00255                 {
00256                     SafeResizeBuckets(buckets);
00257                     Reinsert(End());
00258                 }
00259 
00260             public:
00266                 explicit HashTable(Size bucketHint)
00267                     : m_elems(0)
00268                 {
00269                     // Allocate the optimum number of buckets
00270                     SafeResizeBuckets(m_hashPolicy.NextBucketCount(bucketHint));
00271                 }
00272 
00274                 HashTable(const MyType& ht) 
00275                     : m_elems(0)
00276                 {
00277                     *this = ht; 
00278                 }
00279 
00281                 ~HashTable() 
00282                 {}
00283 
00292                 MyType& Free() 
00293                 {
00294                     // Try to reset the bucket count
00295                     SafeResizeBuckets(m_hashPolicy.NextBucketCount(0));
00296 
00297                     // Free all values
00298                     m_list.Free();
00299                     m_elems = 0;
00300 
00301                     return *this;
00302                 }
00303 
00308                 MyType& operator=(const MyType& ht)
00309                 {
00310                     if (&ht != this)
00311                     {
00312                         // Reset the table
00313                         Free();
00314 
00315                         // Try to allocate new bucket array and copy the elements
00316                         Collection::Array<1,BucketType> newBuckets;
00317                         Collection::List<RecType> newList;
00318 
00319                         newList = ht.m_list;
00320                         newBuckets.Resize(ht.Buckets(), BucketType(newList.End(), newList.End()));
00321 
00322                         // Hopefully, these do not throw
00323                         m_keyExtractFunc = ht.m_keyExtractFunc;
00324                         m_hashFunc = ht.m_hashFunc;
00325                         m_hashPolicy = ht.m_hashPolicy;
00326                         m_compFunc = ht.m_compFunc;
00327                         
00328                         // Everything went ok, swap the pointers and restore the table
00329                         Algo::Swap(m_bucket, newBuckets);
00330                         Algo::Swap(m_list, newList);
00331 
00332                         m_elems = ht.m_elems;
00333                         Reinsert(End());
00334                     }
00335 
00336                     return *this;
00337                 }
00338 
00344                 MyType& Swap(MyType& ht)
00345                 {
00346                     if (&ht != this)
00347                     {
00348                         Algo::Swap(m_list, ht.m_list);
00349                         Algo::Swap(m_elems, ht.m_elems);
00350                         Algo::Swap(m_bucket, ht.m_bucket);
00351                         
00352                         Algo::Swap(m_keyExtractFunc, ht.m_keyExtractFunc);
00353                         Algo::Swap(m_hashFunc, ht.m_hashFunc);
00354                         Algo::Swap(m_hashPolicy, ht.m_hashPolicy);
00355                         Algo::Swap(m_compFunc, ht.m_compFunc);
00356                     }
00357 
00358                     return *this;
00359                 }
00360 
00366                 bool IsEmpty() const 
00367                 { 
00368                     return (m_elems == 0);
00369                 }
00370 
00376                 Size Elements() const
00377                 {
00378                     return m_elems;
00379                 }
00380 
00386                 Size Buckets() const
00387                 {
00388                     return m_bucket.Elements();
00389                 }
00390 
00392                 Size KeyBucketIndex(const KeyType& key) const
00393                 {
00394                     Size hash = m_hashFunc(key);
00395                     return m_hashPolicy.BucketIndex(hash, Buckets());
00396                 }
00397 
00408                 Iterator BucketBegin(Size bucket)
00409                 {
00410                     return Iterator(m_bucket[bucket].m_first);
00411                 }
00412 
00423                 ConstIterator BucketBegin(Size bucket) const
00424                 {
00425                     return ConstIterator(m_bucket[bucket].m_first);
00426                 }
00427 
00438                 Iterator BucketEnd(Size bucket)
00439                 {
00440                     Iterator end = m_bucket[bucket].m_second;
00441                     return end == End() ? end : ++end;
00442                 }
00443 
00454                 ConstIterator BucketEnd(Size bucket) const
00455                 {
00456                     ConstIterator end = m_bucket[bucket].m_second;
00457                     return end == End() ? end : ++end;
00458                 }
00459 
00469                 MyType& Rehash(Size bucketHint)
00470                 {
00471                     ResizeTable(m_hashPolicy.OptimalBucketCount(bucketHint, m_elems));
00472                     return *this;
00473                 }
00474 
00491                 Collection::Pair<Iterator,bool> Insert(const RecType& val)
00492                 {
00493                     // Bucket for the new element
00494                     BucketType &bucket = m_bucket[ValBucketIndex(val)];
00495 
00496                     // Check if already exists
00497                     Iterator ipos = BucketFind(m_keyExtractFunc(val), bucket);
00498                     if (ipos != End())
00499                     {
00500                         return Collection::Pair<Iterator,bool>(ipos, false);
00501                     }
00502 
00503                     // Insert new element                    
00504                     ipos = m_list.InsertBefore(bucket.m_first, val);
00505                     m_elems++;
00506 
00507                     // Update bucket info
00508                     BucketInsertUpdate(ipos, bucket);
00509 
00510                     // Check if table resizing is required
00511                     Collection::Pair<bool,Size> cg = m_hashPolicy.ShouldResize(Elements() + 1, Buckets());
00512                     if (cg.m_first)
00513                     {
00514                         ResizeTable(cg.m_second);
00515                     }
00516 
00517                     return Collection::Pair<Iterator,bool>(ipos, true);
00518                 }
00519 
00531                 Iterator Erase(Iterator it)
00532                 {
00533                     // Update iterators
00534                     BucketType& bucket = m_bucket[ValBucketIndex(*it)];
00535                     BucketEraseUpdate(it, bucket);
00536                     
00537                     // Update element counter
00538                     m_elems--;
00539 
00540                     // Erase element
00541                     return m_list.Erase(it);
00542                 }
00543 
00552                 Iterator Find(const KeyType& key)
00553                 {
00554                     return BucketFind(key, m_bucket[KeyBucketIndex(key)]);
00555                 }
00556 
00565                 ConstIterator Find(const KeyType& key) const
00566                 {
00567                     return BucketFind(key, m_bucket[KeyBucketIndex(key)]);
00568                 }
00569 
00576                 bool Contains(const KeyType& key) const
00577                 {
00578                     return (Find(key) != End());
00579                 }
00580 
00582                 Iterator Begin()
00583                 {
00584                     return m_list.Begin();
00585                 }
00586 
00588                 ConstIterator Begin() const
00589                 {
00590                     return m_list.Begin();
00591                 }
00592 
00594                 Iterator End()
00595                 {
00596                     return m_list.End();
00597                 }
00598 
00600                 ConstIterator End() const
00601                 {
00602                     return m_list.End();
00603                 }
00604 
00606                 Iterator Front()
00607                 {
00608                     return Begin();
00609                 }
00610 
00612                 ConstIterator Front() const
00613                 {
00614                     return Begin();
00615                 }
00616 
00618                 Iterator Back()
00619                 {
00620                     return m_list.Back();
00621                 }
00622 
00624                 ConstIterator Back() const
00625                 {
00626                     return m_list.Back();
00627                 }
00628             };
00629         }
00630 
00632         // Swap specialization for hash tables.
00633         template <class KeyType, class RecType, class KeySelectorType, class HashFuncType, 
00634                 class HashPolicyType, class CompType>
00635         struct SwapFunc< Struct::HashTable<KeyType,RecType,KeySelectorType,HashFuncType,HashPolicyType,CompType> >
00636         {
00637             void operator()(Struct::HashTable<KeyType,RecType,KeySelectorType,HashFuncType,HashPolicyType,CompType>& x, 
00638                 Struct::HashTable<KeyType,RecType,KeySelectorType,HashFuncType,HashPolicyType,CompType>& y)
00639             {
00640                 x.Swap(y);
00641             }
00642         };
00644     }
00645 }
00646 
00647 #endif