IAkPluginHashTable.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. /*******************************************************************************
  2. The content of this file includes portions of the AUDIOKINETIC Wwise Technology
  3. released in source code form as part of the SDK installer package.
  4. Commercial License Usage
  5. Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
  6. may use this file in accordance with the end user license agreement provided
  7. with the software or, alternatively, in accordance with the terms contained in a
  8. written agreement between you and Audiokinetic Inc.
  9. Apache License Usage
  10. Alternatively, this file may be used under the Apache License, Version 2.0 (the
  11. "Apache License"); you may not use this file except in compliance with the
  12. Apache License. You may obtain a copy of the Apache License at
  13. http://www.apache.org/licenses/LICENSE-2.0.
  14. Unless required by applicable law or agreed to in writing, software distributed
  15. under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
  16. OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
  17. the specific language governing permissions and limitations under the License.
  18. Copyright (c) 2023 Audiokinetic Inc.
  19. *******************************************************************************/
  20. /// \file
  21. /// Plug-in interface for HashTable
  22. #pragma once
  23. #include <AK/SoundEngine/Common/AkHashTableTypes.h>
  24. #include <AK/SoundEngine/Common/AkHashTableFuncs.h>
  25. #include <AK/SoundEngine/Common/IAkPlugin.h>
  26. #include <AK/Tools/Common/AkMurMurHash.h>
  27. namespace AK
  28. {
  29. /// Interface for an open-addressed hash table (or key-value array).
  30. /// Relatively low-cost (O(1)) lookup, add, and removal by key. Typical use is to add values by key,
  31. /// and then using GetFirstSlotByKey (and GetNextSlotByKey, if keys are not guaranteed to be unique)
  32. /// to get a Slot into the AkHashTableBase, and then indexing AkHashTableBase::pValues by the provided Slot.
  33. ///
  34. /// Note that the AkHashTableBase referred to is not inherently thread-safe, so appropriate protections
  35. /// will be required if the same hashTable is shared across multiple plug-in instances.
  36. ///
  37. /// Some hash functions are provided in AkMurMurHash.h which can be used for key generation.
  38. /// In particular, this can be very useful for storing data on audio objects, or audio object channels,
  39. /// over time. Note that if indexing by object-channel is desired, GetObjectChannelHash is recommended
  40. /// to mitigate key-collisions from multiple channels of data. However, Audio Object IDs themselves are
  41. /// chaotic enough that they can be used directly.
  42. class IAkPluginServiceHashTable : public IAkPluginService
  43. {
  44. protected:
  45. virtual ~IAkPluginServiceHashTable() {}
  46. public:
  47. // initializes and preallocates storage for specified number of entries
  48. //
  49. // returns either:
  50. // AK_InsufficientMemory if a required allocation could not be made
  51. // AK_Success if the hash table was initialized successfully
  52. virtual AKRESULT InitBase(AK::AkHashTableBase<AkUInt64>* io_pHashTable, AK::IAkPluginMemAlloc* in_pAllocator, AkUInt32 in_uInitialReserveCount, AkUInt32
  53. in_uValueElementSize, AkUInt32 in_uValueElementAlign) = 0;
  54. // helper function for initialization of the hashtable against a specific value type
  55. template<typename ValueType>
  56. AkForceInline AKRESULT Init(AkHashTable<AkUInt64, ValueType>* io_pHashTable, AK::IAkPluginMemAlloc* in_pAllocator, AkUInt32 in_uInitialReserveCount)
  57. {
  58. return InitBase(io_pHashTable, in_pAllocator, in_uInitialReserveCount, sizeof(ValueType), alignof(ValueType));
  59. }
  60. // frees memory allocated for entries
  61. virtual void Term(AK::AkHashTableBase<AkUInt64>* io_pHashTable, AK::IAkPluginMemAlloc* in_pAllocator) = 0;
  62. // resets the table, clearing all keys and values to zero, but leaving the memory allocated
  63. virtual void Reset(AK::AkHashTableBase<AkUInt64>* io_pHashTable) = 0;
  64. // adds the provided key to the hash table
  65. // note that a key can be added to the table multiple times
  66. // and returns a pointer to the value made available, or nullptr if a grow occurred but memory could not be provided
  67. // Note that this can move many entries in the table around, so previous pointers to elements, etc, should be considered invalidated
  68. virtual void* AddKey(AK::AkHashTableBase<AkUInt64>* io_pHashTable, AK::IAkPluginMemAlloc* in_pAllocator, AkUInt64 in_uKey) = 0;
  69. // adds this key to the hash table, and inserts the provided value to the newly reserved space,
  70. // note that a key can be added to the table multiple times
  71. // returns a pointer to the value made available, or nullptr if a grow occurred but memory could not be provided
  72. // Note that this can move many entries in the table around, so previous pointers to elements, etc, should be considered invalidated.
  73. template<typename ValueType>
  74. AkForceInline ValueType* AddKeyValue(AkHashTable<AkUInt64, ValueType>* io_pHashTable, AK::IAkPluginMemAlloc* in_pAllocator, AkUInt64 in_uKey, ValueType* in_pNewValue)
  75. {
  76. if (ValueType* pInsertedValue = (ValueType*)AddKey(io_pHashTable, in_pAllocator, in_uKey))
  77. {
  78. AKASSERT(sizeof(ValueType) == io_pHashTable->uValueElementSize);
  79. AKPLATFORM::AkMemCpy(pInsertedValue, in_pNewValue, sizeof(ValueType));
  80. return pInsertedValue;
  81. }
  82. return nullptr;
  83. }
  84. // removes the entry at the slot provided
  85. // Note that this can move many entries in the table around, so previous pointers to elements, etc, should be considered invalidated
  86. // Returns true when a move of data around the end of the list occurred, e.g. in case iteration over the table needs to be modified
  87. virtual bool RemoveSlot(AK::AkHashTableBase<AkUInt64>* io_pHashTable, AkInt32 in_iSlot) = 0;
  88. // finds a slot with the provided key and deletes it from the table
  89. // Note that this can move many entries in the table around, so previous pointers to elements, etc, should be considered invalidated
  90. virtual void RemoveKey(AK::AkHashTableBase<AkUInt64>* io_pHashTable, AkUInt64 in_uKey) = 0;
  91. // returns either:
  92. // the slot of the first valid entry that in_uKey maps to
  93. // -1 if there are no valid entries at the table that uKey maps to
  94. static AkInt32 GetFirstSlotByKey(AK::AkHashTableBase<AkUInt64>* in_pHashTable, AkUInt64 in_uKey) {
  95. return AK::HashTable::GetFirstSlotForKey(in_pHashTable, in_uKey);
  96. }
  97. // returns either:
  98. // the next slot after iPreviousSlot which contains a valid entry
  99. // -1 if the next slot after iPreviousSlot doesn't contain a valid entry
  100. static AkInt32 GetNextSlotByKey(AK::AkHashTableBase<AkUInt64>* in_pHashTable, AkUInt64 in_uKey, AkInt32 in_iPreviousSlot) {
  101. return AK::HashTable::GetNextSlotForKey(in_pHashTable, in_uKey, in_iPreviousSlot);
  102. }
  103. // runs the provided function over every active slot in the hashtable, which is used to determine if the element should be removed
  104. // Note that this can move many entries in the table around, so previous pointers to elements, etc, should be considered invalidated
  105. // bool functype(AkUInt32 in_slot)
  106. template<typename KeyType, typename FuncType>
  107. void RemoveIf(AkHashTableBase<KeyType>* in_pHashTable, FuncType in_func)
  108. {
  109. AkUInt32 uNumReservedEntries = in_pHashTable->uNumReservedEntries;
  110. bool* pbSlotOccupied = in_pHashTable->pbSlotOccupied;
  111. AkUInt32 uSlot = 0;
  112. while (uSlot < uNumReservedEntries)
  113. {
  114. if (pbSlotOccupied[uSlot] && in_func(uSlot))
  115. {
  116. // if slot is occupied, and the function confirmed removal, remove this slot, but don't advance uSlot
  117. RemoveSlot(in_pHashTable, (AkInt32)uSlot);
  118. }
  119. else
  120. {
  121. uSlot++;
  122. }
  123. }
  124. }
  125. };
  126. #define AK_GET_PLUGIN_SERVICE_HASHTABLE(plugin_ctx) static_cast<AK::IAkPluginServiceHashTable*>(plugin_ctx->GetPluginService(AK::PluginServiceType_HashTable))
  127. /// A common hashtable for mapping audioobjectIds to a combination of audio buffers and objects
  128. struct AkAudioObjectBuffer
  129. {
  130. AkAudioObjectBuffer() : pMetadata(nullptr) {}
  131. AkAudioBuffer pBuffer;
  132. AkAudioObject* pMetadata;
  133. };
  134. typedef AK::AkHashTable<AkAudioObjectID, AkAudioObjectBuffer> AkAudioObjectBufferMap;
  135. /// Common hash function for getting a unique hash for a channel on an audio object
  136. AkForceInline AkUInt64 GetObjectChannelHash(AkUInt64 in_uAudioObjectId, AkUInt32 in_uChannelIdx)
  137. {
  138. return AkHashMurMurMix64(((AkUInt64)in_uChannelIdx << AkAudioObject::kObjectKeyNumBits) | (in_uAudioObjectId & AkAudioObject::kObjectKeyMask));
  139. }
  140. } // namespace AK