AuroraRuntime/Source/Debug/ErrorStack.cpp

208 lines
5.2 KiB
C++

/***
Copyright (C) 2022 J Reece Wilson (a/k/a "Reece"). All rights reserved.
File: ErrorStack.cpp
Date: 2022-11-29
Author: Reece
***/
#include <Source/RuntimeInternal.hpp>
#include "Debug.hpp"
#include "ErrorStack.hpp"
#if defined(AURORA_COMPILER_CLANG)
// warning: ISO C++20 considers use of overloaded operator '==' (with operand types 'AuSPtr<Aurora::Debug::ThreadMessage>' (aka 'ExSharedPtr<Aurora::Debug::ThreadMessage, std::shared_ptr<ThreadMessage>>') and 'AuSPtr<Aurora::Debug::ThreadMessage>' (aka 'ExSharedPtr<Aurora::Debug::ThreadMessage, std::shared_ptr<ThreadMessage>>')) 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<ThreadMessage> pHead)
{
pStack->pHead = pHead;
}
AuSPtr<ThreadMessage> GetHead(ErrorStack *pStack)
{
return pStack->pHead;
}
void SetOOM(ErrorStack *pStack)
{
pStack->bOutOfMemory = true;
}
};
AUKN_SYM const AuString &ThreadMessage::ToString()
{
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 "Unknown error.";
}
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<ThreadMessage> pMessage)
{
ErrorStackAccessor dumb;
if (!dumb.GetHead(pStack))
{
dumb.SetHead(pStack, pMessage);
return;
}
AuSPtr<ThreadMessage> 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<ThreadMessage> 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;
}
}
}
}