136 lines
4.0 KiB
C++
136 lines
4.0 KiB
C++
#pragma once
|
|
|
|
#include <modules/OS.h>
|
|
|
|
#include <type_traits>
|
|
#include <cstdlib>
|
|
|
|
namespace LXC::Util
|
|
{
|
|
// Util function to stop the program //
|
|
inline void Stop()
|
|
{
|
|
// Only checks for a debugger when compiled in Debug mode //
|
|
#ifdef _DEBUG
|
|
|
|
// Triggers a breakpoint so the debugger can work out where the program exits //
|
|
if (IsDebuggerPresent())
|
|
DebugBreak();
|
|
|
|
#endif // _DEBUG
|
|
|
|
// Force exits the program //
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// Custom version of std::unexpected //
|
|
template<typename ErrorType> struct FunctionFail final
|
|
{
|
|
// Basic constructor to copy the error across //
|
|
explicit FunctionFail(ErrorType _err) : error(_err)
|
|
{
|
|
// Only checks for a debugger when compiled in Debug mode //
|
|
#ifdef _DEBUG
|
|
|
|
// Triggers a breakpoint when a debugger is attached as a function has failed //
|
|
if (IsDebuggerPresent())
|
|
DebugBreak();
|
|
|
|
#endif // _DEBUG
|
|
}
|
|
|
|
// Constructs the FunctionFail with the error itself //
|
|
template<typename... Args> requires std::constructible_from<ErrorType, Args...>
|
|
explicit FunctionFail(Args&&... args)
|
|
: error(std::forward<Args>(args)...)
|
|
{
|
|
// Only checks for a debugger when compiled in Debug mode //
|
|
#ifdef _DEBUG
|
|
|
|
// Triggers a breakpoint when a debugger is attached as a function has failed //
|
|
if (IsDebuggerPresent())
|
|
DebugBreak();
|
|
|
|
#endif // _DEBUG
|
|
}
|
|
|
|
const ErrorType error;
|
|
};
|
|
|
|
// Custom version of std::expected //
|
|
template<typename ResultType, typename ErrorType>
|
|
requires (!std::same_as<ResultType, bool>) // ResultType being bool causes issues with operator overloads
|
|
class ReturnVal final
|
|
{
|
|
public:
|
|
// Constructor for function sucess //
|
|
ReturnVal(const ResultType& result)
|
|
: m_Result(result), m_FunctionFailed(false)
|
|
{}
|
|
|
|
// Move constructor (for large objects) //
|
|
ReturnVal(ResultType&& result)
|
|
: m_Result(std::move(result)), m_FunctionFailed(false)
|
|
{}
|
|
|
|
// Constructor for function fail //
|
|
ReturnVal(FunctionFail<ErrorType> error)
|
|
: m_Error(error.error), m_FunctionFailed(true)
|
|
{}
|
|
|
|
// Constructor to support upcasting //
|
|
template<typename Other>
|
|
requires std::is_convertible_v<Other, ResultType>
|
|
ReturnVal(ReturnVal<Other, ErrorType>&& other)
|
|
: m_FunctionFailed(other.m_FunctionFailed)
|
|
{
|
|
// Transfers the correct member of the union //
|
|
if (m_FunctionFailed)
|
|
m_Error = std::move(other.m_Error);
|
|
|
|
else
|
|
m_Result = std::move(other.m_Result);
|
|
}
|
|
|
|
// Destructor //
|
|
~ReturnVal() {};
|
|
|
|
// Different getters of the class //
|
|
|
|
inline bool Failed() const { return m_FunctionFailed; }
|
|
inline bool Suceeded() const { return !m_FunctionFailed; }
|
|
|
|
inline ResultType& Result()
|
|
{
|
|
if (Suceeded()) _LIKELY
|
|
return m_Result;
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
|
|
inline ErrorType& Error()
|
|
{
|
|
if (Failed()) _LIKELY
|
|
return m_Error;
|
|
|
|
std::exit(EXIT_FAILURE);
|
|
}
|
|
|
|
// Operator overloads //
|
|
|
|
explicit operator bool() const { return !m_FunctionFailed; }
|
|
operator ResultType&() { return Result(); }
|
|
|
|
private:
|
|
// Union to hold either the result or the error //
|
|
union
|
|
{
|
|
ResultType m_Result;
|
|
ErrorType m_Error;
|
|
};
|
|
|
|
// Tracks what item is currently in the union //
|
|
bool m_FunctionFailed;
|
|
};
|
|
}
|