/* * 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::DefaultRawMemoryAllocator class #include #include "../../Primitives/interface/BasicTypes.h" #include "../../Primitives/interface/MemoryAllocator.h" #include "../../Platforms/Basic/interface/DebugUtilities.hpp" namespace Diligent { template typename std::enable_if::value, void>::type Destruct(T* ptr) { ptr->~T(); } template typename std::enable_if::value, void>::type Destruct(T* ptr) { } template struct STDAllocator { using value_type = T; using pointer = value_type*; using const_pointer = const value_type*; using reference = value_type&; using const_reference = const value_type&; using size_type = std::size_t; using difference_type = std::ptrdiff_t; STDAllocator(AllocatorType& Allocator, const Char* Description, const Char* FileName, const Int32 LineNumber) noexcept : // clang-format off m_Allocator {Allocator} #ifdef DILIGENT_DEVELOPMENT , m_dvpDescription{Description} , m_dvpFileName {FileName } , m_dvpLineNumber {LineNumber } #endif // clang-format on { } template STDAllocator(const STDAllocator& other) noexcept : // clang-format off m_Allocator {other.m_Allocator} #ifdef DILIGENT_DEVELOPMENT , m_dvpDescription{other.m_dvpDescription} , m_dvpFileName {other.m_dvpFileName } , m_dvpLineNumber {other.m_dvpLineNumber } #endif // clang-format on { } template STDAllocator(STDAllocator&& other) noexcept : // clang-format off m_Allocator {other.m_Allocator} #ifdef DILIGENT_DEVELOPMENT , m_dvpDescription{other.m_dvpDescription} , m_dvpFileName {other.m_dvpFileName } , m_dvpLineNumber {other.m_dvpLineNumber } #endif // clang-format on { } template STDAllocator& operator=(STDAllocator&& other) noexcept { // Android build requires this operator to be defined - I have no idea why. // There is no default constructor to create null allocator, so all fields must be // initialized. DEV_CHECK_ERR(&m_Allocator == &other.m_Allocator, "Inconsistent allocators"); #ifdef DILIGENT_DEVELOPMENT DEV_CHECK_ERR(m_dvpDescription == other.m_dvpDescription, "Incosistent allocator descriptions"); DEV_CHECK_ERR(m_dvpFileName == other.m_dvpFileName, "Incosistent allocator file names"); DEV_CHECK_ERR(m_dvpLineNumber == other.m_dvpLineNumber, "Incosistent allocator line numbers"); #endif return *this; } template struct rebind { typedef STDAllocator other; }; T* allocate(std::size_t count) { #ifndef DILIGENT_DEVELOPMENT static constexpr const char* m_dvpDescription = ""; static constexpr const char* m_dvpFileName = ""; static constexpr Int32 m_dvpLineNumber = -1; #endif return reinterpret_cast(m_Allocator.Allocate(count * sizeof(T), m_dvpDescription, m_dvpFileName, m_dvpLineNumber)); } pointer address(reference r) { return &r; } const_pointer address(const_reference r) { return &r; } void deallocate(T* p, std::size_t count) { m_Allocator.Free(p); } inline size_type max_size() const { return std::numeric_limits::max() / sizeof(T); } // construction/destruction template void construct(U* p, Args&&... args) { ::new (p) U(std::forward(args)...); } inline void destroy(pointer p) { p->~T(); } AllocatorType& m_Allocator; #ifdef DILIGENT_DEVELOPMENT const Char* const m_dvpDescription; const Char* const m_dvpFileName; Int32 const m_dvpLineNumber; #endif }; #define STD_ALLOCATOR(Type, AllocatorType, Allocator, Description) STDAllocator(Allocator, Description, __FILE__, __LINE__) template bool operator==(const STDAllocator& left, const STDAllocator& right) { return &left.m_Allocator == &right.m_Allocator; } template bool operator!=(const STDAllocator& left, const STDAllocator& right) { return !(left == right); } template using STDAllocatorRawMem = STDAllocator; #define STD_ALLOCATOR_RAW_MEM(Type, Allocator, Description) STDAllocatorRawMem(Allocator, Description, __FILE__, __LINE__) template struct STDDeleter { STDDeleter() noexcept {} STDDeleter(AllocatorType& Allocator) noexcept : m_Allocator{&Allocator} {} STDDeleter(const STDDeleter&) = default; STDDeleter& operator=(const STDDeleter&) = default; STDDeleter(STDDeleter&& rhs) noexcept : m_Allocator{rhs.m_Allocator} { rhs.m_Allocator = nullptr; } STDDeleter& operator=(STDDeleter&& rhs) noexcept { m_Allocator = rhs.m_Allocator; rhs.m_Allocator = nullptr; return *this; } void operator()(T* ptr) noexcept { VERIFY(m_Allocator != nullptr, "The deleter has been moved away or never initialized, and can't be used"); Destruct(ptr); m_Allocator->Free(ptr); } private: AllocatorType* m_Allocator = nullptr; }; template using STDDeleterRawMem = STDDeleter; } // namespace Diligent