Simple Application Framework
1
|
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