Version
menu

Wwise SDK 2025.1.3
AkObjectPool.h
Go to the documentation of this file.
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 
5 Commercial License Usage
6 
7 Licensees holding valid commercial licenses to the AUDIOKINETIC Wwise Technology
8 may use this file in accordance with the end user license agreement provided
9 with the software or, alternatively, in accordance with the terms contained in a
10 written agreement between you and Audiokinetic Inc.
11 
12 Apache License Usage
13 
14 Alternatively, this file may be used under the Apache License, Version 2.0 (the
15 "Apache License"); you may not use this file except in compliance with the
16 Apache License. You may obtain a copy of the Apache License at
17 http://www.apache.org/licenses/LICENSE-2.0.
18 
19 Unless required by applicable law or agreed to in writing, software distributed
20 under the Apache License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
21 OR CONDITIONS OF ANY KIND, either express or implied. See the Apache License for
22 the specific language governing permissions and limitations under the License.
23 
24  Copyright (c) 2025 Audiokinetic Inc.
25 *******************************************************************************/
26 
27 #ifndef _AKPOOLALLOCATOR_H
28 #define _AKPOOLALLOCATOR_H
29 
33 
34 /// Extra debug option when calling ObjectPool::Deallocate.
35 /// Going through the free list can be slow when the object count is high.
36 #define AK_OBJECT_POOL_EXTRA_SAFETY
37 
38 /// \cond DOXYGEN_SKIP
39 namespace UnitTest { struct ObjectPoolHelper; }
40 /// \endcond
41 
42 namespace AK
43 {
44  template<AkMemID T_MEMID = AkMemID_Object>
46 
48  {
49  inline static constexpr void Lock() {}
50  inline static constexpr void Unlock() {}
51  };
52 
54 
55  /// An object pool of N reusable objects with one allocation.
56  template<
57  typename T,
58  typename AllocatorType = ObjectPoolDefaultAllocator<>,
59  typename LockType = ObjectPoolDefaultLockType>
60  class ObjectPool : AllocatorType, LockType
61  {
62  public:
63  using ValueType = T;
64  using SizeType = AkUInt32;
65  static constexpr SizeType kInvalidIndex = (SizeType)-1;
66 
67  union DataType
68  {
69  inline ValueType& Data() { return *(ValueType*)data; }
70  inline const ValueType& Data() const { return *(const ValueType*)data; }
71  alignas(ValueType) uint8_t data[sizeof(ValueType)];
73  };
74 
75  using AllocatorType::AllocatorType;
76 
77  ObjectPool() = default;
78  ObjectPool(const ObjectPool&) = delete;
79  ObjectPool(ObjectPool&&) = delete;
80 
81  inline ~ObjectPool() { AKASSERT(!m_data); }
82 
83  ObjectPool& operator=(const ObjectPool&) = delete;
85 
86  inline AKRESULT Init(SizeType count)
87  {
88  AKASSERT(!m_data && "ObjectPool is already initialized, call 'Term' before calling 'Init' again");
89  AKASSERT(count && "ObjectPool count must be greater than zero");
90  AKASSERT(count < kInvalidIndex && "ObjectPool count is above SizeType's maximum capacity");
91 
92  if (m_data || !count)
93  return AK_InvalidParameter;
94 
95  m_data = reinterpret_cast<DataType*>(AllocatorType::Alloc(count * sizeof(DataType)));
96  m_capacity = 0;
97  m_size = 0;
98  m_freeList = 0;
99 
100  if (!m_data)
101  return AK_InsufficientMemory;
102 
103  m_capacity = count;
104 
105  for (SizeType i = 0; i < m_capacity - 1; i++)
106  m_data[i].next = i + 1;
107 
108  m_data[m_capacity - 1].next = kInvalidIndex;
109 
110  return AK_Success;
111  }
112 
113  inline void Term()
114  {
115  // Only assert when some object are still allocated and ValueType is not trivially destructible.
116  AKASSERT(m_size == 0 && "Can't call Term() when some objects are still allocated");
117 
118  if (!m_data)
119  return;
120 
121  AllocatorType::Free(m_data);
122  m_data = nullptr;
123  m_capacity = 0;
124  m_size = 0;
125  m_freeList = 0;
126  }
127 
128  AK_NODISCARD inline SizeType Size() const { return m_size; }
129  AK_NODISCARD inline SizeType Capacity() const { return m_capacity; }
130 
131  AK_NODISCARD inline bool IsFull() const { return m_size >= m_capacity; }
132  AK_NODISCARD inline bool IsEmpty() const { return m_size == 0; }
133 
134  /// Allocates a new object.
135  /// @returns the object on success or nullptr if it fails (already full).
136  /// @{
138  {
139  if (IsFull())
140  return nullptr;
141 
142  LockType::Lock();
143  DataType& data = m_data[m_freeList];
144  m_freeList = data.next;
145  m_size++;
146  LockType::Unlock();
147  return &data.Data();
148  }
149 
150  /// Initialize memory before returning.
152  {
153  ValueType* value = Allocate();
154  if (value)
155  AKPLATFORM::AkMemSet((void*)value, 0, (AkUInt32)sizeof(ValueType));
156 
157  return value;
158  }
159  /// @}
160 
161  /// Deallocates given pointer.
162  /// Calling Deallocate when IsEmpty() returns true is undefined behaviour.
163  /// Calling Deallocate with a pointer that wasn't allocated by this pool is undefined behaviour.
164  ///
165  /// You can define AK_OBJECT_POOL_EXTRA_SAFETY for extra debugging check.
167  {
168  AKASSERT(data && "Deallocating null data");
169  DataType* tdata = reinterpret_cast<DataType*>(data);
170 
171  // Check if data is in memory range.
172  AKASSERT((tdata >= m_data && tdata < m_data + m_capacity) && "Pointer address out of range");
173  if (tdata < m_data || tdata >= m_data + m_capacity)
174  return AK_InvalidParameter;
175 
176  LockType::Lock();
177  AKASSERT(m_size && "Trying to deallocate when empty");
178 
179 #ifdef AK_OBJECT_POOL_EXTRA_SAFETY
180  AKASSERT(IsAllocated((SizeType)(tdata - m_data)));
181 #endif
182  m_size--;
183  tdata->next = m_freeList;
184  m_freeList = (SizeType)(tdata - m_data);
185  LockType::Unlock();
186 
187  return AK_Success;
188  }
189 
190  /// Deallocates all objects.
191  /// This function should only be called if ValueType is trivially destructible.
192  inline void Clear()
193  {
194  for (SizeType i = 0; i < m_capacity - 1; i++)
195  m_data[i].next = i + 1;
196 
197  m_data[m_capacity - 1].next = kInvalidIndex;
198  m_size = 0;
199  m_freeList = 0;
200  }
201 
202  private:
203  DataType* m_data = nullptr;
204  SizeType m_capacity = 0;
205  SizeType m_size = 0;
206  SizeType m_freeList = 0;
207 
209 
210  inline bool IsAllocated(SizeType index) const
211  {
212  for (SizeType k = m_freeList; k != kInvalidIndex; k = m_data[k].next)
213  if (index == k)
214  return false;
215 
216  return true;
217  }
218  };
219 } // namespace AK
220 #endif
Definition of data structures for AkAudioObject.
static constexpr SizeType kInvalidIndex
Definition: AkObjectPool.h:65
static constexpr void Unlock()
Definition: AkObjectPool.h:50
AKSOUNDENGINE_API void Free(AkMemPoolId in_poolId, void *in_pMemAddress)
AK_NODISCARD ValueType * AllocateZeroFilled()
Initialize memory before returning.
Definition: AkObjectPool.h:151
ObjectPool()=default
AK_NODISCARD bool IsFull() const
Definition: AkObjectPool.h:131
AKRESULT Init(SizeType count)
Definition: AkObjectPool.h:86
ObjectPool(ObjectPool &&)=delete
#define AK_NODISCARD
Definition: AkPlatforms.h:149
AK_NODISCARD bool IsEmpty() const
Definition: AkObjectPool.h:132
uint8_t data[sizeof(ValueType)]
Definition: AkObjectPool.h:71
friend struct UnitTest::ObjectPoolHelper
Definition: AkObjectPool.h:208
#define AKASSERT(Condition)
Definition: AkAssert.h:69
AK_NODISCARD ValueType * Allocate()
Definition: AkObjectPool.h:137
@ AK_InsufficientMemory
Memory error.
Definition: AkEnums.h:62
AKRESULT Deallocate(ValueType *data)
Definition: AkObjectPool.h:166
AK_NODISCARD SizeType Size() const
Definition: AkObjectPool.h:128
ObjectPool(const ObjectPool &)=delete
AK_NODISCARD SizeType Capacity() const
Definition: AkObjectPool.h:129
ObjectPool & operator=(const ObjectPool &)=delete
AKRESULT
Definition: AkEnums.h:32
ObjectPool & operator=(ObjectPool &&)=delete
An object pool of N reusable objects with one allocation.
Definition: AkObjectPool.h:61
@ AK_InvalidParameter
Something is not within bounds, check the documentation of the function returning this code.
Definition: AkEnums.h:50
uint32_t AkUInt32
Unsigned 32-bit integer.
AkUInt32 SizeType
Definition: AkObjectPool.h:64
static constexpr void Lock()
Definition: AkObjectPool.h:49
@ AK_Success
The operation was successful.
Definition: AkEnums.h:34
AkForceInline void AkMemSet(void *pDest, AkInt32 iVal, AkUInt32 uSize)
const ValueType & Data() const
Definition: AkObjectPool.h:70

Cette page a-t-elle été utile ?

Besoin d'aide ?

Des questions ? Des problèmes ? Besoin de plus d'informations ? Contactez-nous, nous pouvons vous aider !

Visitez notre page d'Aide

Décrivez-nous de votre projet. Nous sommes là pour vous aider.

Enregistrez votre projet et nous vous aiderons à démarrer sans aucune obligation !

Partir du bon pied avec Wwise