123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- #ifndef _AKPOOLALLOCATOR_H
- #define _AKPOOLALLOCATOR_H
- #include <AK/Tools/Common/AkObject.h>
- #include <AK/Tools/Common/AkAssert.h>
- #include <AK/Tools/Common/AkArray.h>
- #define AK_OBJECT_POOL_EXTRA_SAFETY
- namespace UnitTest { struct ObjectPoolHelper; }
- namespace AK
- {
- template<AkMemID T_MEMID = AkMemID_Object>
- using ObjectPoolDefaultAllocator = AkArrayAllocatorNoAlign<T_MEMID>;
- struct ObjectPoolNoLock
- {
- inline static constexpr void Lock() {}
- inline static constexpr void Unlock() {}
- };
- using ObjectPoolDefaultLockType = ObjectPoolNoLock;
-
- template<
- typename T,
- typename AllocatorType = ObjectPoolDefaultAllocator<>,
- typename LockType = ObjectPoolDefaultLockType>
- class ObjectPool : AllocatorType, LockType
- {
- public:
- using ValueType = T;
- using SizeType = AkUInt32;
- static constexpr SizeType kInvalidIndex = (SizeType)-1;
- union DataType
- {
- inline ValueType& Data() { return *(ValueType*)data; }
- inline const ValueType& Data() const { return *(const ValueType*)data; }
- alignas(ValueType) uint8_t data[sizeof(ValueType)];
- SizeType next;
- };
- using AllocatorType::AllocatorType;
- ObjectPool() = default;
- ObjectPool(const ObjectPool&) = delete;
- ObjectPool(ObjectPool&&) = delete;
- inline ~ObjectPool() { AKASSERT(!m_data); }
- ObjectPool& operator=(const ObjectPool&) = delete;
- ObjectPool& operator=(ObjectPool&&) = delete;
- inline AKRESULT Init(SizeType count)
- {
- AKASSERT(!m_data && "ObjectPool is already initialized, call 'Term' before calling 'Init' again");
- AKASSERT(count && "ObjectPool count must be greater than zero");
- AKASSERT(count < kInvalidIndex && "ObjectPool count is above SizeType's maximum capacity");
- if (m_data || !count)
- return AK_InvalidParameter;
- m_data = reinterpret_cast<DataType*>(AllocatorType::Alloc(count * sizeof(DataType)));
- m_capacity = 0;
- m_size = 0;
- m_freeList = 0;
- if (!m_data)
- return AK_InsufficientMemory;
- m_capacity = count;
- for (SizeType i = 0; i < m_capacity - 1; i++)
- m_data[i].next = i + 1;
- m_data[m_capacity - 1].next = kInvalidIndex;
- return AK_Success;
- }
- inline void Term()
- {
-
- AKASSERT(m_size == 0 && "Can't call Term() when some objects are still allocated");
- if (!m_data)
- return;
- AllocatorType::Free(m_data);
- m_data = nullptr;
- m_capacity = 0;
- m_size = 0;
- m_freeList = 0;
- }
- AK_NODISCARD inline SizeType Size() const { return m_size; }
- AK_NODISCARD inline SizeType Capacity() const { return m_capacity; }
- AK_NODISCARD inline bool IsFull() const { return m_size >= m_capacity; }
- AK_NODISCARD inline bool IsEmpty() const { return m_size == 0; }
-
-
-
- AK_NODISCARD inline ValueType* Allocate()
- {
- if (IsFull())
- return nullptr;
- LockType::Lock();
- DataType& data = m_data[m_freeList];
- m_freeList = data.next;
- m_size++;
- LockType::Unlock();
- return &data.Data();
- }
-
- AK_NODISCARD inline ValueType* AllocateZeroFilled()
- {
- ValueType* value = Allocate();
- if (value)
- AKPLATFORM::AkMemSet((void*)value, 0, (AkUInt32)sizeof(ValueType));
- return value;
- }
-
-
-
-
-
-
- inline AKRESULT Deallocate(ValueType* data)
- {
- AKASSERT(data && "Deallocating null data");
- DataType* tdata = reinterpret_cast<DataType*>(data);
-
- AKASSERT((tdata >= m_data && tdata < m_data + m_capacity) && "Pointer address out of range");
- if (tdata < m_data || tdata >= m_data + m_capacity)
- return AK_InvalidParameter;
- LockType::Lock();
- AKASSERT(m_size && "Trying to deallocate when empty");
- #ifdef AK_OBJECT_POOL_EXTRA_SAFETY
- AKASSERT(IsAllocated((SizeType)(tdata - m_data)));
- #endif
- m_size--;
- tdata->next = m_freeList;
- m_freeList = (SizeType)(tdata - m_data);
- LockType::Unlock();
- return AK_Success;
- }
-
-
- inline void Clear()
- {
- for (SizeType i = 0; i < m_capacity - 1; i++)
- m_data[i].next = i + 1;
- m_data[m_capacity - 1].next = kInvalidIndex;
- m_size = 0;
- m_freeList = 0;
- }
- private:
- DataType* m_data = nullptr;
- SizeType m_capacity = 0;
- SizeType m_size = 0;
- SizeType m_freeList = 0;
- friend struct UnitTest::ObjectPoolHelper;
- inline bool IsAllocated(SizeType index) const
- {
- for (SizeType k = m_freeList; k != kInvalidIndex; k = m_data[k].next)
- if (index == k)
- return false;
- return true;
- }
- };
- }
- #endif
|