/*** Copyright (C) 2021 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: Heap.hpp Date: 2021-6-9 Author: Reece ***/ #pragma once namespace Aurora::Memory { struct Heap { virtual AuSPtr AllocateDivision(AuUInt32 heap, AuUInt32 alignment = 32) = 0; virtual Types::size_t GetChunkSize(const void *head) = 0; template T ZAlloc(Types::size_t length) { return reinterpret_cast(_ZAlloc(length)); } template T ZAlloc(Types::size_t length, Types::size_t align) { return reinterpret_cast(_ZAlloc(length, align)); } template T *ZAlloc() { return reinterpret_cast(_ZAlloc(sizeof(T))); } template T *NewArray(Types::size_t count) { return ZAlloc(count * sizeof(T)); } template T *NewArray(Types::size_t count, Types::size_t align) { return ZAlloc(count * sizeof(T), align); } /// Fast, unsafe alloc template T FAlloc(Types::size_t length) { return reinterpret_cast(_FAlloc(length)); } template T FAlloc(Types::size_t length, Types::size_t align) { return reinterpret_cast(_FAlloc(length, align)); } template T ZRealloc(T in, Types::size_t length) { return reinterpret_cast(_ZRealloc(reinterpret_cast(in), length)); } template T ZRealloc(T in, Types::size_t length, Types::size_t alloc) { return reinterpret_cast(_ZRealloc(reinterpret_cast(in), length), alloc); } template T FRealloc(T in, Types::size_t length) { return reinterpret_cast(_FRealloc(reinterpret_cast(in), length)); } template T FRealloc(T in, Types::size_t length, Types::size_t alloc) { return reinterpret_cast(_FRealloc(reinterpret_cast(in), length), alloc); } template void Free(T in) { _Free(reinterpret_cast(in)); } /** * @brief * @param in * A pointer owned by the heap * @param pinThis * If you attempt to destroy a heap, or allow a shared ptr to free the heap w/o freeing all allocations, the heap will dangle and a telemetry warning will be sent. * pinThis isn't strictly needed unless you wish to slience heap freed before allocation warnings. * A memory management model whereby you dont pin the parent heap will prevent circular references from taking over; in contrast, the alternative will need well defined object disposal * One could keep heap references weak outside of your heap manager and always pin this - or you could pin nothing and be careful with object disposal order * @return */ template AuSPtr ToSmartPointer(T *in, bool pinThis = true) { if (in == nullptr) return {}; auto heapHandle = pinThis ? GetSelfReference() : AuSPtr {}; return AuSPtr(in, [heapHandle, in, this](T *delt) { if constexpr (AuIsClass_v) { delt->~T(); } this->Free(delt); }); } template static AuSPtr ToSmartPointer(AuSPtr heap, T *in, bool pinHeap = true) { auto handle = pinHeap ? heap : AuSPtr {}; auto ptr = heap.get(); // so long as in is a valid pointer within the heap, this is fine return AuSPtr(in, [handle, ptr](T *delt) { ptr->Free(delt); }); } private: virtual AuSPtr GetSelfReference() = 0; virtual AU_ALLOC void *_ZAlloc(Types::size_t length) = 0; virtual AU_ALLOC void *_ZAlloc(Types::size_t length, Types::size_t align) = 0; virtual AU_ALLOC void *_FAlloc(Types::size_t length) = 0; virtual AU_ALLOC void *_FAlloc(Types::size_t length, Types::size_t align) = 0; virtual AU_ALLOC void *_ZRealloc(void *buffer, Types::size_t length, Types::size_t align) = 0; virtual AU_ALLOC void *_ZRealloc(void *buffer, Types::size_t length) = 0; virtual AU_ALLOC void *_FRealloc(void *buffer, Types::size_t length, Types::size_t align) = 0; virtual AU_ALLOC void *_FRealloc(void *buffer, Types::size_t length) = 0; virtual void _Free(void* buffer) = 0; }; /** Returns a heap interface backed by the default allocator */ AUKN_SHARED_API(GetDefaultDiscontiguousHeap, Heap); /** Allocates Fize amount of memory NOTE -> Heaps are guaranteed to outlive its' allocations; heap are the one object that own themselves Destructions are mere suggestions, however, requesting termination before a heap has released all of its memory will result in a telemetry mayday @return a heap backed by allocated memory */ AUKN_SHARED_API(AllocHeap, Heap, AuUInt size); AUKN_SHARED_API(RequestHeapOfRegion, Heap, void *ptr, AuUInt size); }