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
{
2024-01-16 21:11:08 +00:00
struct ProxyHeap ;
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 ;
2024-01-16 21:11:08 +00:00
virtual Types : : size_t GetChunkSize ( const void * pHead ) = 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 >
2024-01-16 21:11:08 +00:00
T ZRealloc ( T pHead , Types : : size_t length )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
return reinterpret_cast < T > ( _ZRealloc ( reinterpret_cast < void * > ( pHead ) , length ) ) ;
2021-06-27 21:25:29 +00:00
}
template < typename T >
2024-01-16 21:11:08 +00:00
T ZRealloc ( T pHead , Types : : size_t length , Types : : size_t alloc )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
return reinterpret_cast < T > ( _ZRealloc ( reinterpret_cast < void * > ( pHead ) , length ) , alloc ) ;
2021-06-27 21:25:29 +00:00
}
template < typename T >
2024-01-16 21:11:08 +00:00
T FRealloc ( T pHead , Types : : size_t length )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
return reinterpret_cast < T > ( _FRealloc ( reinterpret_cast < void * > ( pHead ) , length ) ) ;
2021-06-27 21:25:29 +00:00
}
template < typename T >
2024-01-16 21:11:08 +00:00
T FRealloc ( T pHead , Types : : size_t length , Types : : size_t alloc )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
return reinterpret_cast < T > ( _FRealloc ( reinterpret_cast < void * > ( pHead ) , length ) , alloc ) ;
2021-06-27 21:25:29 +00:00
}
template < typename T >
2024-01-16 21:11:08 +00:00
void Free ( T pHead )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
_Free ( reinterpret_cast < void * > ( pHead ) ) ;
2021-06-27 21:25:29 +00:00
}
2024-01-18 12:17:01 +00:00
protected :
template < typename T >
static void DeleteThat ( T * pThat )
{
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) ) ;
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_destructible_v < T >
# endif
)
{
pThat - > ~ T ( ) ;
}
auto & pHeap = * ( Heap * * ) ( ( ( char * ) pThat ) - kAlignment ) ;
pHeap - > _Free ( & pHeap ) ;
}
template < typename T >
static void DeleteThatArray ( T * pThat )
{
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) * 2 ) ;
auto pVoids = ( void * * ) ( ( ( char * ) pThat ) - kAlignment ) ;
auto pHeap = ( Heap * ) pVoids [ 0 ] ;
auto uCount = ( AuUInt ) pVoids [ 1 ] ;
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_destructible_v < T >
# endif
)
{
for ( AU_ITERATE_N ( i , uCount ) )
{
auto & refElement = pThat [ i ] ;
refElement . ~ T ( ) ;
}
}
pHeap - > _Free ( pVoids ) ;
}
2024-02-15 01:10:23 +00:00
template < typename T , typename Z >
static void DeleteThatCastedOnce ( T * pThat )
{
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) ) ;
auto pBaseClass = AuStaticCast < Z > ( pThat ) ;
2024-02-16 11:45:57 +00:00
if constexpr ( AuIsClass_v < Z >
2024-02-15 01:10:23 +00:00
# if !defined(AURT_HEAP_NO_STL)
2024-02-16 11:45:57 +00:00
& & ! std : : is_trivially_destructible_v < Z >
2024-02-15 01:10:23 +00:00
# endif
)
{
pBaseClass - > ~ Z ( ) ;
}
auto & pHeap = * ( Heap * * ) ( ( ( char * ) pBaseClass ) - kAlignment ) ;
pHeap - > _Free ( & pHeap ) ;
}
2024-01-18 12:17:01 +00:00
template < typename T >
static void RetardedSpecWrittenByRetards ( T * pThat )
{
}
public :
2022-12-08 19:34:15 +00:00
template < class T , class . . . Args >
2023-12-01 06:50:39 +00:00
AuSPtr < T > NewClass ( Args & & . . . args )
2022-12-08 19:34:15 +00:00
{
2024-01-16 21:11:08 +00:00
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) ) ;
AuUInt8 * pPtr ;
2022-12-08 19:34:15 +00:00
2024-01-18 00:01:00 +00:00
auto pThat = this - > GetSelfReferenceRaw ( ) ;
if ( ! pThat )
{
pThat = this ;
}
2024-01-16 21:11:08 +00:00
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_constructible_v < T >
# endif
)
2022-12-08 19:34:15 +00:00
{
2024-01-18 00:01:00 +00:00
pPtr = pThat - > FAlloc < AuUInt8 * > ( sizeof ( T ) + kAlignment , kAlignment ) ;
2022-12-08 19:34:15 +00:00
if ( pPtr )
{
2024-02-13 03:18:13 +00:00
new ( pPtr + kAlignment ) T ( AuForward < Args > ( args ) . . . ) ;
2022-12-08 19:34:15 +00:00
}
}
else
{
2024-01-18 00:01:00 +00:00
pPtr = pThat - > ZAlloc < AuUInt8 * > ( sizeof ( T ) + kAlignment , kAlignment ) ;
2022-12-08 19:34:15 +00:00
}
if ( ! pPtr )
{
return { } ;
}
2024-01-18 00:01:00 +00:00
* ( void * * ) pPtr = pThat ;
2024-01-16 21:11:08 +00:00
return AuSPtr < T > ( ( T * ) ( pPtr + kAlignment ) , & Heap : : DeleteThat < T > ) ;
2022-12-08 19:34:15 +00:00
}
2024-01-19 19:40:38 +00:00
// note: callers can use AuHUPOf_t<T> pUniquePointer = AuNullHeapPointer<T>()
2024-01-18 12:17:01 +00:00
template < class T , class . . . Args >
AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > NewClassUnique ( Args & & . . . args )
{
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) ) ;
AuUInt8 * pPtr ;
auto pThat = this - > GetSelfReferenceRaw ( ) ;
if ( ! pThat )
{
pThat = this ;
}
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_constructible_v < T >
# endif
)
{
pPtr = pThat - > FAlloc < AuUInt8 * > ( sizeof ( T ) + kAlignment , kAlignment ) ;
if ( pPtr )
{
2024-02-13 03:18:13 +00:00
new ( pPtr + kAlignment ) T ( AuForward < Args > ( args ) . . . ) ;
2024-01-18 12:17:01 +00:00
}
}
else
{
pPtr = pThat - > ZAlloc < AuUInt8 * > ( sizeof ( T ) + kAlignment , kAlignment ) ;
}
if ( ! pPtr )
{
return AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ( nullptr , & Heap : : RetardedSpecWrittenByRetards < T > ) ;
}
* ( void * * ) pPtr = pThat ;
return AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ( ( T * ) ( pPtr + kAlignment ) , & Heap : : DeleteThat < T > ) ;
}
2024-01-16 21:11:08 +00:00
template < class T , class . . . Args >
AuSPtr < T > NewClassArray ( AuUInt uElements , Args & & . . . fillCtr )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) * 2 ) ;
AuUInt8 * pPtr ;
if ( ! uElements )
{
return { } ;
}
2024-01-18 00:01:00 +00:00
auto pThat = this - > GetSelfReferenceRaw ( ) ;
if ( ! pThat )
{
pThat = this ;
}
2024-01-16 21:11:08 +00:00
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_constructible_v < T >
# endif
)
{
2024-01-18 00:01:00 +00:00
if ( bool ( pPtr = pThat - > FAlloc < AuUInt8 * > ( ( sizeof ( T ) * uElements ) + kAlignment , kAlignment ) ) )
2024-01-16 21:11:08 +00:00
{
for ( AU_ITERATE_N ( i , uElements ) )
{
2024-02-13 03:18:13 +00:00
new ( pPtr + kAlignment + ( sizeof ( T ) * i ) ) T ( AuForward < Args > ( fillCtr ) . . . ) ;
2024-01-16 21:11:08 +00:00
}
}
}
else
{
2024-01-18 00:01:00 +00:00
if ( bool ( pPtr = pThat - > ZAlloc < AuUInt8 * > ( ( sizeof ( T ) * uElements ) + kAlignment , kAlignment ) ) )
2024-01-16 21:11:08 +00:00
{
if constexpr ( sizeof . . . ( Args ) ! = 0 )
{
# if defined(AURT_HEAP_NO_STL)
static_assert ( false ) ;
# else
auto pElements = ( T * ) ( pPtr + kAlignment ) ;
2024-02-13 03:18:13 +00:00
std : : fill ( pElements , pElements + uElements , AuForward < Args > ( fillCtr ) . . . ) ;
2024-01-16 21:11:08 +00:00
# endif
}
}
}
if ( ! pPtr )
{
return { } ;
}
auto pVoids = ( void * * ) pPtr ;
2024-01-18 00:01:00 +00:00
pVoids [ 0 ] = pThat ;
2024-01-16 21:11:08 +00:00
pVoids [ 1 ] = ( void * ) uElements ;
return AuSPtr < T > ( ( T * ) ( pPtr + kAlignment ) , & Heap : : DeleteThatArray < T > ) ;
2021-06-27 21:25:29 +00:00
}
2024-01-19 19:40:38 +00:00
// note: callers can use AuHUPOf_t<T> pUniquePointer = AuNullHeapPointer<T>()
2024-01-18 12:17:01 +00:00
template < class T , class . . . Args >
AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > NewClassArrayUnique ( AuUInt uElements , Args & & . . . fillCtr )
{
static const auto kAlignment = AuMax ( alignof ( T ) , sizeof ( void * ) * 2 ) ;
AuUInt8 * pPtr ;
if ( ! uElements )
{
return AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ( nullptr , & Heap : : RetardedSpecWrittenByRetards < T > ) ;
}
auto pThat = this - > GetSelfReferenceRaw ( ) ;
if ( ! pThat )
{
pThat = this ;
}
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_constructible_v < T >
# endif
)
{
if ( bool ( pPtr = pThat - > FAlloc < AuUInt8 * > ( ( sizeof ( T ) * uElements ) + kAlignment , kAlignment ) ) )
{
for ( AU_ITERATE_N ( i , uElements ) )
{
2024-02-13 03:18:13 +00:00
new ( pPtr + kAlignment + ( sizeof ( T ) * i ) ) T ( AuForward < Args > ( fillCtr ) . . . ) ;
2024-01-18 12:17:01 +00:00
}
}
}
else
{
if ( bool ( pPtr = pThat - > ZAlloc < AuUInt8 * > ( ( sizeof ( T ) * uElements ) + kAlignment , kAlignment ) ) )
{
if constexpr ( sizeof . . . ( Args ) ! = 0 )
{
# if defined(AURT_HEAP_NO_STL)
static_assert ( false ) ;
# else
auto pElements = ( T * ) ( pPtr + kAlignment ) ;
2024-02-13 03:18:13 +00:00
std : : fill ( pElements , pElements + uElements , AuForward < Args > ( fillCtr ) . . . ) ;
2024-01-18 12:17:01 +00:00
# endif
}
}
}
if ( ! pPtr )
{
return AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ( nullptr , & Heap : : RetardedSpecWrittenByRetards < T > ) ;
}
auto pVoids = ( void * * ) pPtr ;
pVoids [ 0 ] = pThat ;
pVoids [ 1 ] = ( void * ) uElements ;
return AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ( ( T * ) ( pPtr + kAlignment ) , & Heap : : DeleteThatArray < T > ) ;
}
2024-01-19 19:40:38 +00:00
template < class T >
cstatic AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > NullUniquePointer ( )
{
return AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ( nullptr , & Heap : : RetardedSpecWrittenByRetards < T > ) ;
}
2024-02-14 06:35:43 +00:00
template < class Z , class T >
cstatic AuUPtr < Z , decltype ( & Heap : : DeleteThat < Z > ) > CastPointer ( AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > & & pInPointer )
{
if ( ! pInPointer )
{
return NullUniquePointer < Z > ( ) ;
}
2024-02-15 01:10:23 +00:00
else if ( pInPointer . get_deleter ( ) = = & Heap : : DeleteThat < T > )
{
return AuUPtr < Z , decltype ( & Heap : : DeleteThat < Z > ) > ( AuStaticCast < Z > ( pInPointer . release ( ) ) , & Heap : : DeleteThatCastedOnce < Z , T > ) ;
}
2024-02-14 06:35:43 +00:00
else
{
2024-02-15 01:10:23 +00:00
return NullUniquePointer < Z > ( ) ;
2024-02-14 06:35:43 +00:00
}
}
2021-06-27 21:25:29 +00:00
template < typename T >
2024-01-16 21:11:08 +00:00
static AuSPtr < T > ToSmartPointer ( AuSPtr < Heap > heap ,
T * pHead ,
bool bPinHeap = true )
2021-06-27 21:25:29 +00:00
{
2024-01-16 21:11:08 +00:00
auto handle = bPinHeap ?
heap :
AuSPtr < Heap > { } ;
auto pHeap = heap . get ( ) ;
return AuSPtr < T > ( pHead ,
[ handle , pHeap ] ( T * pDeleteMe )
2022-01-18 19:31:15 +00:00
{
2024-01-16 21:11:08 +00:00
if constexpr ( AuIsClass_v < T >
# if !defined(AURT_HEAP_NO_STL)
& & ! std : : is_trivially_destructible_v < T >
# endif
)
2022-12-08 19:34:15 +00:00
{
2024-01-16 21:11:08 +00:00
pDeleteMe - > ~ T ( ) ;
2022-12-08 19:34:15 +00:00
}
2024-01-16 21:11:08 +00:00
pHeap - > Free ( pDeleteMe ) ;
2022-01-18 19:31:15 +00:00
} ) ;
2021-06-27 21:25:29 +00:00
}
2024-01-18 17:19:35 +00:00
template < typename T >
using HUPOf_t = AuUPtr < T , decltype ( & Heap : : DeleteThat < T > ) > ;
2024-01-16 21:11:08 +00:00
protected :
friend struct ProxyHeap ;
2024-01-27 08:04:29 +00:00
friend struct HeapAccessor ;
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.
2024-01-16 21:11:08 +00:00
virtual Heap * GetSelfReferenceRaw ( ) = 0 ;
2022-12-08 19:34:15 +00:00
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
} ;
2024-01-27 08:04:29 +00:00
struct HeapAccessor
{
cstatic AuSPtr < Heap > GetSelfReference ( Heap * pHeap )
{
return pHeap - > GetSelfReference ( ) ;
}
cstatic Heap * GetSelfReferenceRaw ( Heap * pHeap )
{
return pHeap - > GetSelfReferenceRaw ( ) ;
}
} ;
2021-06-27 21:25:29 +00:00
/**
Returns a heap interface backed by the default allocator
*/
2024-02-13 03:18:13 +00:00
AUKN_SHARED_API ( DefaultDiscontiguousHeap , Heap ) ;
inline Heap * GetDefaultDiscontiguousHeap ( )
{
return DefaultDiscontiguousHeapNew ( ) ;
}
inline AuSPtr < Heap > GetDefaultDiscontiguousHeapShared ( )
{
// Might not allocate the control block under some STLs, unlike DefaultDiscontiguousHeapSharedShared() which will generally always allocate a control block under most STLs
return AuUnsafeRaiiToShared ( GetDefaultDiscontiguousHeap ( ) ) ;
}
2021-06-27 21:25:29 +00:00
/**
2024-01-15 12:04:40 +00:00
Allocates uLength amount of contiguous virtual memory
@ warning Heaps are guaranteed to outlive their allocations ; heaps are the one object that effectively own a single reference count on themselves .
2024-01-16 21:11:08 +00:00
Requesting termination before all of its ' memory has been free will result , pHead at worst , a warning .
2024-01-15 12:04:40 +00:00
Expect to leak unless all allocs have been paired by a free .
2022-01-18 19:31:15 +00:00
2024-01-15 12:04:40 +00:00
I do not expect to implement force frees simply because all our primary use cases keep track of dtors to forcefully release leaked objects .
Use RequestHeapOfRegion to be backed by caller owned memory .
2022-01-18 19:31:15 +00:00
2024-01-15 12:04:40 +00:00
@ return a heap backed by uLength bytes of virtual memory
2021-06-27 21:25:29 +00:00
*/
2022-12-08 19:34:15 +00:00
AUKN_SHARED_API ( AllocHeap , Heap , AuUInt uLength ) ;
2024-02-13 03:55:57 +00:00
AUKN_SHARED_API ( RequestHeapOfRegion , Heap , const MemoryViewWrite & memory ) ;
2022-07-21 09:59:02 +00:00
2024-01-15 12:04:40 +00:00
// AllocHeap but use mimalloc (or the default allocator) instead
2022-12-08 19:34:15 +00:00
AUKN_SHARED_API ( AllocHeapMimalloc , Heap , AuUInt uLength ) ;
2024-01-16 21:11:08 +00:00
// Proxies an existing heap with encapsulated statistics
AUKN_SHARED_API ( HeapProxy , Heap , const AuSPtr < Heap > & pHead ) ;
// Proxies an existing heap with encapsulated statistics and leak detector
AUKN_SHARED_API ( HeapProxyEx , Heap , const AuSPtr < Heap > & pHead , LeakFinderAlloc_f pfAlloc , LeakFinderFree_f pfFree ) ;
2024-01-19 19:40:38 +00:00
}