/* * Copyright 2019-2021 Diligent Graphics LLC * Copyright 2015-2019 Egor Yusov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * * In no event and under no legal theory, whether in tort (including negligence), * contract, or otherwise, unless required by applicable law (such as deliberate * and grossly negligent acts) or agreed to in writing, shall any Contributor be * liable for any damages, including any direct, indirect, special, incidental, * or consequential damages of any character arising as a result of this License or * out of the use or inability to use the software (including but not limited to damages * for loss of goodwill, work stoppage, computer failure or malfunction, or any and * all other commercial damages or losses), even if such Contributor has been advised * of the possibility of such damages. */ #pragma once /// \file /// Defines Diligent::DynamicLinearAllocator class #include #include "../../Primitives/interface/BasicTypes.h" #include "../../Primitives/interface/MemoryAllocator.h" #include "../../Platforms/Basic/interface/DebugUtilities.hpp" #include "CompilerDefinitions.h" #include "Align.hpp" namespace Diligent { /// Implementation of a linear allocator on fixed memory pages class DynamicLinearAllocator { public: // clang-format off DynamicLinearAllocator (const DynamicLinearAllocator&) = delete; DynamicLinearAllocator (DynamicLinearAllocator&&) = delete; DynamicLinearAllocator& operator=(const DynamicLinearAllocator&) = delete; DynamicLinearAllocator& operator=(DynamicLinearAllocator&&) = delete; // clang-format on explicit DynamicLinearAllocator(IMemoryAllocator& Allocator, Uint32 BlockSize = 4 << 10) : m_pAllocator{&Allocator}, m_BlockSize{BlockSize} { VERIFY(IsPowerOfTwo(BlockSize), "Block size (", BlockSize, ") is not power of two"); } ~DynamicLinearAllocator() { Free(); } void Free() { for (auto& block : m_Blocks) { m_pAllocator->Free(block.Data); } m_Blocks.clear(); m_pAllocator = nullptr; } void Discard() { for (auto& block : m_Blocks) { block.CurrPtr = block.Data; } } NODISCARD void* Allocate(size_t size, size_t align) { if (size == 0) return nullptr; for (auto& block : m_Blocks) { auto* Ptr = AlignUp(block.CurrPtr, align); if (Ptr + size <= block.Data + block.Size) { block.CurrPtr = Ptr + size; return Ptr; } } // Create a new block size_t BlockSize = m_BlockSize; while (BlockSize < size + align - 1) BlockSize *= 2; m_Blocks.emplace_back(m_pAllocator->Allocate(BlockSize, "dynamic linear allocator page", __FILE__, __LINE__), BlockSize); auto& block = m_Blocks.back(); auto* Ptr = AlignUp(block.Data, align); VERIFY(Ptr + size <= block.Data + block.Size, "Not enough space in the new block - this is a bug"); block.CurrPtr = Ptr + size; return Ptr; } template NODISCARD T* Allocate(size_t count = 1) { return reinterpret_cast(Allocate(sizeof(T) * count, alignof(T))); } template NODISCARD T* Construct(Args&&... args) { T* Ptr = Allocate(1); new (Ptr) T{std::forward(args)...}; return Ptr; } template NODISCARD T* ConstructArray(size_t count, const Args&... args) { T* Ptr = Allocate(count); for (size_t i = 0; i < count; ++i) { new (Ptr + i) T{args...}; } return Ptr; } template NODISCARD T* CopyArray(const T* Src, size_t count) { T* Dst = Allocate(count); for (size_t i = 0; i < count; ++i) { new (Dst + i) T{Src[i]}; } return Dst; } NODISCARD Char* CopyString(const Char* Str, size_t len = 0) { if (Str == nullptr) return nullptr; if (len == 0) len = strlen(Str); else VERIFY_EXPR(len <= strlen(Str)); Char* Dst = Allocate(len + 1); std::memcpy(Dst, Str, sizeof(Char) * len); Dst[len] = 0; return Dst; } NODISCARD wchar_t* CopyWString(const char* Str, size_t len = 0) { if (Str == nullptr) return nullptr; if (len == 0) len = strlen(Str); else VERIFY_EXPR(len <= strlen(Str)); auto* Dst = Allocate(len + 1); for (size_t i = 0; i < len; ++i) { Dst[i] = static_cast(Str[i]); } Dst[len] = 0; return Dst; } NODISCARD Char* CopyString(const String& Str) { return CopyString(Str.c_str(), Str.length()); } NODISCARD wchar_t* CopyWString(const String& Str) { return CopyWString(Str.c_str(), Str.length()); } private: struct Block { uint8_t* const Data = nullptr; size_t const Size = 0; uint8_t* CurrPtr = nullptr; Block(void* _Data, size_t _Size) : Data{static_cast(_Data)}, Size{_Size}, CurrPtr{Data} {} }; std::vector m_Blocks; const Uint32 m_BlockSize = 4 << 10; IMemoryAllocator* m_pAllocator = nullptr; }; } // namespace Diligent