#pragma once #include "deimos/core/base.h" #include "deimos/core/id_name.h" namespace deimos { struct MemoryScope { uint32_t id; }; struct IAllocator { IAllocator() = default; deimos_NO_COPY_MOVE(IAllocator); virtual ~IAllocator() = default; [[nodiscard]] virtual gsl::owner Reallocate( gsl::owner old_ptr, int64_t old_size, int64_t new_size, MemoryScope scope, const SourceLocation& source_location = {}) = 0; }; class Allocator { gsl::owner m_allocator; const MemoryScope m_scope; public: constexpr Allocator(IAllocator* allocator, MemoryScope scope) : m_allocator{allocator}, m_scope{scope} {} deimos_NO_COPY_MOVE(Allocator); ~Allocator() = default; constexpr IAllocator* allocator() const { return m_allocator; } [[nodiscard]] constexpr gsl::owner Allocate( int64_t new_size, const SourceLocation& source_location = {}) { return m_allocator->Reallocate(nullptr, 0, new_size, m_scope, source_location); } [[nodiscard]] gsl::owner Reallocate( gsl::owner old_ptr, int64_t old_size, int64_t new_size, const SourceLocation& source_location = {}) { return m_allocator->Reallocate(old_ptr, old_size, new_size, m_scope, source_location); } constexpr void Free( gsl::owner old_ptr, int64_t old_size, const SourceLocation& source_location = {}) { (void)m_allocator->Reallocate(old_ptr, old_size, 0, m_scope, source_location); } template gsl::owner NewInner( const SourceLocation& source_location, Args&&... args) { gsl::owner ptr = Allocate(sizeof(T), source_location); return new(ptr) T(std::forward(args)...); } template constexpr gsl::owner New(const SourceLocation& source_location = {}) { return NewInner(source_location); } template constexpr gsl::owner New(A0&& arg0, const SourceLocation& source_location = {}) { return NewInner(source_location, std::forward(arg0)); } template constexpr gsl::owner New( A0&& arg0, A1&& arg1, const SourceLocation& source_location = {}) { return NewInner(source_location, std::forward(arg0), std::forward(arg1)); } template constexpr gsl::owner New( A0&& arg0, A1&& arg1, A2&& arg2, const SourceLocation& source_location = {}) { return NewInner(source_location, std::forward(arg0), std::forward(arg1), std::forward(arg2)); } template constexpr gsl::owner New( A0&& arg0, A1&& arg1, A2&& arg2, A3&& arg3, const SourceLocation& source_location = {}) { return NewInner(source_location, std::forward(arg0), std::forward(arg1), std::forward(arg2), std::forward(arg3)); } template void Delete(gsl::owner t, const SourceLocation& source_location = {}) { if constexpr (!std::is_trivially_destructible_v) { t->~T(); } Free(t, sizeof(T), source_location); } template gsl::owner> NewArray(int64_t count, const SourceLocation& source_location = {}) requires std::is_default_constructible_v { Expects(count > 0); auto* raw = Allocate((int64_t)sizeof(T) * count, source_location); if constexpr (std::is_trivially_default_constructible_v) { MemoryZero(raw, (int64_t)sizeof(T) * count); } else { for (int64_t i = 0; i < count; ++i) { new((T*)raw + i) T{}; } } return Span{ (T*)raw, count }; } }; class AllocatorApi { public: AllocatorApi() = default; deimos_NO_COPY_MOVE(AllocatorApi); virtual ~AllocatorApi() = default; static constexpr IdName kApiName{"deimos::AllocatorApi"}; Allocator* system{}; virtual gsl::owner CreateChild(Allocator* parent, gsl::czstring description) = 0; virtual void DestroyChild(gsl::owner) = 0; }; } // namespace deimos