/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: auMemoryModel.hpp Date: 2022-2-1 File: AuroraUtils.hpp File: auROXTLUtils.hpp Date: 2021-6-9 Author: Reece ***/ #pragma once #include "auTypes.hpp" struct AuHeap; namespace __audetail { extern AuHeap *gDefaultDiscontiguousHeap; } namespace Aurora::Memory { struct ProxyHeap; } #if !defined(AURORA_RUNTIME_AU_SHARED_PTR) #define AURORA_RUNTIME_AU_SHARED_PTR std::shared_ptr #endif #if !defined(AURORA_RUNTIME_AU_WEAK_PTR) #define AURORA_RUNTIME_AU_WEAK_PTR std::weak_ptr #endif template using AuWPtr = AURORA_RUNTIME_AU_WEAK_PTR; #if !defined(AURORA_RUNTIME_AU_UNIQUE_PTR) #define AURORA_RUNTIME_AU_UNIQUE_PTR AuUniquePointer #endif #include #include "STLShims/ExtendStlLikeSharedPtr.hpp" template using AuSPtr = typename Aurora::Memory::ExSharedPtr>; template using AuSSPtr = typename AURORA_RUNTIME_AU_SHARED_PTR; template using AuUPtr = AURORA_RUNTIME_AU_UNIQUE_PTR; #if !defined(AU_AuEnableSharedFromThis) #define AU_AuEnableSharedFromThis template struct AuEnableSharedFromThis : Aurora::Memory::ExSharedFromThis> {}; #endif #if !defined(AURORA_RUNTIME_MAKE_SHARED) #define AURORA_RUNTIME_MAKE_SHARED std::make_shared #endif static inline AU_NORETURN void SysPanic(const char *pMsg); static auline void AuMemoryPanic(const char *msg) { #if defined(AURORA_RUNTIME_MEMORY_PANIC) AURORA_RUNTIME_MEMORY_PANIC(msg); #else SysPanic(msg); #endif } #include "MemoryModel/auArraySize.hpp" #include "MemoryModel/auSizeOf.hpp" #include "MemoryModel/auOffsetOf.hpp" template static auto AuTryLockMemoryType(T weak) -> decltype(weak.lock()) { if (weak.expired()) { return {}; } AUROXTL_COMMODITY_TRY { return weak.lock(); } AUROXTL_COMMODITY_CATCH { return {}; } } template static void auline AuSafeDelete(T *in) { static_assert(AuIsBaseOf_v>, "Couldn't not safe delete from type T because it is not derived from Z"); if (in == nullptr) { return; } delete static_cast(in); } #if !defined(AURORA_RUNTIME_AU_DEFAULT_DELETER) #define AURORA_RUNTIME_AU_DEFAULT_DELETER std::default_delete #endif template struct AuPMRAllocator; namespace Aurora::Memory { template struct CppHeapWrapper; #if defined(AURORA_ROXTL_ALLOCATORS_USE_STD) template using PrimitiveArrayAllocator = std::allocator; template using ClassArrayAllocator = std::allocator; template using StringAllocator = std::allocator; #else static void *__FAlloc(Types::size_t length, Types::size_t align); static void __Free(void *buffer); static AuUInt __SizeOf(void *pHead); template struct BaseAuroraRuntimeAllocator { typedef T value_type; AU_COPY_MOVE(BaseAuroraRuntimeAllocator) constexpr BaseAuroraRuntimeAllocator() noexcept { } template constexpr BaseAuroraRuntimeAllocator(const BaseAuroraRuntimeAllocator &) noexcept { } void *allocate_bytes(std::size_t nbytes, std::size_t alignment = alignof(std::max_align_t)) { if (auto pRet = __FAlloc(nbytes, alignment)) { return pRet; } else { throw std::bad_alloc(); } } void deallocate_bytes(void *p, std::size_t nbytes, std::size_t alignment = alignof(std::max_align_t)) { return __Free(p); } #if defined(AU_LANG_CPP_23) constexpr std::allocation_result allocate_at_least(const size_t count) { auto pThat = this->allocate(count); return { (T *)pThat, __SizeOf(pThat) / sizeof(T) }; } #endif template void construct(U *p, Args&&... args) { new ((void *)p) U(AuForward(args)...); } template void construct_at(U *p, Args&&... args) { new ((void *)p) U(AuForward(args)...); } void deallocate(const T *pType, const size_t count) { this->deallocate_bytes((void *)pType, 0, 0); } AU_ALLOC T *allocate(const size_t count) { if (!count) { return nullptr; } return (T *)this->allocate_bytes(count * sizeof(T), alignof(T)); } template U *allocate_object(std::size_t n = 1) { return (U *)this->allocate_bytes(sizeof(U) * n, alignof(U)); } template void deallocate_object(U *p, std::size_t n = 1) { this->deallocate_bytes(p, 0, 0); } template U *new_object(CtorArgs&&... args) { U *p = this->allocate_object(); try { this->construct(p, AuForward(args)...); } catch (...) { this->deallocate_object(p); throw; } return p; } template void delete_object(U *p) { if constexpr (AuIsClass_v && !AuIsTriviallyDestructible_v) { p->~U(); } this->deallocate_object(p); } template inline constexpr bool operator==(const Aurora::Memory::BaseAuroraRuntimeAllocator &rhs) noexcept { return true; } }; template using PrimitiveArrayAllocator = BaseAuroraRuntimeAllocator; template using ClassArrayAllocator = BaseAuroraRuntimeAllocator; template using StringAllocator = BaseAuroraRuntimeAllocator; template using SharedControlBlockAllocator = BaseAuroraRuntimeAllocator; template struct DefaultRuntimeDeleter { constexpr DefaultRuntimeDeleter() noexcept = default; template DefaultRuntimeDeleter(const DefaultRuntimeDeleter &) noexcept { } void operator()(T *pThat) const { if constexpr (AuIsClass_v && !AuIsTriviallyDestructible_v) { pThat->~T(); } Aurora::Memory::__Free(pThat); } }; template struct DefaultRuntimeDeleter { constexpr DefaultRuntimeDeleter() noexcept = default; template DefaultRuntimeDeleter(const DefaultRuntimeDeleter &) noexcept { } template void operator()(Z *pThat) const { AURORA_RUNTIME_AU_DEFAULT_DELETER()(pThat); } }; #endif } #if defined(AURORA_ROXTL_ALLOCATORS_USE_STD) template using AuDefaultDeleter = AURORA_RUNTIME_AU_DEFAULT_DELETER; #else template using AuDefaultDeleter = Aurora::Memory::DefaultRuntimeDeleter; #endif template AuSPtr AuMakeShared(Args&&... args); template static auline AuSPtr AuMakeSharedPanic(Args&&... args) { #if defined(AURORA_ROXTL_ALLOCATORS_USE_STD) try { auto pShared = AURORA_RUNTIME_MAKE_SHARED(AuForward(args)...); if (!pShared) { AuMemoryPanic("Failed to allocate "); // TODO: non-rtti typename } return pShared; } catch (...) { AuMemoryPanic("Failed to allocate "); // TODO: non-rtti typename return {}; } #else auto pShared = AuMakeShared(AuForward(args)...); if (!pShared) { AuMemoryPanic("Failed to allocate "); // TODO: non-rtti typename } return pShared; #endif } template static auline AuSPtr AuMakeSharedThrow(Args&&... args) { #if defined(AURORA_ROXTL_ALLOCATORS_USE_STD) try { auto pShared = AURORA_RUNTIME_MAKE_SHARED(AuForward(args)...); if (!pShared) { // TODO: Agnostic SysPushErrorMemory AU_THROW_STRING("Failed to allocate "); // TODO: non-rtti typename } return pShared; } catch (...) { // TODO: Agnostic SysPushErrorCatch AU_THROW_STRING("Failed to allocate "); // TODO: non-rtti typename return {}; } #else auto pShared = AuMakeShared(AuForward(args)...); if (!pShared) { AU_THROW_STRING("Failed to allocate "); // TODO: non-rtti typename } return pShared; #endif } template static auline AuSPtr AuMakeSharedArray(AuUInt count) { try { #if defined(AU_LANG_CPP_20) && 0 return AURORA_RUNTIME_AU_SHARED_PTR(count); #else return AURORA_RUNTIME_AU_SHARED_PTR(new T[count], AURORA_RUNTIME_AU_DEFAULT_DELETER()); #endif } catch (...) { return {}; } } namespace __audetail { struct Dummy { char a; }; inline AuSPtr gDummy; inline AuSPtr GetDummyDeleter() { if (!gDummy) { #if defined(AURORA_COMPILER_MSVC) return gDummy; #endif gDummy = AuMakeShared(); } return gDummy; } } template static AuSPtr AuUnsafeRaiiToShared(T *in) { return AuSPtr(__audetail::GetDummyDeleter(), in); } template static AuSPtr AuUnsafeRaiiToShared(const AuUPtr &in) { return AuUnsafeRaiiToShared(in.get()); } template inline constexpr bool operator==(const Aurora::Memory::BaseAuroraRuntimeAllocator &lhs, const Aurora::Memory::BaseAuroraRuntimeAllocator &rhs) noexcept { return true; } template inline constexpr bool operator!=(const Aurora::Memory::BaseAuroraRuntimeAllocator &lhs, const Aurora::Memory::BaseAuroraRuntimeAllocator &rhs) noexcept { return false; } #include #include #include #include #include #include #include