// Copyright Epic Games, Inc. All Rights Reserved. #pragma once #if (defined(__AUTORTFM) && __AUTORTFM) #include "BlockAllocator.h" #include #include namespace AutoRTFM { template class TIntrusivePool final { public: using FItem = ItemType; TIntrusivePool() = default; ~TIntrusivePool() { while (FItem* const Item = FreeList) { FreeList = *Item->GetIntrusiveAddress(); Item->~FItem(); } } // Acquires a new Item from the pool. If the item was previously returned // to the pool, we'll call `Resurrect` on it with `Arguments`. Otherwise // create a new item with `Arguments`. template FItem* Take(ArgumentTypes&& ... Arguments) { FItem* Item = nullptr; if (FreeList) { // Unlink a free entry from the free list. Item = FreeList; FreeList = *(FreeList->GetIntrusiveAddress()); Item->Resurrect(std::forward(Arguments)...); } else { // Free list is empty. Allocate another item. void* const Memory = Allocator.Allocate(EntrySize, EntryAlignment); NumAllocated++; Item = new (Memory) FItem(std::forward(Arguments)...); } AUTORTFM_ASSERT(NumInUse < NumAllocated); NumInUse++; return Item; } // Calls `Suppress` on `Item` and returns it to the pool to be reused. void Return(FItem* const Item) { // Suppress the item. Item->Suppress(); // Place the entry onto the free list. *Item->GetIntrusiveAddress() = FreeList; FreeList = Item; AUTORTFM_ASSERT(NumInUse > 0); NumInUse--; } private: static constexpr size_t EntrySize = sizeof(FItem); static constexpr size_t EntryAlignment = alignof(FItem); // The underlying allocator for the pool. TBlockAllocator Allocator; // Free list. FItem* FreeList = nullptr; // Number of entries allocated. size_t NumAllocated = 0; // Number of entries currently in use. size_t NumInUse = 0; TIntrusivePool(TIntrusivePool&&) = delete; TIntrusivePool(const TIntrusivePool&) = delete; TIntrusivePool& operator=(const TIntrusivePool&) = delete; TIntrusivePool& operator=(TIntrusivePool&&) = delete; }; } // namespace AutoRTFM #endif // (defined(__AUTORTFM) && __AUTORTFM)