2021-06-27 21:25:29 +00:00
|
|
|
/***
|
|
|
|
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
|
|
|
|
{
|
2022-07-21 09:59:02 +00:00
|
|
|
struct Heap
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-07-21 09:59:02 +00:00
|
|
|
virtual AuSPtr<Heap> AllocateDivision(AuUInt32 heap, AuUInt32 alignment = 32) = 0;
|
2021-06-27 21:25:29 +00:00
|
|
|
virtual Types::size_t GetChunkSize(const void *head) = 0;
|
2022-12-08 19:34:15 +00:00
|
|
|
virtual HeapStats &GetStats() = 0;
|
2021-06-27 21:25:29 +00:00
|
|
|
|
|
|
|
template<typename T = void *>
|
|
|
|
T ZAlloc(Types::size_t length)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T>(_ZAlloc(length));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T = void *>
|
|
|
|
T ZAlloc(Types::size_t length, Types::size_t align)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T>(_ZAlloc(length, align));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T *ZAlloc()
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T *>(_ZAlloc(sizeof(T)));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T *NewArray(Types::size_t count)
|
|
|
|
{
|
|
|
|
return ZAlloc<T *>(count * sizeof(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T *NewArray(Types::size_t count, Types::size_t align)
|
|
|
|
{
|
|
|
|
return ZAlloc<T *>(count * sizeof(T), align);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Fast, unsafe alloc
|
|
|
|
template<typename T = void *>
|
|
|
|
T FAlloc(Types::size_t length)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T>(_FAlloc(length));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T = void *>
|
|
|
|
T FAlloc(Types::size_t length, Types::size_t align)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T>(_FAlloc(length, align));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T ZRealloc(T in, Types::size_t length)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), length));
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T ZRealloc(T in, Types::size_t length, Types::size_t alloc)
|
|
|
|
{
|
|
|
|
return reinterpret_cast<T>(_ZRealloc(reinterpret_cast<void *>(in), length), alloc);
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T FRealloc(T in, Types::size_t length)
|
|
|
|
{
|
2021-10-02 16:07:33 +00:00
|
|
|
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length));
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
T FRealloc(T in, Types::size_t length, Types::size_t alloc)
|
|
|
|
{
|
2021-10-02 16:07:33 +00:00
|
|
|
return reinterpret_cast<T>(_FRealloc(reinterpret_cast<void *>(in), length), alloc);
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
void Free(T in)
|
|
|
|
{
|
|
|
|
_Free(reinterpret_cast<void *>(in));
|
|
|
|
}
|
|
|
|
|
2022-12-08 19:34:15 +00:00
|
|
|
template <class T, class ...Args>
|
|
|
|
AuSPtr<T> NewClass(T &ref, Args &&...args)
|
|
|
|
{
|
|
|
|
void * pPtr;
|
|
|
|
|
|
|
|
if constexpr (AuIsClass_v<T>)
|
|
|
|
{
|
|
|
|
pPtr = this->FAlloc<void *>(sizeof(T));
|
|
|
|
if (pPtr)
|
|
|
|
{
|
|
|
|
new (pPtr) T(AuForward<Args &&>(args)...);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pPtr = this->ZAlloc<void *>(sizeof(T));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!pPtr)
|
|
|
|
{
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
return ToSmartPointer(pPtr, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-18 19:31:15 +00:00
|
|
|
/**
|
|
|
|
* @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
|
|
|
|
*/
|
2021-06-27 21:25:29 +00:00
|
|
|
template<typename T>
|
2022-12-08 19:34:15 +00:00
|
|
|
AuSPtr<T> ToSmartPointer(T *in, bool pinThis)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
|
|
|
if (in == nullptr) return {};
|
2022-01-18 20:04:14 +00:00
|
|
|
auto heapHandle = pinThis ? GetSelfReference() : AuSPtr<Heap> {};
|
2022-01-19 18:18:13 +00:00
|
|
|
return AuSPtr<T>(in,
|
2022-01-18 19:31:15 +00:00
|
|
|
[heapHandle, in, this](T *delt)
|
|
|
|
{
|
2022-01-19 17:08:13 +00:00
|
|
|
if constexpr (AuIsClass_v<T>)
|
2022-01-18 19:31:15 +00:00
|
|
|
{
|
|
|
|
delt->~T();
|
|
|
|
}
|
|
|
|
this->Free(delt);
|
|
|
|
});
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T>
|
2022-01-18 19:31:15 +00:00
|
|
|
static AuSPtr<T> ToSmartPointer(AuSPtr<Heap> heap, T *in, bool pinHeap = true)
|
2021-06-27 21:25:29 +00:00
|
|
|
{
|
2022-01-18 20:04:14 +00:00
|
|
|
auto handle = pinHeap ? heap : AuSPtr<Heap> {};
|
2022-01-18 19:31:15 +00:00
|
|
|
auto ptr = heap.get(); // so long as in is a valid pointer within the heap, this is fine
|
2022-01-19 18:18:13 +00:00
|
|
|
return AuSPtr<T>(in,
|
2022-01-18 19:31:15 +00:00
|
|
|
[handle, ptr](T *delt)
|
|
|
|
{
|
2022-12-08 19:34:15 +00:00
|
|
|
if constexpr (AuIsClass_v<T>)
|
|
|
|
{
|
|
|
|
delt->~T();
|
|
|
|
}
|
|
|
|
|
|
|
|
ptr->Free(delt);
|
2022-01-18 19:31:15 +00:00
|
|
|
});
|
2021-06-27 21:25:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-01-18 19:31:15 +00:00
|
|
|
|
2022-12-08 19:34:15 +00:00
|
|
|
virtual AuSPtr<Heap> GetSelfReference() = 0; // may return empty/default. not all heaps are sharable.
|
|
|
|
|
|
|
|
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength) = 0;
|
|
|
|
virtual AU_ALLOC void *_ZAlloc(Types::size_t uLength, Types::size_t align) = 0;
|
|
|
|
virtual AU_ALLOC void *_FAlloc(Types::size_t uLength) = 0;
|
|
|
|
virtual AU_ALLOC void *_FAlloc(Types::size_t uLength, Types::size_t align) = 0;
|
|
|
|
virtual AU_ALLOC void *_ZRealloc(void *pBase, Types::size_t uLength, Types::size_t uAlign) = 0;
|
|
|
|
virtual AU_ALLOC void *_ZRealloc(void *pBase, Types::size_t uLength) = 0;
|
|
|
|
virtual AU_ALLOC void *_FRealloc(void *pBase, Types::size_t uLength, Types::size_t uAlign) = 0;
|
|
|
|
virtual AU_ALLOC void *_FRealloc(void *pBase, Types::size_t uLength) = 0;
|
|
|
|
virtual void _Free(void* pBase) = 0;
|
2021-06-27 21:25:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
Returns a heap interface backed by the default allocator
|
|
|
|
*/
|
|
|
|
AUKN_SHARED_API(GetDefaultDiscontiguousHeap, Heap);
|
|
|
|
|
|
|
|
/**
|
|
|
|
Allocates Fize amount of memory
|
2022-01-18 19:31:15 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
|
2021-06-27 21:25:29 +00:00
|
|
|
@return a heap backed by allocated memory
|
|
|
|
*/
|
2022-12-08 19:34:15 +00:00
|
|
|
AUKN_SHARED_API(AllocHeap, Heap, AuUInt uLength);
|
|
|
|
|
|
|
|
AUKN_SHARED_API(RequestHeapOfRegion, Heap, void *pPtr, AuUInt uLength);
|
2022-07-21 09:59:02 +00:00
|
|
|
|
2022-12-08 19:34:15 +00:00
|
|
|
AUKN_SHARED_API(AllocHeapMimalloc, Heap, AuUInt uLength);
|
2021-10-02 16:07:33 +00:00
|
|
|
}
|