csutil/weakkeyedhash.h
00001 /* 00002 Copyright (C) 2011 by Frank Richter 00003 00004 This library is free software; you can redistribute it and/or 00005 modify it under the terms of the GNU Lesser General Public 00006 License as published by the Free Software Foundation; either 00007 version 2 of the License, or (at your option) any later version. 00008 00009 This library is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00012 Library General Public License for more details. 00013 00014 You should have received a copy of the GNU Library General Public 00015 License along with this library; if not, write to the Free 00016 Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00017 */ 00018 00019 #ifndef __CSUTIL_WEAKKEYEDHASH_H__ 00020 #define __CSUTIL_WEAKKEYEDHASH_H__ 00021 00022 #include "hash.h" 00023 00024 namespace CS 00025 { 00026 namespace Container 00027 { 00047 template <class T, class K, 00048 class ArrayMemoryAlloc = CS::Container::ArrayAllocDefault, 00049 class ArrayElementHandler = csArraySafeCopyElementHandler< 00050 CS::Container::HashElement<T, K> > > 00051 class WeakKeyedHash : 00052 protected csHash<T, K, ArrayMemoryAlloc, ArrayElementHandler> 00053 { 00054 typedef csHash<T, K, ArrayMemoryAlloc, ArrayElementHandler> Superclass; 00055 public: 00057 void Purge () 00058 { 00059 for (size_t e = 0; e < this->Elements.GetSize(); e++) 00060 { 00061 typename Superclass::ElementArray& values = this->Elements[e]; 00062 for (size_t i = 0; i < values.GetSize (); ++i) 00063 { 00064 const typename Superclass::Element& v = values[i]; 00065 // Delete any elements with 'invalid' keys while searching 00066 if (!v.GetKey()) 00067 { 00068 values.DeleteIndexFast (i); 00069 this->Size--; 00070 i--; 00071 } 00072 } 00073 } 00074 } 00075 00080 const T& Get (const K& key, const T& fallback) 00081 { 00082 if (this->Elements.GetSize() == 0) return fallback; 00083 typename Superclass::ElementArray& values = 00084 this->Elements[csHashComputer<K>::ComputeHash (key) % this->Modulo]; 00085 for (size_t i = 0; i < values.GetSize (); ++i) 00086 { 00087 const typename Superclass::Element& v = values[i]; 00088 // Delete any elements with 'invalid' keys while searching 00089 if (!v.GetKey()) 00090 { 00091 values.DeleteIndexFast (i); 00092 this->Size--; 00093 i--; 00094 continue; 00095 } 00096 if (csComparator<K, K>::Compare (v.GetKey(), key) == 0) 00097 return v.GetValue(); 00098 } 00099 00100 return fallback; 00101 } 00102 using Superclass::Get; 00103 using Superclass::GetOrCreate; 00104 00109 T* GetElementPointer (const K& key) 00110 { 00111 if (this->Elements.GetSize() == 0) return 0; 00112 typename Superclass::ElementArray& values = 00113 this->Elements[csHashComputer<K>::ComputeHash (key) % this->Modulo]; 00114 for (size_t i = 0; i < values.GetSize (); ++i) 00115 { 00116 typename Superclass::Element& v = values[i]; 00117 // Delete any elements with 'invalid' keys while searching 00118 if (!v.GetKey()) 00119 { 00120 values.DeleteIndexFast (i); 00121 this->Size--; 00122 i--; 00123 continue; 00124 } 00125 if (csComparator<K, K>::Compare (v.GetKey(), key) == 0) 00126 return &v.GetValue(); 00127 } 00128 00129 return 0; 00130 } 00131 using Superclass::GetElementPointer; 00132 00140 T& Put (const K& key, const T &value) 00141 { 00142 if (this->Elements.GetSize() == 0) this->Elements.SetSize (this->Modulo); 00143 typename Superclass::ElementArray& values = 00144 this->Elements[csHashComputer<K>::ComputeHash (key) % this->Modulo]; 00145 // Delete any elements 'invalid' with keys while looking for a slot 00146 size_t idx = 0; 00147 while (idx < values.GetSize()) 00148 { 00149 if (!values[idx].GetKey()) 00150 { 00151 break; 00152 } 00153 idx++; 00154 } 00155 if (idx >= values.GetSize()) 00156 { 00157 values.Push (typename Superclass::Element (key, value)); 00158 this->Size++; 00159 } 00160 if (values.GetSize () > this->Elements.GetSize () / this->GrowRate 00161 && this->Elements.GetSize () < this->MaxSize) 00162 { 00163 this->Grow (); 00164 /* can't use 'values[idx]' since that is no longer the place where 00165 the item is stored. */ 00166 return *(this->GetElementPointer (key)); 00167 } 00168 return values[idx].GetValue(); 00169 } 00171 T& PutUnique (const K& key, const T &value) 00172 { 00173 if (this->Elements.GetSize() == 0) this->Elements.SetSize (this->Modulo); 00174 typename Superclass::ElementArray& values = 00175 this->Elements[csHashComputer<K>::ComputeHash (key) % this->Modulo]; 00176 const size_t len = values.GetSize (); 00177 for (size_t i = 0; i < len; ) 00178 { 00179 typename Superclass::Element& v = values[i]; 00180 // Delete any elements 'invalid' with keys while looking for the slot 00181 if (!v.GetKey()) 00182 { 00183 values.DeleteIndexFast (i); 00184 continue; 00185 } 00186 if (csComparator<K, K>::Compare (v.GetKey(), key) == 0) 00187 { 00188 v.GetValue() = value; 00189 return v.GetValue(); 00190 } 00191 ++i; 00192 } 00193 00194 size_t idx = values.Push (typename Superclass::Element (key, value)); 00195 this->Size++; 00196 if (values.GetSize () > this->Elements.GetSize () / this->GrowRate 00197 && this->Elements.GetSize () < this->MaxSize) 00198 { 00199 this->Grow (); 00200 /* can't use 'values[idx]' since that is no longer the place where 00201 the item is stored. */ 00202 return *(GetElementPointer (key)); 00203 } 00204 return values[idx].GetValue(); 00205 } 00206 00207 using Superclass::DeleteAll; 00208 00210 class GlobalIterator 00211 { 00212 private: 00213 typedef typename Superclass::GlobalIterator WrappedIterator; 00214 WrappedIterator iter; 00215 00216 bool haveNext; 00217 K key; 00218 T* value; 00219 protected: 00220 void NextElement () 00221 { 00222 while (iter.HasNext ()) 00223 { 00224 K key; 00225 value = &(iter.NextNoAdvance (key)); 00226 if (key) 00227 { 00228 this->key = key; 00229 this->value = value; 00230 haveNext = true; 00231 return; 00232 } 00233 iter.Advance (); 00234 // @@@ Would be nice to clear out invalid keys as well here 00235 // like: ...->DeleteElement (*this); 00236 } 00237 haveNext = false; 00238 key = K (); 00239 } 00240 00241 GlobalIterator (const WrappedIterator& iter) 00242 : iter (iter) 00243 { 00244 NextElement (); 00245 } 00246 00247 friend class WeakKeyedHash<T, K, ArrayMemoryAlloc, ArrayElementHandler>; 00248 public: 00250 GlobalIterator (const GlobalIterator& o) 00251 : iter (o.iter), haveNext (o.haveNext), key (o.key), value (o.value) {} 00252 00254 GlobalIterator& operator=(const GlobalIterator& o) 00255 { 00256 iter = o.iter; 00257 haveNext = o.haveNext; 00258 key = o.key; 00259 value = o.value; 00260 return *this; 00261 } 00262 00264 bool HasNext () const 00265 { 00266 return haveNext; 00267 } 00268 00270 void Advance () 00271 { 00272 iter.Advance (); 00273 NextElement (); 00274 } 00275 00277 T& NextNoAdvance () 00278 { 00279 return *value; 00280 } 00281 00283 T& Next () 00284 { 00285 T &ret = NextNoAdvance (); 00286 Advance (); 00287 return ret; 00288 } 00289 00291 T& NextNoAdvance (K &key) 00292 { 00293 key = this->key; 00294 return NextNoAdvance (); 00295 } 00296 00298 T& Next (K &key) 00299 { 00300 key = this->key; 00301 return Next (); 00302 } 00303 00305 const csTuple2<T, K> NextTuple () 00306 { 00307 csTuple2<T, K> t (NextNoAdvance (), 00308 this->key); 00309 Advance (); 00310 return t; 00311 } 00312 00314 void Reset () 00315 { 00316 iter->Reset (); 00317 NextElement (); 00318 } 00319 }; 00320 friend class GlobalIterator; 00321 00327 GlobalIterator GetIterator () 00328 { 00329 return GlobalIterator (Superclass::GetIterator ()); 00330 } 00331 00336 void DeleteElement (GlobalIterator& iterator) 00337 { 00338 Superclass::DeleteElement (iterator.iter); 00339 } 00340 00342 class ConstGlobalIterator 00343 { 00344 private: 00345 typedef typename Superclass::ConstGlobalIterator WrappedIterator; 00346 WrappedIterator iter; 00347 00348 bool haveNext; 00349 K key; 00350 const T* value; 00351 protected: 00352 void NextElement () 00353 { 00354 while (iter.HasNext ()) 00355 { 00356 K key; 00357 value = &(iter.NextNoAdvance (key)); 00358 if (key) 00359 { 00360 this->key = key; 00361 this->value = value; 00362 haveNext = true; 00363 return; 00364 } 00365 iter.Advance (); 00366 // @@@ Would be nice to clear out invalid keys as well here 00367 // like: ...->DeleteElement (*this); 00368 } 00369 haveNext = false; 00370 key = K (); 00371 } 00372 00373 ConstGlobalIterator (const WrappedIterator& iter) 00374 : iter (iter) 00375 { 00376 NextElement (); 00377 } 00378 00379 friend class WeakKeyedHash<T, K, ArrayMemoryAlloc, ArrayElementHandler>; 00380 public: 00382 ConstGlobalIterator (const ConstGlobalIterator& o) 00383 : iter (o.iter), haveNext (o.haveNext), key (o.key), value (o.value) {} 00384 00386 ConstGlobalIterator& operator=(const ConstGlobalIterator& o) 00387 { 00388 iter = o.iter; 00389 haveNext = o.haveNext; 00390 key = o.key; 00391 value = o.value; 00392 return *this; 00393 } 00394 00396 bool HasNext () const 00397 { 00398 return haveNext; 00399 } 00400 00402 void Advance () 00403 { 00404 iter.Advance(); 00405 NextElement (); 00406 } 00407 00409 const T& NextNoAdvance () 00410 { 00411 return *value; 00412 } 00413 00415 const T& Next () 00416 { 00417 const T &ret = NextNoAdvance (); 00418 Advance (); 00419 return ret; 00420 } 00421 00423 const T& NextNoAdvance (K &key) 00424 { 00425 key = this->key; 00426 return NextNoAdvance (); 00427 } 00428 00430 const T& Next (K &key) 00431 { 00432 key = this->key; 00433 return Next (); 00434 } 00435 00437 const csTuple2<T, K> NextTuple () 00438 { 00439 csTuple2<T, K> t (NextNoAdvance (), 00440 this->key); 00441 Advance (); 00442 return t; 00443 } 00444 00446 void Reset () 00447 { 00448 iter->Reset (); 00449 NextElement (); 00450 } 00451 }; 00452 friend class ConstGlobalIterator; 00453 00459 ConstGlobalIterator GetIterator () const 00460 { 00461 return ConstGlobalIterator (Superclass::GetIterator ()); 00462 } 00463 00464 // @@@ FIXME: More csHash<> methods (and iterators) need to be 'ported' 00465 }; 00466 } // namespace Container 00467 } // namespace CS 00468 00469 #endif // __CSUTIL_WEAKKEYEDHASH_H__
Generated for Crystal Space 2.1 by doxygen 1.6.1
