// Copyright (c) Wojciech Figat. All rights reserved. #pragma once #include "Allocation.h" /// /// Allocator that uses pages for stack-based allocs without freeing memory during it's lifetime. /// class ArenaAllocator { private: struct Page { void* Memory; Page* Next; uint32 Offset, Size; }; int32 _pageSize; Page* _first = nullptr; public: ArenaAllocator(int32 pageSizeBytes = 1024 * 1024) // 1 MB by default : _pageSize(pageSizeBytes) { } ~ArenaAllocator() { Free(); } // Allocates a chunk of unitialized memory. void* Allocate(uint64 size, uint64 alignment = 1); // Frees all memory allocations within allocator. void Free(); // Creates a new object within the arena allocator. template inline T* New(Args&&...args) { T* ptr = (T*)Allocate(sizeof(T)); new(ptr) T(Forward(args)...); return ptr; } // Invokes destructor on values in an array and clears it. template static void ClearDelete(Array& collection) { Value* ptr = collection.Get(); for (int32 i = 0; i < collection.Count(); i++) Memory::DestructItem(ptr[i]); collection.Clear(); } // Invokes destructor on values in a dictionary and clears it. template static void ClearDelete(Dictionary& collection) { for (auto it = collection.Begin(); it.IsNotEnd(); ++it) Memory::DestructItem(it->Value); collection.Clear(); } }; /// /// The memory allocation policy that uses a part of shared page allocator. Allocations are performed in stack-manner, and free is no-op. /// class ArenaAllocation { public: enum { HasSwap = true }; typedef ArenaAllocator* Tag; template class Data { private: T* _data = nullptr; ArenaAllocator* _arena = nullptr; public: FORCE_INLINE Data() { } FORCE_INLINE Data(Tag tag) { _arena = tag; } FORCE_INLINE ~Data() { } FORCE_INLINE T* Get() { return _data; } FORCE_INLINE const T* Get() const { return _data; } FORCE_INLINE int32 CalculateCapacityGrow(int32 capacity, const int32 minCapacity) const { return AllocationUtils::CalculateCapacityGrow(capacity, minCapacity); } FORCE_INLINE void Allocate(const int32 capacity) { ASSERT_LOW_LAYER(!_data && _arena); _data = (T*)_arena->Allocate(capacity * sizeof(T), alignof(T)); } FORCE_INLINE void Relocate(const int32 capacity, int32 oldCount, int32 newCount) { ASSERT_LOW_LAYER(_arena); T* newData = capacity != 0 ? (T*)_arena->Allocate(capacity * sizeof(T), alignof(T)) : nullptr; if (oldCount) { if (newCount > 0) Memory::MoveItems(newData, _data, newCount); Memory::DestructItems(_data, oldCount); } _data = newData; } FORCE_INLINE void Free() { _data = nullptr; } FORCE_INLINE void Swap(Data& other) { ::Swap(_data, other._data); ::Swap(_arena, other._arena); } }; };