/*** Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved. File: ErrorStack.cpp Date: 2022-11-29 Author: Reece ***/ #include #include "Debug.hpp" #include "ErrorStack.hpp" #if defined(AURORA_COMPILER_CLANG) // warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'AuSPtr' (aka 'ExSharedPtr>') and 'AuSPtr' (aka 'ExSharedPtr>')) to be ambiguous despite there being a unique best viable function [-Wambiguous-reversed-operator] #pragma clang diagnostic ignored "-Wambiguous-reversed-operator" // Yea, I couldn't give less of a nanoshit what some C++20 spec says. Even llvm/clang doesn't care to language police it into a fatal unimplemented compiler condition. So, idc. #endif namespace Aurora::Debug { static thread_local AuString tlsLastMessageError; static AuString strFailureCategoryCache[128]; struct ErrorStackAccessor { void SetNext(ErrorStack *pStack, ErrorStack *pNext) { pStack->pNext = pNext; } ErrorStack *GetNext(ErrorStack *pStack) { return pStack->pNext; } void SetHead(ErrorStack *pStack, AuSPtr pHead) { pStack->pHead = pHead; } AuSPtr GetHead(ErrorStack *pStack) { return pStack->pHead; } void SetOOM(ErrorStack *pStack) { pStack->bOutOfMemory = true; } }; AUKN_SYM const AuString &ThreadMessage::ToString() { static const AuString kUnknownError = "Unknown Error."; if (this->pStringMessage) { return *this->pStringMessage; } if (eFailureCategory) { auto uIndex = (AuUInt)*eFailureCategory; if (AuArraySize(strFailureCategoryCache) <= uIndex) { return tlsLastMessageError = fmt::format("Debug::EFailureCategory = {}", (AuUInt)*eFailureCategory); } else { auto &stringBuffer = strFailureCategoryCache[uIndex]; if (stringBuffer.size()) { return stringBuffer; } else { return stringBuffer = fmt::format("Debug::EFailureCategory = {}", (AuUInt)*eFailureCategory); } } } if (optOsErrorCode) { return tlsLastMessageError = fmt::format("OS = {}", (AuUInt)*optOsErrorCode); } return kUnknownError; } static thread_local ErrorStack *tlsErrorStackBase; AUKN_SYM ErrorStack::ErrorStack() { auto pStack = this; if (!tlsErrorStackBase) { tlsErrorStackBase = pStack; return; } ErrorStackAccessor dumb; auto itr = tlsErrorStackBase; while (auto pNext = dumb.GetNext(itr)) { itr = pNext; } dumb.SetNext(itr, pStack); } AUKN_SYM ErrorStack::~ErrorStack() { auto pStack = this; if (!tlsErrorStackBase) { return; } ErrorStackAccessor dumb; auto itr = tlsErrorStackBase; if (itr == pStack) { tlsErrorStackBase = nullptr; return; } while (auto pNext = dumb.GetNext(itr)) { if (pNext == pStack) { dumb.SetNext(pStack, {}); return; } itr = pNext; } } static void AddToInstance(ErrorStack *pStack, AuSPtr pMessage) { ErrorStackAccessor dumb; if (!dumb.GetHead(pStack)) { dumb.SetHead(pStack, pMessage); return; } AuSPtr pMessage2 { dumb.GetHead(pStack) }; if (pMessage2 == pMessage) { return; } while (auto pNext = pMessage2->pNextThreadMesage) { if (pNext == pMessage) { return; } pMessage2 = pNext; } pMessage2->pNextThreadMesage = pMessage; } ////////////////////////////////////////////////////////////////// // internal api: bool ShouldPushErrorStackInternal() { return bool(tlsErrorStackBase); } void PushErrorStackInternal(AuSPtr pMessage) { ErrorStackAccessor dumb; auto itr = tlsErrorStackBase; if (itr) { AddToInstance(itr, pMessage); while (auto pNext = dumb.GetNext(itr)) { AddToInstance(itr, pMessage); itr = pNext; } } } void OnOutOfMemory() { ErrorStackAccessor dumb; auto itr = tlsErrorStackBase; if (itr) { dumb.SetOOM(itr); while (auto pNext = dumb.GetNext(itr)) { dumb.SetOOM(itr); itr = pNext; } } } }