diff --git a/Common/FileRead.h b/Common/FileRead.h index 1d8157e..b4d913c 100644 --- a/Common/FileRead.h +++ b/Common/FileRead.h @@ -5,6 +5,7 @@ namespace LXC::Util { + // Error returned when Util::ReadFile runs into errors // struct FileReadError { // Different reasons why the error can occur // @@ -38,20 +39,21 @@ namespace LXC::Util } }; + // Util function to read a file as quick as possible with error handling // inline ReturnVal ReadFile(const std::filesystem::path& filepath) { // Checks the file exists // if (!std::filesystem::exists(filepath)) - return FunctionFail(FileReadError(std::filesystem::absolute(filepath), FileReadError::FileNotFound)); + return FunctionFail(std::filesystem::absolute(filepath), FileReadError::FileNotFound); // Checks it is a regular file // if (!std::filesystem::is_regular_file(filepath)) - return FunctionFail(FileReadError(std::filesystem::absolute(filepath), FileReadError::NotAFile)); + return FunctionFail(std::filesystem::absolute(filepath), FileReadError::NotAFile); // Checks it can open the file // std::ifstream file(filepath, std::ios::binary | std::ios::ate); if (!file) - return FunctionFail(FileReadError(std::filesystem::absolute(filepath), FileReadError::PermissionDenied)); + return FunctionFail(std::filesystem::absolute(filepath), FileReadError::PermissionDenied); // Copies the file to the output string // const std::streamsize len = file.tellg(); diff --git a/Common/IO.h b/Common/IO.h index 4874309..4879cff 100644 --- a/Common/IO.h +++ b/Common/IO.h @@ -6,18 +6,32 @@ #include #include -namespace LXC::Internal +namespace LXC::Util { - // Returns a reference to the log file // - // To be used only by LXC components // - inline std::ofstream& Log() + // Enum to translate to the Win32 code for the colors // + enum Color : WORD { - static std::ofstream sLog; - return sLog; - } + DEFAULT = 0x07, + + BLACK = 0x00, + BLUE = 0x01, + GREEN = 0x02, + AQUA = 0x03, + RED = 0x04, + PURPLE = 0x05, + YELLOW = 0x06, + LIGHT_GRAY = 0x07, + LIGHT_BLUE = 0x09, + LIGHT_GREEN = 0x0a, + LIGHT_AQUA = 0x0b, + LIGHT_RED = 0x0c, + LIGHT_PURPLE = 0x0d, + LIGHT_YELLOW = 0x0e, + WHITE = 0x0f + }; } -namespace LXC::Util +namespace LXC::Internal { // Checks if a type can be outputted to std::ostream // template concept Logable = requires(std::ostream& os, T t) @@ -36,57 +50,81 @@ namespace LXC::Util { obj.LogStr() } -> std::same_as; }; - // Enum to translate to the Win32 code for the colors // - enum Color : WORD + // Returns a reference to the log file // + inline std::ofstream& Log() { - BLACK = 0x00, - BLUE = 0x01, - GREEN = 0x02, - AQUA = 0x03, - RED = 0x04, - PURPLE = 0x05, - YELLOW = 0x06, - LIGHT_GRAY = 0x07, - LIGHT_BLUE = 0x09, - LIGHT_GREEN = 0x0a, - LIGHT_AQUA = 0x0b, - LIGHT_RED = 0x0c, - LIGHT_PURPLE = 0x0d, - LIGHT_YELLOW = 0x0e, - WHITE = 0x0f - }; + static std::ofstream sLog; + return sLog; + } + // Base function for all derived Print() functions // + template + inline void WriteImpl(std::ostream& os, Args&&... args) + { + static HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); + if constexpr(col != Util::Color::DEFAULT) + SetConsoleTextAttribute(hConsole, static_cast(col)); + + (os << ... << std::forward(args)); + + if constexpr (newLine) + os << std::endl; + + if constexpr (col != Util::Color::DEFAULT) + SetConsoleTextAttribute(hConsole, static_cast(Util::Color::DEFAULT)); + } +} + +namespace LXC::Util +{ // Prints arguments to the console with the given color // template - requires AllLogable - inline void PrintAs(Args... args) + requires Internal::AllLogable + inline void PrintAs(Args&&... args) { - // Permenant handle to the console // - static HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE); - - // Prints it to the console and resets the color // - SetConsoleTextAttribute(hConsole, (WORD)col); - (std::cout << ... << args); - SetConsoleTextAttribute(hConsole, (WORD)Color::LIGHT_GRAY); + Internal::WriteImpl(std::cout, std::forward(args)...); } // Prints arguments to the console // template - requires AllLogable - inline void Print(Args... args) + requires Internal::AllLogable + inline void Print(Args&&... args) { - // Fowards the arguments to the console // - (std::cout << ... << args); + Internal::WriteImpl(std::cout, std::forward(args)...); } // Prints arguments to the console with a new-line character at the end // template - requires AllLogable - inline void PrintLn(Args... args) + requires Internal::AllLogable + inline void PrintLn(Args&&... args) { - // Fowards the arguments to the console // - (std::cout << ... << args); - std::cout << std::endl; + Internal::WriteImpl(std::cout, std::forward(args)...); + } + + // Logs all the arguments to the file (automatically flushes) // + template + requires Internal::AllLogable && (sizeof...(Args) > 1) + inline void Log(Args&&... args) + { + std::ofstream& log = Internal::Log(); + if (log.is_open()) _UNLIKELY + Internal::WriteImpl(log, R"([LXC] ")", std::forward(args)..., '"'); + } + + // Logs a singular argument to the log, calls Log() if it can on the object // + template + requires Internal::HasLogStrFunc || Internal::Logable + inline void Log(T arg) + { + std::ofstream& log = Internal::Log(); + if (log.is_open()) _UNLIKELY + { + if constexpr (Internal::HasLogStrFunc) + Internal::WriteImpl(log, "[LXC] ", '{', arg.LogStr(), '}'); + + else + Internal::WriteImpl(log, "[LXC] ", '"', arg, '"'); + } } // Intitalises the log with the given file name // @@ -103,55 +141,4 @@ namespace LXC::Util log.close(); }); } - - // Logs all the arguments to the file (automatically flushes) // - template - requires AllLogable && (sizeof...(Args) > 1) - inline void Log(Args... args) - { - std::ofstream& log = Internal::Log(); - - // Only attempts to write to an open log // - if (log.is_open()) _UNLIKELY - { - // Opening symbol to make the log look fancy // - log << "[LXC] \""; - - // Fowards the arguments to the log and flushes // - (log << ... << args); - log << "\"\n"; - log.flush(); - } - } - - // Logs a singular argument to the log, calls Log() if it can on the object // - template - requires HasLogStrFunc || Logable - inline void Log(T arg) - { - std::ofstream& log = Internal::Log(); - - // Only attempts to write to an open log // - if (log.is_open()) _UNLIKELY - { - // Opening symbol to make log look fancy // - log << "[LXC] "; - - // Logic if it can call LogStr() // - if constexpr (HasLogStrFunc) - { - // Prints the generated string // - log << '{' << arg.LogStr() << "}\n"; - log.flush(); - } - - // Default logic // - else - { - // Prints the singular arg // - log << '"' << arg << "\"\n"; - log.flush(); - } - } - } } diff --git a/Common/Result.h b/Common/Result.h index d1c5698..14630b0 100644 --- a/Common/Result.h +++ b/Common/Result.h @@ -24,10 +24,10 @@ namespace LXC::Util } // Custom version of std::unexpected // - template struct FunctionFail + template struct FunctionFail final { - explicit FunctionFail(ErrorType _err) - : error(_err) + // 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 @@ -39,13 +39,28 @@ namespace LXC::Util #endif // _DEBUG } - ErrorType error; + // Constructs the FunctionFail with the error itself // + template requires std::constructible_from + explicit FunctionFail(Args&&... args) + : error(std::forward(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 requires (!std::same_as) // ResultType being bool causes issues with operator overloads - class ReturnVal + class ReturnVal final { public: // Constructor for function sucess //