Version
menu_open
link
Wwise SDK 2022.1.11
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) 2024 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 namespace UnitTest { struct ObjectPoolHelper; }
39 
40 namespace AK
41 {
42  template<AkMemID T_MEMID = AkMemID_Object>
44 
46  {
47  inline static constexpr void Lock() {}
48  inline static constexpr void Unlock() {}
49  };
50 
52 
53  /// An object pool of N reusable objects with one allocation.
54  template<
55  typename T,
56  typename AllocatorType = ObjectPoolDefaultAllocator<>,
57  typename LockType = ObjectPoolDefaultLockType>
58  class ObjectPool : AllocatorType, LockType
59  {
60  public:
61  using ValueType = T;
62  using SizeType = AkUInt32;
63  static constexpr SizeType kInvalidIndex = (SizeType)-1;
64 
65  union DataType
66  {
67  inline ValueType& Data() { return *(ValueType*)data; }
68  inline const ValueType& Data() const { return *(const ValueType*)data; }
69  alignas(ValueType) uint8_t data[sizeof(ValueType)];
71  };
72 
73  using AllocatorType::AllocatorType;
74 
75  ObjectPool() = default;
76  ObjectPool(const ObjectPool&) = delete;
77  ObjectPool(ObjectPool&&) = delete;
78 
79  inline ~ObjectPool() { AKASSERT(!m_data); }
80 
81  ObjectPool& operator=(const ObjectPool&) = delete;
83 
84  inline AKRESULT Init(SizeType count)
85  {
86  AKASSERT(!m_data && "ObjectPool is already initialized, call 'Term' before calling 'Init' again");
87  AKASSERT(count && "ObjectPool count must be greater than zero");
88  AKASSERT(count < kInvalidIndex && "ObjectPool count is above SizeType's maximum capacity");
89 
90  if (m_data || !count)
91  return AK_InvalidParameter;
92 
93  m_data = reinterpret_cast<DataType*>(AllocatorType::Alloc(count * sizeof(DataType)));
94  m_capacity = 0;
95  m_size = 0;
96  m_freeList = 0;
97 
98  if (!m_data)
99  return AK_InsufficientMemory;
100 
101  m_capacity = count;
102 
103  for (SizeType i = 0; i < m_capacity - 1; i++)
104  m_data[i].next = i + 1;
105 
106  m_data[m_capacity - 1].next = kInvalidIndex;
107 
108  return AK_Success;
109  }
110 
111  inline void Term()
112  {
113  // Only assert when some object are still allocated and ValueType is not trivially destructible.
114  AKASSERT(m_size == 0 && "Can't call Term() when some objects are still allocated");
115 
116  if (!m_data)
117  return;
118 
119  AllocatorType::Free(m_data);
120  m_data = nullptr;
121  m_capacity = 0;
122  m_size = 0;
123  m_freeList = 0;
124  }
125 
126  AK_NODISCARD inline SizeType Size() const { return m_size; }
127  AK_NODISCARD inline SizeType Capacity() const { return m_capacity; }
128 
129  AK_NODISCARD inline bool IsFull() const { return m_size >= m_capacity; }
130  AK_NODISCARD inline bool IsEmpty() const { return m_size == 0; }
131 
132  /// Allocates a new object.
133  /// @returns the object on success or nullptr if it fails (already full).
134  /// @{
136  {
137  if (IsFull())
138  return nullptr;
139 
140  LockType::Lock();
141  DataType& data = m_data[m_freeList];
142  m_freeList = data.next;
143  m_size++;
144  LockType::Unlock();
145  return &data.Data();
146  }
147 
148  /// Initialize memory before returning.
150  {
151  ValueType* value = Allocate();
152  if (value)
153  AKPLATFORM::AkMemSet((void*)value, 0, (AkUInt32)sizeof(ValueType));
154 
155  return value;
156  }
157  /// @}
158 
159  /// Deallocates given pointer.
160  /// Calling Deallocate when IsEmpty() returns true is undefined behaviour.
161  /// Calling Deallocate with a pointer that wasn't allocated by this pool is undefined behaviour.
162  ///
163  /// You can define AK_OBJECT_POOL_EXTRA_SAFETY for extra debugging check.
165  {
166  AKASSERT(data && "Deallocating null data");
167  DataType* tdata = reinterpret_cast<DataType*>(data);
168 
169  // Check if data is in memory range.
170  AKASSERT((tdata >= m_data && tdata < m_data + m_capacity) && "Pointer address out of range");
171  if (tdata < m_data || tdata >= m_data + m_capacity)
172  return AK_InvalidParameter;
173 
174  LockType::Lock();
175  AKASSERT(m_size && "Trying to deallocate when empty");
176 
177 #ifdef AK_OBJECT_POOL_EXTRA_SAFETY
178  AKASSERT(IsAllocated((SizeType)(tdata - m_data)));
179 #endif
180  m_size--;
181  tdata->next = m_freeList;
182  m_freeList = (SizeType)(tdata - m_data);
183  LockType::Unlock();
184 
185  return AK_Success;
186  }
187 
188  /// Deallocates all objects.
189  /// This function should only be called if ValueType is trivially destructible.
190  inline void Clear()
191  {
192  for (SizeType i = 0; i < m_capacity - 1; i++)
193  m_data[i].next = i + 1;
194 
195  m_data[m_capacity - 1].next = kInvalidIndex;
196  m_size = 0;
197  m_freeList = 0;
198  }
199 
200  private:
201  DataType* m_data = nullptr;
202  SizeType m_capacity = 0;
203  SizeType m_size = 0;
204  SizeType m_freeList = 0;
205 
207 
208  inline bool IsAllocated(SizeType index) const
209  {
210  for (SizeType k = m_freeList; k != kInvalidIndex; k = m_data[k].next)
211  if (index == k)
212  return false;
213 
214  return true;
215  }
216  };
217 } // namespace AK
218 #endif
Audiokinetic namespace.
static constexpr SizeType kInvalidIndex
Definition: AkObjectPool.h:63
static constexpr void Unlock()
Definition: AkObjectPool.h:48
AKSOUNDENGINE_API void Free(AkMemPoolId in_poolId, void *in_pMemAddress)
AKRESULT
Standard function call result.
Definition: AkTypes.h:199
AK_NODISCARD ValueType * AllocateZeroFilled()
Initialize memory before returning.
Definition: AkObjectPool.h:149
ObjectPool()=default
AK_NODISCARD bool IsFull() const
Definition: AkObjectPool.h:129
AKRESULT Init(SizeType count)
Definition: AkObjectPool.h:84
@ AK_Success
The operation was successful.
Definition: AkTypes.h:201
ObjectPool(ObjectPool &&)=delete
@ AK_InvalidParameter
Something is not within bounds, check the documentation of the function returning this code.
Definition: AkTypes.h:217
AK_NODISCARD bool IsEmpty() const
Definition: AkObjectPool.h:130
uint8_t data[sizeof(ValueType)]
Definition: AkObjectPool.h:69
friend struct UnitTest::ObjectPoolHelper
Definition: AkObjectPool.h:206
#define AKASSERT(Condition)
Definition: AkAssert.h:67
AK_NODISCARD ValueType * Allocate()
Definition: AkObjectPool.h:135
AKRESULT Deallocate(ValueType *data)
Definition: AkObjectPool.h:164
AK_NODISCARD SizeType Size() const
Definition: AkObjectPool.h:126
ObjectPool(const ObjectPool &)=delete
AkForceInline void AkMemSet(void *pDest, AkInt32 iVal, AkUInt32 uSize)
Platform Independent Helper.
AK_NODISCARD SizeType Capacity() const
Definition: AkObjectPool.h:127
ObjectPool & operator=(const ObjectPool &)=delete
ObjectPool & operator=(ObjectPool &&)=delete
An object pool of N reusable objects with one allocation.
Definition: AkObjectPool.h:59
uint32_t AkUInt32
Unsigned 32-bit integer.
#define AK_NODISCARD
Definition: AkTypes.h:101
AkUInt32 SizeType
Definition: AkObjectPool.h:62
static constexpr void Lock()
Definition: AkObjectPool.h:47
@ AK_InsufficientMemory
Memory error.
Definition: AkTypes.h:229
const ValueType & Data() const
Definition: AkObjectPool.h:68

Was this page helpful?

Need Support?

Questions? Problems? Need more info? Contact us, and we can help!

Visit our Support page

Tell us about your project. We're here to help.

Register your project and we'll help you get started with no strings attached!

Get started with Wwise