AkHashTableFuncs.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /***********************************************************************
  2. The content of this file includes source code for the sound engine
  3. portion of the AUDIOKINETIC Wwise Technology and constitutes "Level
  4. Two Source Code" as defined in the Source Code Addendum attached
  5. with this file. Any use of the Level Two Source Code shall be
  6. subject to the terms and conditions outlined in the Source Code
  7. Addendum and the End User License Agreement for Wwise(R).
  8. Copyright (c) 2023 Audiokinetic Inc.
  9. ***********************************************************************/
  10. #pragma once
  11. #include <AK/SoundEngine/Common/AkHashTableTypes.h>
  12. // Inline-able functions for AK::HashTable
  13. // Exposing enough functionality to be use by plug-in services and other things in non-header files
  14. // For plug-ins, further functionality is provided by IAkPluginServiceHashTable
  15. // For core soundengine execution, further functionality is provided in AkHashTable.h
  16. namespace AK
  17. {
  18. namespace HashTable
  19. {
  20. namespace Internal
  21. {
  22. template<typename KeyType>
  23. inline AkInt32 IdealPos(KeyType uKey, AkInt32 iEntriesMask)
  24. {
  25. return AkInt32(uKey) & iEntriesMask;
  26. }
  27. // returns how far away the current slot is from the key's ideal position
  28. template<typename KeyType>
  29. AkInt32 DistanceFromIdealPos(AkInt32 iSlot, KeyType uKey, AkInt32 iEntriesMask)
  30. {
  31. // subtraction against an unmasked key and then masking afterwards,
  32. // will give same result as if we masked the slot and key individually, first
  33. // (also wraparound of the slot relative to the ukey also washes away with the masking)
  34. return (iSlot - AkInt32(uKey)) & iEntriesMask;
  35. }
  36. // Internal helper function for AkHashTableBase; don't call this directly, use AK::HashTable::Get* functions instead
  37. template<typename KeyType>
  38. inline AkInt32 LinearProbe(const KeyType* pKeys, const bool* pbSlotOccupied, KeyType uKey, AkInt32 iSlot, AkUInt32 uNumEntries)
  39. {
  40. AkInt32 iDistFromBestSlot = 0;
  41. AkInt32 iEntriesMask = (AkInt32)uNumEntries - 1;
  42. for (; ; )
  43. {
  44. if (!pbSlotOccupied[iSlot])
  45. return -1;
  46. KeyType keyInSlot = pKeys[iSlot];
  47. if (keyInSlot == uKey)
  48. break;
  49. if (iDistFromBestSlot > DistanceFromIdealPos(iSlot, keyInSlot, iEntriesMask))
  50. return -1;
  51. iSlot = (iSlot + 1) & iEntriesMask;
  52. ++iDistFromBestSlot;
  53. }
  54. return iSlot;
  55. }
  56. // Internal helper function for AkHashTableBase; don't call this directly, use AkHashTableGet* functions instead
  57. inline AkInt32 OccupiedProbe(const bool* pbSlotOccupied, AkInt32 iSlot, AkInt32 iNumEntries)
  58. {
  59. while (iSlot < iNumEntries)
  60. {
  61. // 64-bit load to scan 8 pbSlotOccupieds at once
  62. // (safe to load a bit past the end of slotOccupied region because we cap against iNumEntries anyway)
  63. if (AkUInt64 slotOccCompressed = *((AkUInt64*)(pbSlotOccupied + iSlot)))
  64. {
  65. iSlot = iSlot + AKPLATFORM::AkBitScanForward64(slotOccCompressed) / 8;
  66. iSlot = (iSlot >= iNumEntries) ? -1 : iSlot;
  67. return iSlot;
  68. }
  69. else
  70. {
  71. iSlot += 8;
  72. }
  73. }
  74. return -1;
  75. }
  76. } // namespace Internal
  77. // returns either:
  78. // the slot of the first valid entry that uKey maps to
  79. // -1 if there are no valid entries at the table that uKey maps to
  80. template<typename KeyType>
  81. inline AkInt32 GetFirstSlotForKey(const AkHashTableBase<KeyType>* pHashTable, KeyType uKey)
  82. {
  83. if (pHashTable->uNumReservedEntries == 0)
  84. return -1;
  85. AkUInt32 uNumEntries = pHashTable->uNumReservedEntries;
  86. AkInt32 iBestSlot = uKey & (uNumEntries - 1);
  87. return Internal::LinearProbe(pHashTable->pKeys, pHashTable->pbSlotOccupied, uKey, iBestSlot, uNumEntries);
  88. }
  89. // returns either:
  90. // the next slot after iPreviousIndex which contains a valid entry
  91. // -1 if the next table after iPreviousIndex doesn't contain a valid entry
  92. template<typename KeyType>
  93. inline AkInt32 GetNextSlotForKey(const AkHashTableBase<KeyType>* pHashTable, KeyType uKey, AkInt32 iPreviousSlot)
  94. {
  95. if (pHashTable->uNumReservedEntries == 0)
  96. return -1;
  97. AkUInt32 uNumEntries = pHashTable->uNumReservedEntries;
  98. AkInt32 iNextSlot = (iPreviousSlot + 1) & (uNumEntries - 1);
  99. return Internal::LinearProbe(pHashTable->pKeys, pHashTable->pbSlotOccupied, uKey, iNextSlot, uNumEntries);
  100. }
  101. // returns either:
  102. // the slot of the first occupied entry in the hash table
  103. // -1 if there are no occupied entries in the table
  104. template<typename KeyType>
  105. inline AkInt32 GetFirstActiveSlot(const AkHashTableBase<KeyType>* pHashTable)
  106. {
  107. return Internal::OccupiedProbe(pHashTable->pbSlotOccupied, 0, (AkInt32)pHashTable->uNumReservedEntries);
  108. }
  109. // returns either:
  110. // the slot of the next occupied entry in the hash table (relative to iPreviousSlot)
  111. // -1 if there are no occupied entries in the table after iPreviousSlot
  112. template<typename KeyType>
  113. inline AkInt32 GetNextActiveSlot(const AkHashTableBase<KeyType>* pHashTable, AkInt32 iPreviousSlot)
  114. {
  115. return Internal::OccupiedProbe(pHashTable->pbSlotOccupied, iPreviousSlot + 1, (AkInt32)pHashTable->uNumReservedEntries);
  116. }
  117. // runs the provided function over every active slot in the hashtable
  118. // functype(AkUInt32 in_slot)
  119. template<typename KeyType, typename FuncType>
  120. inline void ForEachSlot(const AkHashTableBase<KeyType>* in_pHashTable, FuncType in_func)
  121. {
  122. AkUInt32 uNumReservedEntries = in_pHashTable->uNumReservedEntries;
  123. bool* pbSlotOccupied = in_pHashTable->pbSlotOccupied;
  124. for (AkUInt32 uBaseSlot = 0; uBaseSlot < uNumReservedEntries; uBaseSlot += 8)
  125. {
  126. AkUInt64 slotOccMask = *(AkUInt64*)(pbSlotOccupied + uBaseSlot);
  127. while (slotOccMask)
  128. {
  129. AkUInt32 slotSubIdx = AKPLATFORM::AkBitScanReverse64(slotOccMask);
  130. in_func(uBaseSlot + 7 - (slotSubIdx / 8));
  131. slotOccMask ^= (0x8000000000000000ULL >> slotSubIdx);
  132. }
  133. }
  134. }
  135. } // namespace HashTable
  136. } // namespace AK