/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ExtendStlLikeSharedPtr.hpp Date: 2022-1-25 Author: Reece ***/ #pragma once namespace Aurora::Memory { namespace _detail { struct IPtrGet { virtual void *Get() = 0; }; struct IPtrNoOpGet : IPtrGet { inline virtual void *Get() override { AU_THROW_STRING("ExSharedPointer Null Access Violation"); } }; inline IPtrNoOpGet gNoop; } template struct ExSharedPtr : public Base_t #if !defined(_AURORA_NULLEXPT_ENABLE_UB) && !defined(_AURORA_NULLEXPT_BRANCH) , _detail::IPtrGet #endif { using element_type = Base_t::element_type; using weak_type = Base_t::weak_type; using base_type = Base_t; using Base_t::Base_t; ExSharedPtr(Base_t &&in) : Base_t(in) { #if !defined(_AURORA_NULLEXPT_ENABLE_UB) _cache(); #endif } ExSharedPtr(const Base_t &in) : Base_t(in) { #if !defined(_AURORA_NULLEXPT_ENABLE_UB) _cache(); #endif } void swap(Base_t &r) { Base_t::swap(r); #if !defined(_AURORA_NULLEXPT_ENABLE_UB) _cache(); #endif } void reset() { Base_t::reset(); #if !defined(_AURORA_NULLEXPT_BRANCH) ptr = &_detail::gNoop; #endif } operator Base_t() const noexcept { return *this; } ExSharedPtr &operator =(const Base_t &in) noexcept { Base_t::operator=(in); #if !defined(_AURORA_NULLEXPT_ENABLE_UB) _cache(); #endif return *this; } template TType2_t &operator*() const { return *operator->(); } template TType2_t *operator->() const { #if defined(_AURORA_NULLEXPT_ENABLE_UB) return Base_t::operator->(); #elif !defined(_AURORA_NULLEXPT_BRANCH) return AuReinterpretCast(ptr->Get()); #else throwif(); return Base_t::operator->(); #endif } template TType2_t &operator*() { return *operator->(); } template TType2_t *operator->() { #if defined(_AURORA_NULLEXPT_ENABLE_UB) return Base_t::operator->(); #elif !defined(_AURORA_NULLEXPT_BRANCH) return AuReinterpretCast(ptr->Get()); #else throwif(); return Base_t::operator->(); #endif } private: #if !defined(_AURORA_NULLEXPT_BRANCH) _detail::IPtrGet *ptr = this; inline virtual void *Get() override { return Base_t::operator->(); } auline void _cache() { if (Base_t::operator bool()) { ptr = this; } else { ptr = &_detail::gNoop; } } #else auline void _cache() { cached = Base_t::operator bool(); } auline void throwif() const { if (!cached) [[unlikely]] { if (!Base_t::operator bool()) [[likely]] { AU_THROW_STRING("ExSharedPointer Null Access Violation"); } } } auline void throwif() { if (!cached) [[unlikely]] { cached = Base_t::operator bool(); if (!cached) [[likely]] { AU_THROW_STRING("ExSharedPointer Null Access Violation"); } } } #endif }; template struct ExSharedFromThis : Base_t { ExSharedPtr> SharedFromThis() { return Base_t::shared_from_this(); } }; }