Refactored error handling

Now uses base error class which has an abstract function for overiding how it is displayed to the console.
This commit is contained in:
Pasha Bibko
2025-05-05 15:44:59 +01:00
parent a16ce34c8b
commit 616ed1ca21
26 changed files with 340 additions and 243 deletions

60
common/Console.h Normal file
View File

@@ -0,0 +1,60 @@
#pragma once
#define NOMINMAX
#include <Windows.h>
#include <iostream>
#include <string>
namespace LX
{
enum class Color
{
BLACK = 0,
BLUE = 1,
GREEN = 2,
AQUA = 3,
RED = 4,
PURPLE = 5,
YELLOW = 6,
LIGHT_GRAY = 7,
LIGHT_BLUE = 9,
LIGHT_GREEN = 10,
LIGHT_AQUA = 11,
LIGHT_RED = 12,
LIGHT_PURPLE = 13,
LIGHT_YELLOW = 14,
WHITE = 15
};
inline void PrintStringAsColor(const std::string& str, Color c)
{
// Gets a handle to the console //
static HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
// Sets the color of the console to the desired color //
SetConsoleTextAttribute(hConsole, (WORD)c);
// Outputs the text //
std::cout << str;
// Resets the color //
SetConsoleTextAttribute(hConsole, (WORD)Color::LIGHT_GRAY);
}
// Util function for getting a line of the source at a given index (used for errors) //
inline std::string GetLineAtIndexOf(const std::string src, const std::streamsize index)
{
// Finds the start of the line //
size_t start = src.rfind('\n', index);
if (start == std::string::npos) { start = 0; } // None means first line
else { start = start + 1; } // Skips new line char
// Finds the end of the line //
size_t end = src.find('\n', index);
if (end == std::string::npos) { end = src.size(); } // None means last line
// Returns the string between start and end //
return src.substr(start, end - start);
}
}

24
common/Error.h Normal file
View File

@@ -0,0 +1,24 @@
#pragma once
namespace LX
{
// Base error class for all LX thrown errors //
// Holds nothing apart from the v-table //
struct RuntimeError
{
// Prints the error to the console //
// Include Common/Console.h for printing util functions //
virtual void PrintToConsole() const = 0;
// Returns a C-String of the type that was thrown //
virtual const char* ErrorType() const = 0;
};
}
// Helper macro to autogenerate a basic error type in a .h file //
// Still requires function definitions in a .cpp file //
#define CREATE_EMPTY_LX_ERROR_TYPE(name)\
struct name : public LX::RuntimeError{ GENERATE_LX_ERROR_REQUIRED_FUNCTION_DECLARATIONS };
// Helper macro to autogenerate function declarations of functions required by LX::RuntimeError //
#define GENERATE_LX_ERROR_REQUIRED_FUNCTION_DECLARATIONS void PrintToConsole() const; const char* ErrorType() const;

31
common/ThrowIf.h Normal file
View File

@@ -0,0 +1,31 @@
#pragma once
// Type traits is included for std::is_base_of_v //
#include <type_traits>
namespace LX
{
// Foward declares LX::RuntimeError so it can be used to see if a class derives from //
struct RuntimeError;
// Util function to throw an error if the condition is met //
// Given error type must derive from LX::RuntimeError //
template<typename Error, typename... Args>
inline void ThrowIf(const bool condition, Args&&... args)
{
// Checks that the error type will be caught by the error checker //
static_assert
(
std::is_base_of_v<LX::RuntimeError, Error>,
"Must throw a type that derives from LX::RuntimeError"
);
// Checks if the condition is met and micro-optimises that errors will not be thrown //
if (condition) [[unlikely]]
{
// Throws a COPY of the error and not itself //
// How C++ works, no way around it //
throw Error(std::forward<Args>(args)...);
}
}
}