/*** Copyright (C) 2021-2024 Jamie Reece Wilson (a/k/a "Reece"). All rights reserved. File: Heap.inl Date: 2024-7-14 Date: 2021-6-9 Author: Reece ***/ #pragma once namespace Aurora::Memory { template T Heap::ZAlloc(Types::size_t uLength) { if constexpr (AuIsVoid_v>) { return reinterpret_cast(_ZAlloc(uLength)); } else { return reinterpret_cast(_ZAlloc(uLength, alignof(AuRemovePointer_t))); } } template T Heap::ZAlloc(Types::size_t uLength, Types::size_t uAlignment) { return reinterpret_cast(_ZAlloc(uLength, uAlignment)); } template T *Heap::ZAlloc() { return reinterpret_cast(_ZAlloc(sizeof(T), alignof(T))); } template T *Heap::NewArray(Types::size_t uLength) { return ZAlloc(uLength * sizeof(T), alignof(T)); } template T *Heap::NewArray(Types::size_t uLength, Types::size_t uAlignment) { return ZAlloc(uLength * sizeof(T), uAlignment); } template T Heap::FAlloc(Types::size_t uLength) { if constexpr (AuIsVoid_v>) { return reinterpret_cast(_FAlloc(uLength)); } else { return reinterpret_cast(_FAlloc(uLength, alignof(AuRemovePointer_t))); } } template T Heap::FAlloc(Types::size_t uLength, Types::size_t uAlignment) { return reinterpret_cast(_FAlloc(uLength, uAlignment)); } template T *Heap::FAlloc() { return reinterpret_cast(_FAlloc(sizeof(T), alignof(T))); } // Reallocs template T Heap::ZRealloc(T pHead, Types::size_t uLength) { if constexpr (AuIsVoid_v>) { return reinterpret_cast(_ZRealloc(reinterpret_cast(pHead), uLength)); } else { return reinterpret_cast(_ZRealloc(reinterpret_cast(pHead), uLength, alignof(AuRemovePointer_t))); } } template T Heap::ZRealloc(T pHead, Types::size_t uLength, Types::size_t uAlignment) { return reinterpret_cast(_ZRealloc(reinterpret_cast(pHead), uLength, uAlignment)); } template T Heap::FRealloc(T pHead, Types::size_t uLength) { if constexpr (AuIsVoid_v>) { return reinterpret_cast(_FRealloc(reinterpret_cast(pHead), uLength)); } else { return reinterpret_cast(_FRealloc(reinterpret_cast(pHead), uLength, alignof(AuRemovePointer_t))); } } template T Heap::FRealloc(T pHead, Types::size_t uLength, Types::size_t uAlignment) { return reinterpret_cast(_FRealloc(reinterpret_cast(pHead), uLength, uAlignment)); } // Free template void Heap::Free(T pHead) { _Free(reinterpret_cast(pHead)); } template void Heap::DeleteThat(T *pThat) { static const auto kAlignment = AuMax(alignof(T), sizeof(void *)); if constexpr (AuIsClass_v && !AuIsTriviallyDestructible_v) { pThat->~T(); } auto &pHeap = *(Heap **)(((char *)pThat) - kAlignment); pHeap->_Free(&pHeap); } template void Heap::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 uLength = (AuUInt)pVoids[1]; if constexpr (AuIsClass_v && !AuIsTriviallyDestructible_v) { for (AU_ITERATE_N(i, uLength)) { auto &refElement = pThat[i]; refElement.~T(); } } pHeap->_Free(pVoids); } template void Heap::DeleteThatArray2(T *pThat) { auto pBase = ((void **)pThat)[-1]; auto pVoids = (void **)pBase; auto pHeap = (Heap *)pVoids[0]; auto uLength = (AuUInt)pVoids[1]; if constexpr (AuIsClass_v && !AuIsTriviallyDestructible_v) { for (AU_ITERATE_N(i, uLength)) { auto &refElement = pThat[i]; refElement.~T(); } } pHeap->_Free(pVoids); } template void Heap::DeleteThatCastedOnce(T *pThat) { static const auto kAlignment = AuMax(alignof(Z), sizeof(void *)); auto pBaseClass = AuStaticCast(pThat); if constexpr (AuIsClass_v && !AuIsTriviallyDestructible_v) { pBaseClass->~Z(); } auto &pHeap = *(Heap **)(((char *)pBaseClass) - kAlignment); pHeap->_Free(&pHeap); } template void Heap::RetardedSpecWrittenByRetards(T *pThat) { } template AuSPtr Heap::NewClass(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 && !AuIsTriviallyConstructible_v) { pPtr = pThat->FAlloc(sizeof(T) + kAlignment, kAlignment); if (pPtr) { new (pPtr + kAlignment) T(AuForward(args)...); } } else { pPtr = pThat->ZAlloc(sizeof(T) + kAlignment, kAlignment); } if (!pPtr) { return {}; } *(void **)pPtr = pThat; auto pTThat = (T *)(pPtr + kAlignment); AUROXTL_COMMODITY_TRY { return AuSPtr(pTThat, &Heap::DeleteThat, CppHeapWrapper { this }); } AUROXTL_COMMODITY_CATCH { Heap::DeleteThat(pTThat); return {}; } } template AuUPtr)> Heap::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 && !AuIsTriviallyConstructible_v) { pPtr = pThat->FAlloc(sizeof(T) + kAlignment, kAlignment); if (pPtr) { new (pPtr + kAlignment) T(AuForward(args)...); } } else { pPtr = pThat->ZAlloc(sizeof(T) + kAlignment, kAlignment); } if (!pPtr) { return AuUPtr)>(nullptr, &Heap::RetardedSpecWrittenByRetards); } *(void **)pPtr = pThat; if constexpr (AuIsSame_v) { return AuUPtr)>((T *)(pPtr + kAlignment), &Heap::DeleteThat); } else { return Heap::CastPointer(AuMove(AuUPtr)>((T *)(pPtr + kAlignment), &Heap::DeleteThat))); } } template AuSPtr Heap::NewClassArray(AuUInt uElements, Args &&... fillCtr) { const auto kAlignment = AuMax(alignof(T), sizeof(void *) * 2); AuUInt8 *pPtr; if (!uElements) { return {}; } auto pThat = this->GetSelfReferenceRaw(); if (!pThat) { pThat = this; } if constexpr (AuIsClass_v && !AuIsTriviallyConstructible_v) { if (bool(pPtr = pThat->FAlloc((sizeof(T) * uElements) + kAlignment, kAlignment))) { for (AU_ITERATE_N(i, uElements)) { new (pPtr + kAlignment + (sizeof(T) * i)) T(AuForward(fillCtr)...); } } } else { if (bool(pPtr = pThat->ZAlloc((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); std::fill(pElements, pElements + uElements, AuForward(fillCtr)...); #endif } } } if (!pPtr) { return {}; } auto pVoids = (void **)pPtr; pVoids[0] = pThat; pVoids[1] = (void *)uElements; auto pTThat = (T *)(pPtr + kAlignment); AUROXTL_COMMODITY_TRY { return AuSPtr(pTThat, &Heap::DeleteThatArray, CppHeapWrapper { this }); } AUROXTL_COMMODITY_CATCH { Heap::DeleteThatArray(pTThat); return {}; } } template AuSPtr Heap::NewClassArray2(AuUInt uElements, AuUInt uAlignment, Args &&... fillCtr) { const auto kAlignment = AuMax(uAlignment, sizeof(void *) * 4); AuUInt8 *pPtr; if (!uElements) { return {}; } auto pThat = this->GetSelfReferenceRaw(); if (!pThat) { pThat = this; } if constexpr (AuIsClass_v && !AuIsTriviallyConstructible_v) { if (bool(pPtr = pThat->FAlloc((sizeof(T) * uElements) + kAlignment, kAlignment))) { for (AU_ITERATE_N(i, uElements)) { new (pPtr + kAlignment + (sizeof(T) * i)) T(AuForward(fillCtr)...); } } } else { if (bool(pPtr = pThat->ZAlloc((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); std::fill(pElements, pElements + uElements, AuForward(fillCtr)...); #endif } } } if (!pPtr) { return {}; } auto pVoids = (void **)pPtr; pVoids[0] = pThat; pVoids[1] = (void *)uElements; ((void **)(pPtr + kAlignment))[-1] = pPtr; auto pTThat = (T *)(pPtr + kAlignment); AUROXTL_COMMODITY_TRY { return AuSPtr(pTThat, &Heap::DeleteThatArray2, CppHeapWrapper { this }); } AUROXTL_COMMODITY_CATCH { Heap::DeleteThatArray2(pTThat); return {}; } } template AuUPtr)> Heap::NewClassArrayUnique(AuUInt uElements, Args &&... fillCtr) { const auto kAlignment = AuMax(alignof(T), sizeof(void *) * 2); AuUInt8 *pPtr; if (!uElements) { return AuUPtr)>(nullptr, &Heap::RetardedSpecWrittenByRetards); } auto pThat = this->GetSelfReferenceRaw(); if (!pThat) { pThat = this; } if constexpr (AuIsClass_v && !AuIsTriviallyConstructible_v) { if (bool(pPtr = pThat->FAlloc((sizeof(T) * uElements) + kAlignment, kAlignment))) { for (AU_ITERATE_N(i, uElements)) { new (pPtr + kAlignment + (sizeof(T) * i)) T(AuForward(fillCtr)...); } } } else { if (bool(pPtr = pThat->ZAlloc((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); std::fill(pElements, pElements + uElements, AuForward(fillCtr)...); #endif } } } if (!pPtr) { return AuUPtr)>(nullptr, &Heap::RetardedSpecWrittenByRetards); } auto pVoids = (void **)pPtr; pVoids[0] = pThat; pVoids[1] = (void *)uElements; return AuUPtr)>((T *)(pPtr + kAlignment), &Heap::DeleteThatArray); } template AuUPtr)> Heap::NewClassArray2Unique(AuUInt uElements, AuUInt uAlignment, Args &&... fillCtr) { const auto kAlignment = AuMax(uAlignment, sizeof(void *) * 4); AuUInt8 *pPtr; if (!uElements) { return AuUPtr)>(nullptr, &Heap::RetardedSpecWrittenByRetards); } auto pThat = this->GetSelfReferenceRaw(); if (!pThat) { pThat = this; } if constexpr (AuIsClass_v && !AuIsTriviallyConstructible_v) { if (bool(pPtr = pThat->FAlloc((sizeof(T) * uElements) + kAlignment, kAlignment))) { for (AU_ITERATE_N(i, uElements)) { new (pPtr + kAlignment + (sizeof(T) * i)) T(AuForward(fillCtr)...); } } } else { if (bool(pPtr = pThat->ZAlloc((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); std::fill(pElements, pElements + uElements, AuForward(fillCtr)...); #endif } } } if (!pPtr) { return AuUPtr)>(nullptr, &Heap::RetardedSpecWrittenByRetards); } auto pVoids = (void **)pPtr; pVoids[0] = pThat; pVoids[1] = (void *)uElements; ((void **)(pPtr + kAlignment))[-1] = pPtr; auto pTThat = (T *)(pPtr + kAlignment); return AuUPtr)>(pTThat, &Heap::DeleteThatArray2); } template AuUPtr)> Heap::NullUniquePointer() { return AuUPtr)>(nullptr, &Heap::RetardedSpecWrittenByRetards); } template AuUPtr)> Heap::CastPointer(AuUPtr)> &&pInPointer) { if (!pInPointer) { return NullUniquePointer(); } else if (pInPointer.get_deleter() == &Heap::DeleteThat) { return AuUPtr)>(AuStaticCast(pInPointer.release()), &Heap::DeleteThatCastedOnce); } else { return NullUniquePointer(); } } namespace detail { inline AuSPtr AllocateArray(Heap *pHeap, AuUInt uLength, AuUInt32 uAlignment) { return pHeap->NewClassArray2(uLength, uAlignment); } } }