ovr_sdk

annotate LibOVR/Src/Kernel/OVR_Hash.h @ 0:1b39a1b46319

initial 0.4.4
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 14 Jan 2015 06:51:16 +0200
parents
children
rev   line source
nuclear@0 1 /************************************************************************************
nuclear@0 2
nuclear@0 3 PublicHeader: None
nuclear@0 4 Filename : OVR_Hash.h
nuclear@0 5 Content : Template hash-table/set implementation
nuclear@0 6 Created : September 19, 2012
nuclear@0 7 Notes :
nuclear@0 8
nuclear@0 9 Copyright : Copyright 2014 Oculus VR, LLC All Rights reserved.
nuclear@0 10
nuclear@0 11 Licensed under the Oculus VR Rift SDK License Version 3.2 (the "License");
nuclear@0 12 you may not use the Oculus VR Rift SDK except in compliance with the License,
nuclear@0 13 which is provided at the time of installation or download, or which
nuclear@0 14 otherwise accompanies this software in either electronic or hard copy form.
nuclear@0 15
nuclear@0 16 You may obtain a copy of the License at
nuclear@0 17
nuclear@0 18 http://www.oculusvr.com/licenses/LICENSE-3.2
nuclear@0 19
nuclear@0 20 Unless required by applicable law or agreed to in writing, the Oculus VR SDK
nuclear@0 21 distributed under the License is distributed on an "AS IS" BASIS,
nuclear@0 22 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
nuclear@0 23 See the License for the specific language governing permissions and
nuclear@0 24 limitations under the License.
nuclear@0 25
nuclear@0 26 ************************************************************************************/
nuclear@0 27
nuclear@0 28 #ifndef OVR_Hash_h
nuclear@0 29 #define OVR_Hash_h
nuclear@0 30
nuclear@0 31 #include "OVR_ContainerAllocator.h"
nuclear@0 32 #include "OVR_Alg.h"
nuclear@0 33
nuclear@0 34 // 'new' operator is redefined/used in this file.
nuclear@0 35 #undef new
nuclear@0 36
nuclear@0 37 namespace OVR {
nuclear@0 38
nuclear@0 39 //-----------------------------------------------------------------------------------
nuclear@0 40 // ***** Hash Table Implementation
nuclear@0 41
nuclear@0 42 // HastSet and Hash.
nuclear@0 43 //
nuclear@0 44 // Hash table, linear probing, internal chaining. One interesting/nice thing
nuclear@0 45 // about this implementation is that the table itself is a flat chunk of memory
nuclear@0 46 // containing no pointers, only relative indices. If the key and value types
nuclear@0 47 // of the Hash contain no pointers, then the Hash can be serialized using raw IO.
nuclear@0 48 //
nuclear@0 49 // Never shrinks, unless you explicitly Clear() it. Expands on
nuclear@0 50 // demand, though. For best results, if you know roughly how big your
nuclear@0 51 // table will be, default it to that size when you create it.
nuclear@0 52 //
nuclear@0 53 // Key usability feature:
nuclear@0 54 //
nuclear@0 55 // 1. Allows node hash values to either be cached or not.
nuclear@0 56 //
nuclear@0 57 // 2. Allows for alternative keys with methods such as GetAlt(). Handy
nuclear@0 58 // if you need to search nodes by their components; no need to create
nuclear@0 59 // temporary nodes.
nuclear@0 60 //
nuclear@0 61
nuclear@0 62
nuclear@0 63 // *** Hash functors:
nuclear@0 64 //
nuclear@0 65 // IdentityHash - use when the key is already a good hash
nuclear@0 66 // HFixedSizeHash - general hash based on object's in-memory representation.
nuclear@0 67
nuclear@0 68
nuclear@0 69 // Hash is just the input value; can use this for integer-indexed hash tables.
nuclear@0 70 template<class C>
nuclear@0 71 class IdentityHash
nuclear@0 72 {
nuclear@0 73 public:
nuclear@0 74 size_t operator()(const C& data) const
nuclear@0 75 { return (size_t) data; }
nuclear@0 76 };
nuclear@0 77
nuclear@0 78 // Computes a hash of an object's representation.
nuclear@0 79 template<class C>
nuclear@0 80 class FixedSizeHash
nuclear@0 81 {
nuclear@0 82 public:
nuclear@0 83 // Alternative: "sdbm" hash function, suggested at same web page
nuclear@0 84 // above, http::/www.cs.yorku.ca/~oz/hash.html
nuclear@0 85 // This is somewhat slower then Bernstein, but it works way better than the above
nuclear@0 86 // hash function for hashing large numbers of 32-bit ints.
nuclear@0 87 static OVR_FORCE_INLINE size_t SDBM_Hash(const void* data_in, size_t size, size_t seed = 5381)
nuclear@0 88 {
nuclear@0 89 const uint8_t* data = (const uint8_t*) data_in;
nuclear@0 90 size_t h = seed;
nuclear@0 91 while (size-- > 0)
nuclear@0 92 {
nuclear@0 93 #ifndef __clang_analyzer__ // It mistakenly thinks data is garbage.
nuclear@0 94 h = (h << 16) + (h << 6) - h + (size_t)data[size];
nuclear@0 95 #endif
nuclear@0 96 }
nuclear@0 97 return h;
nuclear@0 98 }
nuclear@0 99
nuclear@0 100 size_t operator()(const C& data) const
nuclear@0 101 {
nuclear@0 102 const unsigned char* p = (const unsigned char*) &data;
nuclear@0 103 const size_t size = sizeof(C);
nuclear@0 104
nuclear@0 105 return SDBM_Hash(p, size);
nuclear@0 106 }
nuclear@0 107 };
nuclear@0 108
nuclear@0 109
nuclear@0 110
nuclear@0 111 // *** HashsetEntry Entry types.
nuclear@0 112
nuclear@0 113 // Compact hash table Entry type that re-computes hash keys during hash traversal.
nuclear@0 114 // Good to use if the hash function is cheap or the hash value is already cached in C.
nuclear@0 115 template<class C, class HashF>
nuclear@0 116 class HashsetEntry
nuclear@0 117 {
nuclear@0 118 public:
nuclear@0 119 // Internal chaining for collisions.
nuclear@0 120 intptr_t NextInChain;
nuclear@0 121 C Value;
nuclear@0 122
nuclear@0 123 HashsetEntry()
nuclear@0 124 : NextInChain(-2) { }
nuclear@0 125 HashsetEntry(const HashsetEntry& e)
nuclear@0 126 : NextInChain(e.NextInChain), Value(e.Value) { }
nuclear@0 127 HashsetEntry(const C& key, intptr_t next)
nuclear@0 128 : NextInChain(next), Value(key) { }
nuclear@0 129
nuclear@0 130 bool IsEmpty() const { return NextInChain == -2; }
nuclear@0 131 bool IsEndOfChain() const { return NextInChain == -1; }
nuclear@0 132
nuclear@0 133 // Cached hash value access - can be optimized bu storing hash locally.
nuclear@0 134 // Mask value only needs to be used if SetCachedHash is not implemented.
nuclear@0 135 size_t GetCachedHash(size_t maskValue) const { return HashF()(Value) & maskValue; }
nuclear@0 136 void SetCachedHash(size_t) {}
nuclear@0 137
nuclear@0 138 void Clear()
nuclear@0 139 {
nuclear@0 140 Value.~C(); // placement delete
nuclear@0 141 NextInChain = -2;
nuclear@0 142 }
nuclear@0 143 // Free is only used from dtor of hash; Clear is used during regular operations:
nuclear@0 144 // assignment, hash reallocations, value reassignments, so on.
nuclear@0 145 void Free() { Clear(); }
nuclear@0 146 };
nuclear@0 147
nuclear@0 148 // Hash table Entry type that caches the Entry hash value for nodes, so that it
nuclear@0 149 // does not need to be re-computed during access.
nuclear@0 150 template<class C, class HashF>
nuclear@0 151 class HashsetCachedEntry
nuclear@0 152 {
nuclear@0 153 public:
nuclear@0 154 // Internal chaining for collisions.
nuclear@0 155 intptr_t NextInChain;
nuclear@0 156 size_t HashValue;
nuclear@0 157 C Value;
nuclear@0 158
nuclear@0 159 HashsetCachedEntry()
nuclear@0 160 : NextInChain(-2) { }
nuclear@0 161 HashsetCachedEntry(const HashsetCachedEntry& e)
nuclear@0 162 : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
nuclear@0 163 HashsetCachedEntry(const C& key, intptr_t next)
nuclear@0 164 : NextInChain(next), Value(key) { }
nuclear@0 165
nuclear@0 166 bool IsEmpty() const { return NextInChain == -2; }
nuclear@0 167 bool IsEndOfChain() const { return NextInChain == -1; }
nuclear@0 168
nuclear@0 169 // Cached hash value access - can be optimized bu storing hash locally.
nuclear@0 170 // Mask value only needs to be used if SetCachedHash is not implemented.
nuclear@0 171 size_t GetCachedHash(size_t maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
nuclear@0 172 void SetCachedHash(size_t hashValue) { HashValue = hashValue; }
nuclear@0 173
nuclear@0 174 void Clear()
nuclear@0 175 {
nuclear@0 176 Value.~C();
nuclear@0 177 NextInChain = -2;
nuclear@0 178 }
nuclear@0 179 // Free is only used from dtor of hash; Clear is used during regular operations:
nuclear@0 180 // assignment, hash reallocations, value reassignments, so on.
nuclear@0 181 void Free() { Clear(); }
nuclear@0 182 };
nuclear@0 183
nuclear@0 184
nuclear@0 185 //-----------------------------------------------------------------------------------
nuclear@0 186 // *** HashSet implementation - relies on either cached or regular entries.
nuclear@0 187 //
nuclear@0 188 // Use: Entry = HashsetCachedEntry<C, HashF> if hashes are expensive to
nuclear@0 189 // compute and thus need caching in entries.
nuclear@0 190 // Entry = HashsetEntry<C, HashF> if hashes are already externally cached.
nuclear@0 191 //
nuclear@0 192 template<class C, class HashF = FixedSizeHash<C>,
nuclear@0 193 class AltHashF = HashF,
nuclear@0 194 class Allocator = ContainerAllocator<C>,
nuclear@0 195 class Entry = HashsetCachedEntry<C, HashF> >
nuclear@0 196 class HashSetBase
nuclear@0 197 {
nuclear@0 198 enum { HashMinSize = 8 };
nuclear@0 199
nuclear@0 200 public:
nuclear@0 201 OVR_MEMORY_REDEFINE_NEW(HashSetBase)
nuclear@0 202
nuclear@0 203 typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> SelfType;
nuclear@0 204
nuclear@0 205 HashSetBase() : pTable(NULL) { }
nuclear@0 206 HashSetBase(int sizeHint) : pTable(NULL) { SetCapacity(this, sizeHint); }
nuclear@0 207 HashSetBase(const SelfType& src) : pTable(NULL) { Assign(this, src); }
nuclear@0 208
nuclear@0 209 ~HashSetBase()
nuclear@0 210 {
nuclear@0 211 if (pTable)
nuclear@0 212 {
nuclear@0 213 // Delete the entries.
nuclear@0 214 for (size_t i = 0, n = pTable->SizeMask; i <= n; i++)
nuclear@0 215 {
nuclear@0 216 Entry* e = &E(i);
nuclear@0 217 if (!e->IsEmpty())
nuclear@0 218 e->Free();
nuclear@0 219 }
nuclear@0 220
nuclear@0 221 Allocator::Free(pTable);
nuclear@0 222 pTable = NULL;
nuclear@0 223 }
nuclear@0 224 }
nuclear@0 225
nuclear@0 226
nuclear@0 227 void Assign(const SelfType& src)
nuclear@0 228 {
nuclear@0 229 Clear();
nuclear@0 230 if (src.IsEmpty() == false)
nuclear@0 231 {
nuclear@0 232 SetCapacity(src.GetSize());
nuclear@0 233
nuclear@0 234 for (ConstIterator it = src.Begin(); it != src.End(); ++it)
nuclear@0 235 {
nuclear@0 236 Add(*it);
nuclear@0 237 }
nuclear@0 238 }
nuclear@0 239 }
nuclear@0 240
nuclear@0 241
nuclear@0 242 // Remove all entries from the HashSet table.
nuclear@0 243 void Clear()
nuclear@0 244 {
nuclear@0 245 if (pTable)
nuclear@0 246 {
nuclear@0 247 // Delete the entries.
nuclear@0 248 for (size_t i = 0, n = pTable->SizeMask; i <= n; i++)
nuclear@0 249 {
nuclear@0 250 Entry* e = &E(i);
nuclear@0 251 if (!e->IsEmpty())
nuclear@0 252 e->Clear();
nuclear@0 253 }
nuclear@0 254
nuclear@0 255 Allocator::Free(pTable);
nuclear@0 256 pTable = NULL;
nuclear@0 257 }
nuclear@0 258 }
nuclear@0 259
nuclear@0 260 // Returns true if the HashSet is empty.
nuclear@0 261 bool IsEmpty() const
nuclear@0 262 {
nuclear@0 263 return pTable == NULL || pTable->EntryCount == 0;
nuclear@0 264 }
nuclear@0 265
nuclear@0 266
nuclear@0 267 // Set a new or existing value under the key, to the value.
nuclear@0 268 // Pass a different class of 'key' so that assignment reference object
nuclear@0 269 // can be passed instead of the actual object.
nuclear@0 270 template<class CRef>
nuclear@0 271 void Set(const CRef& key)
nuclear@0 272 {
nuclear@0 273 size_t hashValue = HashF()(key);
nuclear@0 274 intptr_t index = (intptr_t)-1;
nuclear@0 275
nuclear@0 276 if (pTable != NULL)
nuclear@0 277 index = findIndexCore(key, hashValue & pTable->SizeMask);
nuclear@0 278
nuclear@0 279 if (index >= 0)
nuclear@0 280 {
nuclear@0 281 E(index).Value = key;
nuclear@0 282 }
nuclear@0 283 else
nuclear@0 284 {
nuclear@0 285 // Entry under key doesn't exist.
nuclear@0 286 add(key, hashValue);
nuclear@0 287 }
nuclear@0 288 }
nuclear@0 289
nuclear@0 290 template<class CRef>
nuclear@0 291 inline void Add(const CRef& key)
nuclear@0 292 {
nuclear@0 293 size_t hashValue = HashF()(key);
nuclear@0 294 add(key, hashValue);
nuclear@0 295 }
nuclear@0 296
nuclear@0 297 // Remove by alternative key.
nuclear@0 298 template<class K>
nuclear@0 299 void RemoveAlt(const K& key)
nuclear@0 300 {
nuclear@0 301 if (pTable == NULL)
nuclear@0 302 return;
nuclear@0 303
nuclear@0 304 size_t hashValue = AltHashF()(key);
nuclear@0 305 intptr_t index = hashValue & pTable->SizeMask;
nuclear@0 306
nuclear@0 307 Entry* e = &E(index);
nuclear@0 308
nuclear@0 309 // If empty node or occupied by collider, we have nothing to remove.
nuclear@0 310 if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != (size_t)index))
nuclear@0 311 return;
nuclear@0 312
nuclear@0 313 // Save index
nuclear@0 314 intptr_t naturalIndex = index;
nuclear@0 315 intptr_t prevIndex = -1;
nuclear@0 316
nuclear@0 317 while ((e->GetCachedHash(pTable->SizeMask) != (size_t)naturalIndex) || !(e->Value == key))
nuclear@0 318 {
nuclear@0 319 // Keep looking through the chain.
nuclear@0 320 prevIndex = index;
nuclear@0 321 index = e->NextInChain;
nuclear@0 322 if (index == -1)
nuclear@0 323 return; // End of chain, item not found
nuclear@0 324 e = &E(index);
nuclear@0 325 }
nuclear@0 326
nuclear@0 327 // Found it - our item is at index
nuclear@0 328 if (naturalIndex == index)
nuclear@0 329 {
nuclear@0 330 // If we have a follower, move it to us
nuclear@0 331 if (!e->IsEndOfChain())
nuclear@0 332 {
nuclear@0 333 Entry* enext = &E(e->NextInChain);
nuclear@0 334 e->Clear();
nuclear@0 335 new (e) Entry(*enext);
nuclear@0 336 // Point us to the follower's cell that will be cleared
nuclear@0 337 e = enext;
nuclear@0 338 }
nuclear@0 339 }
nuclear@0 340 else
nuclear@0 341 {
nuclear@0 342 // We are not at natural index, so deal with the prev items next index
nuclear@0 343 E(prevIndex).NextInChain = e->NextInChain;
nuclear@0 344 }
nuclear@0 345
nuclear@0 346 // Clear us, of the follower cell that was moved.
nuclear@0 347 e->Clear();
nuclear@0 348 pTable->EntryCount --;
nuclear@0 349 // Should we check the size to condense hash? ...
nuclear@0 350 }
nuclear@0 351
nuclear@0 352 // Remove by main key.
nuclear@0 353 template<class CRef>
nuclear@0 354 void Remove(const CRef& key)
nuclear@0 355 {
nuclear@0 356 RemoveAlt(key);
nuclear@0 357 }
nuclear@0 358
nuclear@0 359 // Retrieve the pointer to a value under the given key.
nuclear@0 360 // - If there's no value under the key, then return NULL.
nuclear@0 361 // - If there is a value, return the pointer.
nuclear@0 362 template<class K>
nuclear@0 363 C* Get(const K& key)
nuclear@0 364 {
nuclear@0 365 intptr_t index = findIndex(key);
nuclear@0 366 if (index >= 0)
nuclear@0 367 return &E(index).Value;
nuclear@0 368 return 0;
nuclear@0 369 }
nuclear@0 370
nuclear@0 371 template<class K>
nuclear@0 372 const C* Get(const K& key) const
nuclear@0 373 {
nuclear@0 374 intptr_t index = findIndex(key);
nuclear@0 375 if (index >= 0)
nuclear@0 376 return &E(index).Value;
nuclear@0 377 return 0;
nuclear@0 378 }
nuclear@0 379
nuclear@0 380 // Alternative key versions of Get. Used by Hash.
nuclear@0 381 template<class K>
nuclear@0 382 const C* GetAlt(const K& key) const
nuclear@0 383 {
nuclear@0 384 intptr_t index = findIndexAlt(key);
nuclear@0 385 if (index >= 0)
nuclear@0 386 return &E(index).Value;
nuclear@0 387 return 0;
nuclear@0 388 }
nuclear@0 389
nuclear@0 390 template<class K>
nuclear@0 391 C* GetAlt(const K& key)
nuclear@0 392 {
nuclear@0 393 intptr_t index = findIndexAlt(key);
nuclear@0 394 if (index >= 0)
nuclear@0 395 return &E(index).Value;
nuclear@0 396 return 0;
nuclear@0 397 }
nuclear@0 398
nuclear@0 399 template<class K>
nuclear@0 400 bool GetAlt(const K& key, C* pval) const
nuclear@0 401 {
nuclear@0 402 intptr_t index = findIndexAlt(key);
nuclear@0 403 if (index >= 0)
nuclear@0 404 {
nuclear@0 405 if (pval)
nuclear@0 406 *pval = E(index).Value;
nuclear@0 407 return true;
nuclear@0 408 }
nuclear@0 409 return false;
nuclear@0 410 }
nuclear@0 411
nuclear@0 412
nuclear@0 413 size_t GetSize() const
nuclear@0 414 {
nuclear@0 415 return pTable == NULL ? 0 : (size_t)pTable->EntryCount;
nuclear@0 416 }
nuclear@0 417 int GetSizeI() const { return (int)GetSize(); }
nuclear@0 418
nuclear@0 419
nuclear@0 420 // Resize the HashSet table to fit one more Entry. Often this
nuclear@0 421 // doesn't involve any action.
nuclear@0 422 void CheckExpand()
nuclear@0 423 {
nuclear@0 424 if (pTable == NULL)
nuclear@0 425 {
nuclear@0 426 // Initial creation of table. Make a minimum-sized table.
nuclear@0 427 setRawCapacity(HashMinSize);
nuclear@0 428 }
nuclear@0 429 else if (pTable->EntryCount * 5 > (pTable->SizeMask + 1) * 4)
nuclear@0 430 {
nuclear@0 431 // pTable is more than 5/4 ths full. Expand.
nuclear@0 432 setRawCapacity((pTable->SizeMask + 1) * 2);
nuclear@0 433 }
nuclear@0 434 }
nuclear@0 435
nuclear@0 436 // Hint the bucket count to >= n.
nuclear@0 437 void Resize(size_t n)
nuclear@0 438 {
nuclear@0 439 // Not really sure what this means in relation to
nuclear@0 440 // STLport's hash_map... they say they "increase the
nuclear@0 441 // bucket count to at least n" -- but does that mean
nuclear@0 442 // their real capacity after Resize(n) is more like
nuclear@0 443 // n*2 (since they do linked-list chaining within
nuclear@0 444 // buckets?).
nuclear@0 445 SetCapacity(n);
nuclear@0 446 }
nuclear@0 447
nuclear@0 448 // Size the HashSet so that it can comfortably contain the given
nuclear@0 449 // number of elements. If the HashSet already contains more
nuclear@0 450 // elements than newSize, then this may be a no-op.
nuclear@0 451 void SetCapacity(size_t newSize)
nuclear@0 452 {
nuclear@0 453 size_t newRawSize = (newSize * 5) / 4;
nuclear@0 454 if (newRawSize <= GetSize())
nuclear@0 455 return;
nuclear@0 456 setRawCapacity(newRawSize);
nuclear@0 457 }
nuclear@0 458
nuclear@0 459 // Disable inappropriate 'operator ->' warning on MSVC6.
nuclear@0 460 #ifdef OVR_CC_MSVC
nuclear@0 461 #if (OVR_CC_MSVC < 1300)
nuclear@0 462 # pragma warning(disable : 4284)
nuclear@0 463 #endif
nuclear@0 464 #endif
nuclear@0 465
nuclear@0 466 // Iterator API, like STL.
nuclear@0 467 struct ConstIterator
nuclear@0 468 {
nuclear@0 469 const C& operator * () const
nuclear@0 470 {
nuclear@0 471 OVR_ASSERT(Index >= 0 && Index <= (intptr_t)pHash->pTable->SizeMask);
nuclear@0 472 return pHash->E(Index).Value;
nuclear@0 473 }
nuclear@0 474
nuclear@0 475 const C* operator -> () const
nuclear@0 476 {
nuclear@0 477 OVR_ASSERT(Index >= 0 && Index <= (intptr_t)pHash->pTable->SizeMask);
nuclear@0 478 return &pHash->E(Index).Value;
nuclear@0 479 }
nuclear@0 480
nuclear@0 481 void operator ++ ()
nuclear@0 482 {
nuclear@0 483 // Find next non-empty Entry.
nuclear@0 484 if (Index <= (intptr_t)pHash->pTable->SizeMask)
nuclear@0 485 {
nuclear@0 486 Index++;
nuclear@0 487 while ((size_t)Index <= pHash->pTable->SizeMask &&
nuclear@0 488 pHash->E(Index).IsEmpty())
nuclear@0 489 {
nuclear@0 490 Index++;
nuclear@0 491 }
nuclear@0 492 }
nuclear@0 493 }
nuclear@0 494
nuclear@0 495 bool operator == (const ConstIterator& it) const
nuclear@0 496 {
nuclear@0 497 if (IsEnd() && it.IsEnd())
nuclear@0 498 {
nuclear@0 499 return true;
nuclear@0 500 }
nuclear@0 501 else
nuclear@0 502 {
nuclear@0 503 return (pHash == it.pHash) && (Index == it.Index);
nuclear@0 504 }
nuclear@0 505 }
nuclear@0 506
nuclear@0 507 bool operator != (const ConstIterator& it) const
nuclear@0 508 {
nuclear@0 509 return ! (*this == it);
nuclear@0 510 }
nuclear@0 511
nuclear@0 512
nuclear@0 513 bool IsEnd() const
nuclear@0 514 {
nuclear@0 515 return (pHash == NULL) ||
nuclear@0 516 (pHash->pTable == NULL) ||
nuclear@0 517 (Index > (intptr_t)pHash->pTable->SizeMask);
nuclear@0 518 }
nuclear@0 519
nuclear@0 520 ConstIterator()
nuclear@0 521 : pHash(NULL), Index(0)
nuclear@0 522 { }
nuclear@0 523
nuclear@0 524 public:
nuclear@0 525 // Constructor was intentionally made public to allow create
nuclear@0 526 // iterator with arbitrary index.
nuclear@0 527 ConstIterator(const SelfType* h, intptr_t index)
nuclear@0 528 : pHash(h), Index(index)
nuclear@0 529 { }
nuclear@0 530
nuclear@0 531 const SelfType* GetContainer() const
nuclear@0 532 {
nuclear@0 533 return pHash;
nuclear@0 534 }
nuclear@0 535 intptr_t GetIndex() const
nuclear@0 536 {
nuclear@0 537 return Index;
nuclear@0 538 }
nuclear@0 539
nuclear@0 540 protected:
nuclear@0 541 friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
nuclear@0 542
nuclear@0 543 const SelfType* pHash;
nuclear@0 544 intptr_t Index;
nuclear@0 545 };
nuclear@0 546
nuclear@0 547 friend struct ConstIterator;
nuclear@0 548
nuclear@0 549
nuclear@0 550 // Non-const Iterator; Get most of it from ConstIterator.
nuclear@0 551 struct Iterator : public ConstIterator
nuclear@0 552 {
nuclear@0 553 // Allow non-const access to entries.
nuclear@0 554 C& operator*() const
nuclear@0 555 {
nuclear@0 556 OVR_ASSERT((ConstIterator::pHash) && ConstIterator::pHash->pTable && (ConstIterator::Index >= 0) && (ConstIterator::Index <= (intptr_t)ConstIterator::pHash->pTable->SizeMask));
nuclear@0 557 return const_cast<SelfType*>(ConstIterator::pHash)->E(ConstIterator::Index).Value;
nuclear@0 558 }
nuclear@0 559
nuclear@0 560 C* operator->() const
nuclear@0 561 {
nuclear@0 562 return &(operator*());
nuclear@0 563 }
nuclear@0 564
nuclear@0 565 Iterator()
nuclear@0 566 : ConstIterator(NULL, 0)
nuclear@0 567 { }
nuclear@0 568
nuclear@0 569 // Removes current element from Hash
nuclear@0 570 void Remove()
nuclear@0 571 {
nuclear@0 572 RemoveAlt(operator*());
nuclear@0 573 }
nuclear@0 574
nuclear@0 575 template <class K>
nuclear@0 576 void RemoveAlt(const K& key)
nuclear@0 577 {
nuclear@0 578 SelfType* phash = const_cast<SelfType*>(ConstIterator::pHash);
nuclear@0 579 //Entry* ee = &phash->E(ConstIterator::Index);
nuclear@0 580 //const C& key = ee->Value;
nuclear@0 581
nuclear@0 582 size_t hashValue = AltHashF()(key);
nuclear@0 583 intptr_t index = hashValue & phash->pTable->SizeMask;
nuclear@0 584
nuclear@0 585 Entry* e = &phash->E(index);
nuclear@0 586
nuclear@0 587 // If empty node or occupied by collider, we have nothing to remove.
nuclear@0 588 if (e->IsEmpty() || (e->GetCachedHash(phash->pTable->SizeMask) != (size_t)index))
nuclear@0 589 return;
nuclear@0 590
nuclear@0 591 // Save index
nuclear@0 592 intptr_t naturalIndex = index;
nuclear@0 593 intptr_t prevIndex = -1;
nuclear@0 594
nuclear@0 595 while ((e->GetCachedHash(phash->pTable->SizeMask) != (size_t)naturalIndex) || !(e->Value == key))
nuclear@0 596 {
nuclear@0 597 // Keep looking through the chain.
nuclear@0 598 prevIndex = index;
nuclear@0 599 index = e->NextInChain;
nuclear@0 600 if (index == -1)
nuclear@0 601 return; // End of chain, item not found
nuclear@0 602 e = &phash->E(index);
nuclear@0 603 }
nuclear@0 604
nuclear@0 605 if (index == (intptr_t)ConstIterator::Index)
nuclear@0 606 {
nuclear@0 607 // Found it - our item is at index
nuclear@0 608 if (naturalIndex == index)
nuclear@0 609 {
nuclear@0 610 // If we have a follower, move it to us
nuclear@0 611 if (!e->IsEndOfChain())
nuclear@0 612 {
nuclear@0 613 Entry* enext = &phash->E(e->NextInChain);
nuclear@0 614 e->Clear();
nuclear@0 615 new (e) Entry(*enext);
nuclear@0 616 // Point us to the follower's cell that will be cleared
nuclear@0 617 e = enext;
nuclear@0 618 --ConstIterator::Index;
nuclear@0 619 }
nuclear@0 620 }
nuclear@0 621 else
nuclear@0 622 {
nuclear@0 623 // We are not at natural index, so deal with the prev items next index
nuclear@0 624 phash->E(prevIndex).NextInChain = e->NextInChain;
nuclear@0 625 }
nuclear@0 626
nuclear@0 627 // Clear us, of the follower cell that was moved.
nuclear@0 628 e->Clear();
nuclear@0 629 phash->pTable->EntryCount --;
nuclear@0 630 }
nuclear@0 631 else
nuclear@0 632 OVR_ASSERT(0); //?
nuclear@0 633 }
nuclear@0 634
nuclear@0 635 private:
nuclear@0 636 friend class HashSetBase<C, HashF, AltHashF, Allocator, Entry>;
nuclear@0 637
nuclear@0 638 Iterator(SelfType* h, intptr_t i0)
nuclear@0 639 : ConstIterator(h, i0)
nuclear@0 640 { }
nuclear@0 641 };
nuclear@0 642
nuclear@0 643 friend struct Iterator;
nuclear@0 644
nuclear@0 645 Iterator Begin()
nuclear@0 646 {
nuclear@0 647 if (pTable == 0)
nuclear@0 648 return Iterator(NULL, 0);
nuclear@0 649
nuclear@0 650 // Scan till we hit the First valid Entry.
nuclear@0 651 size_t i0 = 0;
nuclear@0 652 while (i0 <= pTable->SizeMask && E(i0).IsEmpty())
nuclear@0 653 {
nuclear@0 654 i0++;
nuclear@0 655 }
nuclear@0 656 return Iterator(this, i0);
nuclear@0 657 }
nuclear@0 658 Iterator End() { return Iterator(NULL, 0); }
nuclear@0 659
nuclear@0 660 ConstIterator Begin() const { return const_cast<SelfType*>(this)->Begin(); }
nuclear@0 661 ConstIterator End() const { return const_cast<SelfType*>(this)->End(); }
nuclear@0 662
nuclear@0 663 template<class K>
nuclear@0 664 Iterator Find(const K& key)
nuclear@0 665 {
nuclear@0 666 intptr_t index = findIndex(key);
nuclear@0 667 if (index >= 0)
nuclear@0 668 return Iterator(this, index);
nuclear@0 669 return Iterator(NULL, 0);
nuclear@0 670 }
nuclear@0 671
nuclear@0 672 template<class K>
nuclear@0 673 Iterator FindAlt(const K& key)
nuclear@0 674 {
nuclear@0 675 intptr_t index = findIndexAlt(key);
nuclear@0 676 if (index >= 0)
nuclear@0 677 return Iterator(this, index);
nuclear@0 678 return Iterator(NULL, 0);
nuclear@0 679 }
nuclear@0 680
nuclear@0 681 template<class K>
nuclear@0 682 ConstIterator Find(const K& key) const { return const_cast<SelfType*>(this)->Find(key); }
nuclear@0 683
nuclear@0 684 template<class K>
nuclear@0 685 ConstIterator FindAlt(const K& key) const { return const_cast<SelfType*>(this)->FindAlt(key); }
nuclear@0 686
nuclear@0 687 private:
nuclear@0 688 // Find the index of the matching Entry. If no match, then return -1.
nuclear@0 689 template<class K>
nuclear@0 690 intptr_t findIndex(const K& key) const
nuclear@0 691 {
nuclear@0 692 if (pTable == NULL)
nuclear@0 693 return -1;
nuclear@0 694 size_t hashValue = HashF()(key) & pTable->SizeMask;
nuclear@0 695 return findIndexCore(key, hashValue);
nuclear@0 696 }
nuclear@0 697
nuclear@0 698 template<class K>
nuclear@0 699 intptr_t findIndexAlt(const K& key) const
nuclear@0 700 {
nuclear@0 701 if (pTable == NULL)
nuclear@0 702 return -1;
nuclear@0 703 size_t hashValue = AltHashF()(key) & pTable->SizeMask;
nuclear@0 704 return findIndexCore(key, hashValue);
nuclear@0 705 }
nuclear@0 706
nuclear@0 707 // Find the index of the matching Entry. If no match, then return -1.
nuclear@0 708 template<class K>
nuclear@0 709 intptr_t findIndexCore(const K& key, size_t hashValue) const
nuclear@0 710 {
nuclear@0 711 // Table must exist.
nuclear@0 712 OVR_ASSERT(pTable != 0);
nuclear@0 713 // Hash key must be 'and-ed' by the caller.
nuclear@0 714 OVR_ASSERT((hashValue & ~pTable->SizeMask) == 0);
nuclear@0 715
nuclear@0 716 size_t index = hashValue;
nuclear@0 717 const Entry* e = &E(index);
nuclear@0 718
nuclear@0 719 // If empty or occupied by a collider, not found.
nuclear@0 720 if (e->IsEmpty() || (e->GetCachedHash(pTable->SizeMask) != index))
nuclear@0 721 return -1;
nuclear@0 722
nuclear@0 723 while(1)
nuclear@0 724 {
nuclear@0 725 OVR_ASSERT(e->GetCachedHash(pTable->SizeMask) == hashValue);
nuclear@0 726
nuclear@0 727 if (e->GetCachedHash(pTable->SizeMask) == hashValue && e->Value == key)
nuclear@0 728 {
nuclear@0 729 // Found it.
nuclear@0 730 return index;
nuclear@0 731 }
nuclear@0 732 // Values can not be equal at this point.
nuclear@0 733 // That would mean that the hash key for the same value differs.
nuclear@0 734 OVR_ASSERT(!(e->Value == key));
nuclear@0 735
nuclear@0 736 // Keep looking through the chain.
nuclear@0 737 index = e->NextInChain;
nuclear@0 738 if (index == (size_t)-1)
nuclear@0 739 break; // end of chain
nuclear@0 740
nuclear@0 741 e = &E(index);
nuclear@0 742 OVR_ASSERT(!e->IsEmpty());
nuclear@0 743 }
nuclear@0 744 return -1;
nuclear@0 745 }
nuclear@0 746
nuclear@0 747
nuclear@0 748 // Add a new value to the HashSet table, under the specified key.
nuclear@0 749 template<class CRef>
nuclear@0 750 void add(const CRef& key, size_t hashValue)
nuclear@0 751 {
nuclear@0 752 CheckExpand();
nuclear@0 753 hashValue &= pTable->SizeMask;
nuclear@0 754
nuclear@0 755 pTable->EntryCount++;
nuclear@0 756
nuclear@0 757 intptr_t index = hashValue;
nuclear@0 758 Entry* naturalEntry = &(E(index));
nuclear@0 759
nuclear@0 760 if (naturalEntry->IsEmpty())
nuclear@0 761 {
nuclear@0 762 // Put the new Entry in.
nuclear@0 763 new (naturalEntry) Entry(key, -1);
nuclear@0 764 }
nuclear@0 765 else
nuclear@0 766 {
nuclear@0 767 // Find a blank spot.
nuclear@0 768 intptr_t blankIndex = index;
nuclear@0 769 do {
nuclear@0 770 blankIndex = (blankIndex + 1) & pTable->SizeMask;
nuclear@0 771 } while(!E(blankIndex).IsEmpty());
nuclear@0 772
nuclear@0 773 Entry* blankEntry = &E(blankIndex);
nuclear@0 774
nuclear@0 775 if (naturalEntry->GetCachedHash(pTable->SizeMask) == (size_t)index)
nuclear@0 776 {
nuclear@0 777 // Collision. Link into this chain.
nuclear@0 778
nuclear@0 779 // Move existing list head.
nuclear@0 780 new (blankEntry) Entry(*naturalEntry); // placement new, copy ctor
nuclear@0 781
nuclear@0 782 // Put the new info in the natural Entry.
nuclear@0 783 naturalEntry->Value = key;
nuclear@0 784 naturalEntry->NextInChain = blankIndex;
nuclear@0 785 }
nuclear@0 786 else
nuclear@0 787 {
nuclear@0 788 // Existing Entry does not naturally
nuclear@0 789 // belong in this slot. Existing
nuclear@0 790 // Entry must be moved.
nuclear@0 791
nuclear@0 792 // Find natural location of collided element (i.e. root of chain)
nuclear@0 793 intptr_t collidedIndex = naturalEntry->GetCachedHash(pTable->SizeMask);
nuclear@0 794 OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (intptr_t)pTable->SizeMask);
nuclear@0 795 for (;;)
nuclear@0 796 {
nuclear@0 797 Entry* e = &E(collidedIndex);
nuclear@0 798 if (e->NextInChain == index)
nuclear@0 799 {
nuclear@0 800 // Here's where we need to splice.
nuclear@0 801 new (blankEntry) Entry(*naturalEntry);
nuclear@0 802 e->NextInChain = blankIndex;
nuclear@0 803 break;
nuclear@0 804 }
nuclear@0 805 collidedIndex = e->NextInChain;
nuclear@0 806 OVR_ASSERT(collidedIndex >= 0 && collidedIndex <= (intptr_t)pTable->SizeMask);
nuclear@0 807 }
nuclear@0 808
nuclear@0 809 // Put the new data in the natural Entry.
nuclear@0 810 naturalEntry->Value = key;
nuclear@0 811 naturalEntry->NextInChain = -1;
nuclear@0 812 }
nuclear@0 813 }
nuclear@0 814
nuclear@0 815 // Record hash value: has effect only if cached node is used.
nuclear@0 816 naturalEntry->SetCachedHash(hashValue);
nuclear@0 817 }
nuclear@0 818
nuclear@0 819 // Index access helpers.
nuclear@0 820 Entry& E(size_t index)
nuclear@0 821 {
nuclear@0 822 // Must have pTable and access needs to be within bounds.
nuclear@0 823 OVR_ASSERT(index <= pTable->SizeMask);
nuclear@0 824 return *(((Entry*) (pTable + 1)) + index);
nuclear@0 825 }
nuclear@0 826 const Entry& E(size_t index) const
nuclear@0 827 {
nuclear@0 828 OVR_ASSERT(index <= pTable->SizeMask);
nuclear@0 829 return *(((Entry*) (pTable + 1)) + index);
nuclear@0 830 }
nuclear@0 831
nuclear@0 832
nuclear@0 833 // Resize the HashSet table to the given size (Rehash the
nuclear@0 834 // contents of the current table). The arg is the number of
nuclear@0 835 // HashSet table entries, not the number of elements we should
nuclear@0 836 // actually contain (which will be less than this).
nuclear@0 837 void setRawCapacity(size_t newSize)
nuclear@0 838 {
nuclear@0 839 if (newSize == 0)
nuclear@0 840 {
nuclear@0 841 // Special case.
nuclear@0 842 Clear();
nuclear@0 843 return;
nuclear@0 844 }
nuclear@0 845
nuclear@0 846 // Minimum size; don't incur rehashing cost when expanding
nuclear@0 847 // very small tables. Not that we perform this check before
nuclear@0 848 // 'log2f' call to avoid fp exception with newSize == 1.
nuclear@0 849 if (newSize < HashMinSize)
nuclear@0 850 newSize = HashMinSize;
nuclear@0 851 else
nuclear@0 852 {
nuclear@0 853 // Force newSize to be a power of two.
nuclear@0 854 int bits = Alg::UpperBit(newSize-1) + 1; // Chop( Log2f((float)(newSize-1)) + 1);
nuclear@0 855 OVR_ASSERT((size_t(1) << bits) >= newSize);
nuclear@0 856 newSize = size_t(1) << bits;
nuclear@0 857 }
nuclear@0 858
nuclear@0 859 SelfType newHash;
nuclear@0 860 newHash.pTable = (TableType*)
nuclear@0 861 Allocator::Alloc(
nuclear@0 862 sizeof(TableType) + sizeof(Entry) * newSize);
nuclear@0 863 // Need to do something on alloc failure!
nuclear@0 864 OVR_ASSERT(newHash.pTable);
nuclear@0 865
nuclear@0 866 newHash.pTable->EntryCount = 0;
nuclear@0 867 newHash.pTable->SizeMask = newSize - 1;
nuclear@0 868 size_t i, n;
nuclear@0 869
nuclear@0 870 // Mark all entries as empty.
nuclear@0 871 for (i = 0; i < newSize; i++)
nuclear@0 872 newHash.E(i).NextInChain = -2;
nuclear@0 873
nuclear@0 874 // Copy stuff to newHash
nuclear@0 875 if (pTable)
nuclear@0 876 {
nuclear@0 877 for (i = 0, n = pTable->SizeMask; i <= n; i++)
nuclear@0 878 {
nuclear@0 879 Entry* e = &E(i);
nuclear@0 880 if (e->IsEmpty() == false)
nuclear@0 881 {
nuclear@0 882 // Insert old Entry into new HashSet.
nuclear@0 883 newHash.Add(e->Value);
nuclear@0 884 // placement delete of old element
nuclear@0 885 e->Clear();
nuclear@0 886 }
nuclear@0 887 }
nuclear@0 888
nuclear@0 889 // Delete our old data buffer.
nuclear@0 890 Allocator::Free(pTable);
nuclear@0 891 }
nuclear@0 892
nuclear@0 893 // Steal newHash's data.
nuclear@0 894 pTable = newHash.pTable;
nuclear@0 895 newHash.pTable = NULL;
nuclear@0 896 }
nuclear@0 897
nuclear@0 898 struct TableType
nuclear@0 899 {
nuclear@0 900 size_t EntryCount;
nuclear@0 901 size_t SizeMask;
nuclear@0 902 // Entry array follows this structure
nuclear@0 903 // in memory.
nuclear@0 904 };
nuclear@0 905 TableType* pTable;
nuclear@0 906 };
nuclear@0 907
nuclear@0 908
nuclear@0 909
nuclear@0 910 //-----------------------------------------------------------------------------------
nuclear@0 911 template<class C, class HashF = FixedSizeHash<C>,
nuclear@0 912 class AltHashF = HashF,
nuclear@0 913 class Allocator = ContainerAllocator<C>,
nuclear@0 914 class Entry = HashsetCachedEntry<C, HashF> >
nuclear@0 915 class HashSet : public HashSetBase<C, HashF, AltHashF, Allocator, Entry>
nuclear@0 916 {
nuclear@0 917 public:
nuclear@0 918 typedef HashSetBase<C, HashF, AltHashF, Allocator, Entry> BaseType;
nuclear@0 919 typedef HashSet<C, HashF, AltHashF, Allocator, Entry> SelfType;
nuclear@0 920
nuclear@0 921 HashSet() { }
nuclear@0 922 HashSet(int sizeHint) : BaseType(sizeHint) { }
nuclear@0 923 HashSet(const SelfType& src) : BaseType(src) { }
nuclear@0 924 ~HashSet() { }
nuclear@0 925
nuclear@0 926 void operator = (const SelfType& src) { BaseType::Assign(src); }
nuclear@0 927
nuclear@0 928 // Set a new or existing value under the key, to the value.
nuclear@0 929 // Pass a different class of 'key' so that assignment reference object
nuclear@0 930 // can be passed instead of the actual object.
nuclear@0 931 template<class CRef>
nuclear@0 932 void Set(const CRef& key)
nuclear@0 933 {
nuclear@0 934 BaseType::Set(key);
nuclear@0 935 }
nuclear@0 936
nuclear@0 937 template<class CRef>
nuclear@0 938 inline void Add(const CRef& key)
nuclear@0 939 {
nuclear@0 940 BaseType::Add(key);
nuclear@0 941 }
nuclear@0 942
nuclear@0 943 // Hint the bucket count to >= n.
nuclear@0 944 void Resize(size_t n)
nuclear@0 945 {
nuclear@0 946 BaseType::SetCapacity(n);
nuclear@0 947 }
nuclear@0 948
nuclear@0 949 // Size the HashSet so that it can comfortably contain the given
nuclear@0 950 // number of elements. If the HashSet already contains more
nuclear@0 951 // elements than newSize, then this may be a no-op.
nuclear@0 952 void SetCapacity(size_t newSize)
nuclear@0 953 {
nuclear@0 954 BaseType::SetCapacity(newSize);
nuclear@0 955 }
nuclear@0 956
nuclear@0 957 };
nuclear@0 958
nuclear@0 959 // HashSet with uncached hash code; declared for convenience.
nuclear@0 960 template<class C, class HashF = FixedSizeHash<C>,
nuclear@0 961 class AltHashF = HashF,
nuclear@0 962 class Allocator = ContainerAllocator<C> >
nuclear@0 963 class HashSetUncached : public HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> >
nuclear@0 964 {
nuclear@0 965 public:
nuclear@0 966
nuclear@0 967 typedef HashSetUncached<C, HashF, AltHashF, Allocator> SelfType;
nuclear@0 968 typedef HashSet<C, HashF, AltHashF, Allocator, HashsetEntry<C, HashF> > BaseType;
nuclear@0 969
nuclear@0 970 // Delegated constructors.
nuclear@0 971 HashSetUncached() { }
nuclear@0 972 HashSetUncached(int sizeHint) : BaseType(sizeHint) { }
nuclear@0 973 HashSetUncached(const SelfType& src) : BaseType(src) { }
nuclear@0 974 ~HashSetUncached() { }
nuclear@0 975
nuclear@0 976 void operator = (const SelfType& src)
nuclear@0 977 {
nuclear@0 978 BaseType::operator = (src);
nuclear@0 979 }
nuclear@0 980 };
nuclear@0 981
nuclear@0 982
nuclear@0 983 //-----------------------------------------------------------------------------------
nuclear@0 984 // ***** Hash hash table implementation
nuclear@0 985
nuclear@0 986 // Node for Hash - necessary so that Hash can delegate its implementation
nuclear@0 987 // to HashSet.
nuclear@0 988 template<class C, class U, class HashF>
nuclear@0 989 struct HashNode
nuclear@0 990 {
nuclear@0 991 typedef HashNode<C, U, HashF> SelfType;
nuclear@0 992 typedef C FirstType;
nuclear@0 993 typedef U SecondType;
nuclear@0 994
nuclear@0 995 C First;
nuclear@0 996 U Second;
nuclear@0 997
nuclear@0 998 // NodeRef is used to allow passing of elements into HashSet
nuclear@0 999 // without using a temporary object.
nuclear@0 1000 struct NodeRef
nuclear@0 1001 {
nuclear@0 1002 const C* pFirst;
nuclear@0 1003 const U* pSecond;
nuclear@0 1004
nuclear@0 1005 NodeRef(const C& f, const U& s) : pFirst(&f), pSecond(&s) { }
nuclear@0 1006 NodeRef(const NodeRef& src) : pFirst(src.pFirst), pSecond(src.pSecond) { }
nuclear@0 1007
nuclear@0 1008 // Enable computation of ghash_node_hashf.
nuclear@0 1009 inline size_t GetHash() const { return HashF()(*pFirst); }
nuclear@0 1010 // Necessary conversion to allow HashNode::operator == to work.
nuclear@0 1011 operator const C& () const { return *pFirst; }
nuclear@0 1012 };
nuclear@0 1013
nuclear@0 1014 // Note: No default constructor is necessary.
nuclear@0 1015 HashNode(const HashNode& src) : First(src.First), Second(src.Second) { }
nuclear@0 1016 HashNode(const NodeRef& src) : First(*src.pFirst), Second(*src.pSecond) { }
nuclear@0 1017 void operator = (const NodeRef& src) { First = *src.pFirst; Second = *src.pSecond; }
nuclear@0 1018
nuclear@0 1019 template<class K>
nuclear@0 1020 bool operator == (const K& src) const { return (First == src); }
nuclear@0 1021
nuclear@0 1022 template<class K>
nuclear@0 1023 static size_t CalcHash(const K& data) { return HashF()(data); }
nuclear@0 1024 inline size_t GetHash() const { return HashF()(First); }
nuclear@0 1025
nuclear@0 1026 // Hash functors used with this node. A separate functor is used for alternative
nuclear@0 1027 // key lookup so that it does not need to access the '.First' element.
nuclear@0 1028 struct NodeHashF
nuclear@0 1029 {
nuclear@0 1030 template<class K>
nuclear@0 1031 size_t operator()(const K& data) const { return data.GetHash(); }
nuclear@0 1032 };
nuclear@0 1033 struct NodeAltHashF
nuclear@0 1034 {
nuclear@0 1035 template<class K>
nuclear@0 1036 size_t operator()(const K& data) const { return HashNode<C,U,HashF>::CalcHash(data); }
nuclear@0 1037 };
nuclear@0 1038 };
nuclear@0 1039
nuclear@0 1040
nuclear@0 1041
nuclear@0 1042 // **** Extra hashset_entry types to allow NodeRef construction.
nuclear@0 1043
nuclear@0 1044 // The big difference between the below types and the ones used in hash_set is that
nuclear@0 1045 // these allow initializing the node with 'typename C::NodeRef& keyRef', which
nuclear@0 1046 // is critical to avoid temporary node allocation on stack when using placement new.
nuclear@0 1047
nuclear@0 1048 // Compact hash table Entry type that re-computes hash keys during hash traversal.
nuclear@0 1049 // Good to use if the hash function is cheap or the hash value is already cached in C.
nuclear@0 1050 template<class C, class HashF>
nuclear@0 1051 class HashsetNodeEntry
nuclear@0 1052 {
nuclear@0 1053 public:
nuclear@0 1054 // Internal chaining for collisions.
nuclear@0 1055 intptr_t NextInChain;
nuclear@0 1056 C Value;
nuclear@0 1057
nuclear@0 1058 HashsetNodeEntry()
nuclear@0 1059 : NextInChain(-2) { }
nuclear@0 1060 HashsetNodeEntry(const HashsetNodeEntry& e)
nuclear@0 1061 : NextInChain(e.NextInChain), Value(e.Value) { }
nuclear@0 1062 HashsetNodeEntry(const C& key, intptr_t next)
nuclear@0 1063 : NextInChain(next), Value(key) { }
nuclear@0 1064 HashsetNodeEntry(const typename C::NodeRef& keyRef, intptr_t next)
nuclear@0 1065 : NextInChain(next), Value(keyRef) { }
nuclear@0 1066
nuclear@0 1067 bool IsEmpty() const { return NextInChain == -2; }
nuclear@0 1068 bool IsEndOfChain() const { return NextInChain == -1; }
nuclear@0 1069 size_t GetCachedHash(size_t maskValue) const { return HashF()(Value) & maskValue; }
nuclear@0 1070 void SetCachedHash(size_t hashValue) { OVR_UNUSED(hashValue); }
nuclear@0 1071
nuclear@0 1072 void Clear()
nuclear@0 1073 {
nuclear@0 1074 Value.~C(); // placement delete
nuclear@0 1075 NextInChain = -2;
nuclear@0 1076 }
nuclear@0 1077 // Free is only used from dtor of hash; Clear is used during regular operations:
nuclear@0 1078 // assignment, hash reallocations, value reassignments, so on.
nuclear@0 1079 void Free() { Clear(); }
nuclear@0 1080 };
nuclear@0 1081
nuclear@0 1082 // Hash table Entry type that caches the Entry hash value for nodes, so that it
nuclear@0 1083 // does not need to be re-computed during access.
nuclear@0 1084 template<class C, class HashF>
nuclear@0 1085 class HashsetCachedNodeEntry
nuclear@0 1086 {
nuclear@0 1087 public:
nuclear@0 1088 // Internal chaining for collisions.
nuclear@0 1089 intptr_t NextInChain;
nuclear@0 1090 size_t HashValue;
nuclear@0 1091 C Value;
nuclear@0 1092
nuclear@0 1093 HashsetCachedNodeEntry()
nuclear@0 1094 : NextInChain(-2) { }
nuclear@0 1095 HashsetCachedNodeEntry(const HashsetCachedNodeEntry& e)
nuclear@0 1096 : NextInChain(e.NextInChain), HashValue(e.HashValue), Value(e.Value) { }
nuclear@0 1097 HashsetCachedNodeEntry(const C& key, intptr_t next)
nuclear@0 1098 : NextInChain(next), Value(key) { }
nuclear@0 1099 HashsetCachedNodeEntry(const typename C::NodeRef& keyRef, intptr_t next)
nuclear@0 1100 : NextInChain(next), Value(keyRef) { }
nuclear@0 1101
nuclear@0 1102 bool IsEmpty() const { return NextInChain == -2; }
nuclear@0 1103 bool IsEndOfChain() const { return NextInChain == -1; }
nuclear@0 1104 size_t GetCachedHash(size_t maskValue) const { OVR_UNUSED(maskValue); return HashValue; }
nuclear@0 1105 void SetCachedHash(size_t hashValue) { HashValue = hashValue; }
nuclear@0 1106
nuclear@0 1107 void Clear()
nuclear@0 1108 {
nuclear@0 1109 Value.~C();
nuclear@0 1110 NextInChain = -2;
nuclear@0 1111 }
nuclear@0 1112 // Free is only used from dtor of hash; Clear is used during regular operations:
nuclear@0 1113 // assignment, hash reallocations, value reassignments, so on.
nuclear@0 1114 void Free() { Clear(); }
nuclear@0 1115 };
nuclear@0 1116
nuclear@0 1117
nuclear@0 1118 //-----------------------------------------------------------------------------------
nuclear@0 1119 template<class C, class U,
nuclear@0 1120 class HashF = FixedSizeHash<C>,
nuclear@0 1121 class Allocator = ContainerAllocator<C>,
nuclear@0 1122 class HashNode = OVR::HashNode<C,U,HashF>,
nuclear@0 1123 class Entry = HashsetCachedNodeEntry<HashNode, typename HashNode::NodeHashF>,
nuclear@0 1124 class Container = HashSet<HashNode, typename HashNode::NodeHashF,
nuclear@0 1125 typename HashNode::NodeAltHashF, Allocator,
nuclear@0 1126 Entry> >
nuclear@0 1127 class Hash
nuclear@0 1128 {
nuclear@0 1129 public:
nuclear@0 1130 OVR_MEMORY_REDEFINE_NEW(Hash)
nuclear@0 1131
nuclear@0 1132 // Types used for hash_set.
nuclear@0 1133 typedef U ValueType;
nuclear@0 1134 typedef Hash<C, U, HashF, Allocator, HashNode, Entry, Container> SelfType;
nuclear@0 1135
nuclear@0 1136 // Actual hash table itself, implemented as hash_set.
nuclear@0 1137 Container mHash;
nuclear@0 1138
nuclear@0 1139 public:
nuclear@0 1140 Hash() { }
nuclear@0 1141 Hash(int sizeHint) : mHash(sizeHint) { }
nuclear@0 1142 Hash(const SelfType& src) : mHash(src.mHash) { }
nuclear@0 1143 ~Hash() { }
nuclear@0 1144
nuclear@0 1145 void operator = (const SelfType& src) { mHash = src.mHash; }
nuclear@0 1146
nuclear@0 1147 // Remove all entries from the Hash table.
nuclear@0 1148 inline void Clear() { mHash.Clear(); }
nuclear@0 1149 // Returns true if the Hash is empty.
nuclear@0 1150 inline bool IsEmpty() const { return mHash.IsEmpty(); }
nuclear@0 1151
nuclear@0 1152 // Access (set).
nuclear@0 1153 inline void Set(const C& key, const U& value)
nuclear@0 1154 {
nuclear@0 1155 typename HashNode::NodeRef e(key, value);
nuclear@0 1156 mHash.Set(e);
nuclear@0 1157 }
nuclear@0 1158 inline void Add(const C& key, const U& value)
nuclear@0 1159 {
nuclear@0 1160 typename HashNode::NodeRef e(key, value);
nuclear@0 1161 mHash.Add(e);
nuclear@0 1162 }
nuclear@0 1163
nuclear@0 1164 // Removes an element by clearing its Entry.
nuclear@0 1165 inline void Remove(const C& key)
nuclear@0 1166 {
nuclear@0 1167 mHash.RemoveAlt(key);
nuclear@0 1168 }
nuclear@0 1169 template<class K>
nuclear@0 1170 inline void RemoveAlt(const K& key)
nuclear@0 1171 {
nuclear@0 1172 mHash.RemoveAlt(key);
nuclear@0 1173 }
nuclear@0 1174
nuclear@0 1175 // Retrieve the value under the given key.
nuclear@0 1176 // - If there's no value under the key, then return false and leave *pvalue alone.
nuclear@0 1177 // - If there is a value, return true, and Set *Pvalue to the Entry's value.
nuclear@0 1178 // - If value == NULL, return true or false according to the presence of the key.
nuclear@0 1179 bool Get(const C& key, U* pvalue) const
nuclear@0 1180 {
nuclear@0 1181 const HashNode* p = mHash.GetAlt(key);
nuclear@0 1182 if (p)
nuclear@0 1183 {
nuclear@0 1184 if (pvalue)
nuclear@0 1185 *pvalue = p->Second;
nuclear@0 1186 return true;
nuclear@0 1187 }
nuclear@0 1188 return false;
nuclear@0 1189 }
nuclear@0 1190
nuclear@0 1191 template<class K>
nuclear@0 1192 bool GetAlt(const K& key, U* pvalue) const
nuclear@0 1193 {
nuclear@0 1194 const HashNode* p = mHash.GetAlt(key);
nuclear@0 1195 if (p)
nuclear@0 1196 {
nuclear@0 1197 if (pvalue)
nuclear@0 1198 *pvalue = p->Second;
nuclear@0 1199 return true;
nuclear@0 1200 }
nuclear@0 1201 return false;
nuclear@0 1202 }
nuclear@0 1203
nuclear@0 1204 // Retrieve the pointer to a value under the given key.
nuclear@0 1205 // - If there's no value under the key, then return NULL.
nuclear@0 1206 // - If there is a value, return the pointer.
nuclear@0 1207 inline U* Get(const C& key)
nuclear@0 1208 {
nuclear@0 1209 HashNode* p = mHash.GetAlt(key);
nuclear@0 1210 return p ? &p->Second : 0;
nuclear@0 1211 }
nuclear@0 1212 inline const U* Get(const C& key) const
nuclear@0 1213 {
nuclear@0 1214 const HashNode* p = mHash.GetAlt(key);
nuclear@0 1215 return p ? &p->Second : 0;
nuclear@0 1216 }
nuclear@0 1217
nuclear@0 1218 template<class K>
nuclear@0 1219 inline U* GetAlt(const K& key)
nuclear@0 1220 {
nuclear@0 1221 HashNode* p = mHash.GetAlt(key);
nuclear@0 1222 return p ? &p->Second : 0;
nuclear@0 1223 }
nuclear@0 1224 template<class K>
nuclear@0 1225 inline const U* GetAlt(const K& key) const
nuclear@0 1226 {
nuclear@0 1227 const HashNode* p = mHash.GetAlt(key);
nuclear@0 1228 return p ? &p->Second : 0;
nuclear@0 1229 }
nuclear@0 1230
nuclear@0 1231 // Sizing methods - delegate to Hash.
nuclear@0 1232 inline size_t GetSize() const { return mHash.GetSize(); }
nuclear@0 1233 inline int GetSizeI() const { return (int)GetSize(); }
nuclear@0 1234 inline void Resize(size_t n) { mHash.Resize(n); }
nuclear@0 1235 inline void SetCapacity(size_t newSize) { mHash.SetCapacity(newSize); }
nuclear@0 1236
nuclear@0 1237 // Iterator API, like STL.
nuclear@0 1238 typedef typename Container::ConstIterator ConstIterator;
nuclear@0 1239 typedef typename Container::Iterator Iterator;
nuclear@0 1240
nuclear@0 1241 inline Iterator Begin() { return mHash.Begin(); }
nuclear@0 1242 inline Iterator End() { return mHash.End(); }
nuclear@0 1243 inline ConstIterator Begin() const { return mHash.Begin(); }
nuclear@0 1244 inline ConstIterator End() const { return mHash.End(); }
nuclear@0 1245
nuclear@0 1246 Iterator Find(const C& key) { return mHash.FindAlt(key); }
nuclear@0 1247 ConstIterator Find(const C& key) const { return mHash.FindAlt(key); }
nuclear@0 1248
nuclear@0 1249 template<class K>
nuclear@0 1250 Iterator FindAlt(const K& key) { return mHash.FindAlt(key); }
nuclear@0 1251 template<class K>
nuclear@0 1252 ConstIterator FindAlt(const K& key) const { return mHash.FindAlt(key); }
nuclear@0 1253 };
nuclear@0 1254
nuclear@0 1255
nuclear@0 1256
nuclear@0 1257 // Hash with uncached hash code; declared for convenience.
nuclear@0 1258 template<class C, class U, class HashF = FixedSizeHash<C>, class Allocator = ContainerAllocator<C> >
nuclear@0 1259 class HashUncached
nuclear@0 1260 : public Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
nuclear@0 1261 HashsetNodeEntry<HashNode<C,U,HashF>, typename HashNode<C,U,HashF>::NodeHashF> >
nuclear@0 1262 {
nuclear@0 1263 public:
nuclear@0 1264 typedef HashUncached<C, U, HashF, Allocator> SelfType;
nuclear@0 1265 typedef Hash<C, U, HashF, Allocator, HashNode<C,U,HashF>,
nuclear@0 1266 HashsetNodeEntry<HashNode<C,U,HashF>,
nuclear@0 1267 typename HashNode<C,U,HashF>::NodeHashF> > BaseType;
nuclear@0 1268
nuclear@0 1269 // Delegated constructors.
nuclear@0 1270 HashUncached() { }
nuclear@0 1271 HashUncached(int sizeHint) : BaseType(sizeHint) { }
nuclear@0 1272 HashUncached(const SelfType& src) : BaseType(src) { }
nuclear@0 1273 ~HashUncached() { }
nuclear@0 1274 void operator = (const SelfType& src) { BaseType::operator = (src); }
nuclear@0 1275 };
nuclear@0 1276
nuclear@0 1277
nuclear@0 1278
nuclear@0 1279 // And identity hash in which keys serve as hash value. Can be uncached,
nuclear@0 1280 // since hash computation is assumed cheap.
nuclear@0 1281 template<class C, class U, class Allocator = ContainerAllocator<C>, class HashF = IdentityHash<C> >
nuclear@0 1282 class HashIdentity
nuclear@0 1283 : public HashUncached<C, U, HashF, Allocator>
nuclear@0 1284 {
nuclear@0 1285 public:
nuclear@0 1286 typedef HashIdentity<C, U, Allocator, HashF> SelfType;
nuclear@0 1287 typedef HashUncached<C, U, HashF, Allocator> BaseType;
nuclear@0 1288
nuclear@0 1289 // Delegated constructors.
nuclear@0 1290 HashIdentity() { }
nuclear@0 1291 HashIdentity(int sizeHint) : BaseType(sizeHint) { }
nuclear@0 1292 HashIdentity(const SelfType& src) : BaseType(src) { }
nuclear@0 1293 ~HashIdentity() { }
nuclear@0 1294 void operator = (const SelfType& src) { BaseType::operator = (src); }
nuclear@0 1295 };
nuclear@0 1296
nuclear@0 1297
nuclear@0 1298 } // OVR
nuclear@0 1299
nuclear@0 1300
nuclear@0 1301 #ifdef OVR_DEFINE_NEW
nuclear@0 1302 #define new OVR_DEFINE_NEW
nuclear@0 1303 #endif
nuclear@0 1304
nuclear@0 1305 #endif