From 24a15c3a3d06064539f8eadb1a7e0f4a500402d5 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Fri, 21 Nov 2025 19:47:55 +0100 Subject: [PATCH 1/9] fix: Don't overwrite previous console mode --- scroll/ConsoleLogger/ConsoleLogger.ipp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/scroll/ConsoleLogger/ConsoleLogger.ipp b/scroll/ConsoleLogger/ConsoleLogger.ipp index c4ddc9e..615bcee 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.ipp +++ b/scroll/ConsoleLogger/ConsoleLogger.ipp @@ -36,7 +36,19 @@ namespace scroll { const HANDLE hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); ATL_ASSERT(hConsoleHandle != NULL && hConsoleHandle != INVALID_HANDLE_VALUE); - ATL_ASSERT(SetConsoleMode(hConsoleHandle, ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING) > 0); + + BOOL result = FALSE; + DWORD mode; + + result = GetConsoleMode(hConsoleHandle, &mode); + + ATL_ASSERT(result > 0); + + mode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; + + result = SetConsoleMode(hConsoleHandle, mode); + + ATL_ASSERT(result > 0); #endif } From a5417be5df499690973c1de9ae7638261e01c109 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sat, 22 Nov 2025 22:19:00 +0100 Subject: [PATCH 2/9] perf: Optimize log time --- Base | 2 +- scroll/ConsoleLogger/ConsoleLogger.hpp | 54 +++++- scroll/ConsoleLogger/ConsoleLogger.ipp | 221 +++++++++++-------------- scroll/FileLogger/FileLogger.hpp | 24 ++- scroll/FileLogger/FileLogger.ipp | 166 +++++++++++-------- scroll/Logger/Logger.hpp | 186 +++++++++++++++++++-- scroll/Logger/Logger.ipp | 124 +++----------- scroll/base.hpp | 5 +- 8 files changed, 466 insertions(+), 316 deletions(-) diff --git a/Base b/Base index 367e49e..fd8417f 160000 --- a/Base +++ b/Base @@ -1 +1 @@ -Subproject commit 367e49e1c9c47505e82250ee72a61a1154e3a48e +Subproject commit fd8417f2c24e7191955812c54c34fe34123ce01c diff --git a/scroll/ConsoleLogger/ConsoleLogger.hpp b/scroll/ConsoleLogger/ConsoleLogger.hpp index 58925e5..9a45fe3 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.hpp +++ b/scroll/ConsoleLogger/ConsoleLogger.hpp @@ -9,14 +9,9 @@ namespace scroll { class ConsoleLogger : public Logger { - private: - static void writeLogHeader(std::ostream& stream, view source, view levelName, ConsoleEscapeCode levelBackgroundColor, ConsoleEscapeCode levelForegroundColor); - public: explicit ConsoleLogger(std::ostream& stream, LogLevel minLogLevel, view source); - ~ConsoleLogger(); - std::ostream& getOutputStream(); void setOutputStream(std::ostream& stream); @@ -29,10 +24,10 @@ namespace scroll { ConsoleLogger& padRight(uint64 padding); template - void trace(view file, uint32 line, Argument&& argument); + void trace(view file, uint64 line, Argument&& argument); template - void trace(view file, uint32 line, view pattern, Argument&&... arguments); + void trace(view file, uint64 line, view pattern, Argument&&... arguments); template void debug(Argument&& argument); @@ -58,8 +53,53 @@ namespace scroll { template void error(view function, view file, uint64 line, view pattern, Argument&&... arguments); + private: + #if ATL_OPERATING_SYSTEM == ATL_OPERATING_SYSTEM_WINDOWS + void setConsoleMode(DWORD nStdHandle) { + const HANDLE hConsoleHandle = GetStdHandle(nStdHandle); + + ATL_ASSERT(hConsoleHandle != NULL && hConsoleHandle != INVALID_HANDLE_VALUE); + + BOOL result = FALSE; + DWORD mode; + + result = GetConsoleMode(hConsoleHandle, &mode); + + if (result == 0) { + redirected = true; + + return; + } + + result = SetConsoleMode(hConsoleHandle, mode | ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING); + + ATL_ASSERT(result > 0); + } + #endif + + template + uint64 writeConsoleLog(view level, uint64 levelSize, view pattern, Argument&&... arguments); + + template + void writeTraceLog(view file, uint64 line, view pattern, Argument&&... arguments); + + template + void writeDebugLog(view pattern, Argument&&... arguments); + + template + void writeInfoLog(view pattern, Argument&&... arguments); + + template + void writeWarningLog(view pattern, Argument&&... arguments); + + template + void writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments); + + void flushLog(uint64 size) const; + private: std::ostream* stream; + bool redirected = false; bool writingEscapeCodes = false; }; } diff --git a/scroll/ConsoleLogger/ConsoleLogger.ipp b/scroll/ConsoleLogger/ConsoleLogger.ipp index 615bcee..b0ed905 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.ipp +++ b/scroll/ConsoleLogger/ConsoleLogger.ipp @@ -2,27 +2,12 @@ // Licensed under MIT. namespace scroll { - inline void ConsoleLogger::writeLogHeader(std::ostream& stream, view source, view levelName, ConsoleEscapeCode levelBackgroundColor, ConsoleEscapeCode levelForegroundColor) { - stream << "\033[" << ConsoleEscapeCode::DIMMED << "m[" << timestamp() << "]\033[" << ConsoleEscapeCode::RESET_BRIGHT << "m "; - - if (source.count() > 0) { - stream << source << ' '; - } - - stream << "\033[" << levelBackgroundColor << ';' << levelForegroundColor << "m " << levelName << ' '; - stream << "\033[" << ConsoleEscapeCode::RESET_BACKGROUND_COLOR << ';' << ConsoleEscapeCode::RESET_FOREGROUND_COLOR << "m "; - } - - inline ConsoleLogger::ConsoleLogger(std::ostream& stream, LogLevel minimumLogLevel, view source) : - Logger(minimumLogLevel, source) + inline ConsoleLogger::ConsoleLogger(std::ostream& stream, LogLevel minLogLevel, view source) : + Logger(minLogLevel, source) { - setOutputStream(stream); - } - - inline ConsoleLogger::~ConsoleLogger() { - if (writingEscapeCodes) { - stream->write("m", 1); - } + #if ATL_OPERATING_SYSTEM == ATL_OPERATING_SYSTEM_WINDOWS + setConsoleMode(STD_OUTPUT_HANDLE); + #endif } inline std::ostream& ConsoleLogger::getOutputStream() { @@ -31,25 +16,6 @@ namespace scroll { inline void ConsoleLogger::setOutputStream(std::ostream& stream) { this->stream = &stream; - - #if ATL_OPERATING_SYSTEM == ATL_OPERATING_SYSTEM_WINDOWS - const HANDLE hConsoleHandle = GetStdHandle(STD_OUTPUT_HANDLE); - - ATL_ASSERT(hConsoleHandle != NULL && hConsoleHandle != INVALID_HANDLE_VALUE); - - BOOL result = FALSE; - DWORD mode; - - result = GetConsoleMode(hConsoleHandle, &mode); - - ATL_ASSERT(result > 0); - - mode |= ENABLE_PROCESSED_OUTPUT | ENABLE_VIRTUAL_TERMINAL_PROCESSING; - - result = SetConsoleMode(hConsoleHandle, mode); - - ATL_ASSERT(result > 0); - #endif } template @@ -94,142 +60,157 @@ namespace scroll { } template - void ConsoleLogger::trace(view file, uint32 line, Argument&& argument) { - if (LogLevel::TRACE < minLogLevel) { - return; - } - - std::ostream& stream = std::cerr; + inline void ConsoleLogger::trace(view file, uint64 line, Argument&& argument) { + writeTraceLog(file, line, argumentInjectionPattern, std::forward(argument)); + } - writeLogHeader(stream, source, "TRACE", ConsoleEscapeCode::BACKGROUND_COLOR_WHITE, ConsoleEscapeCode::FOREGROUND_COLOR_BLACK); - writeIndented(stream, format("[] (at []:[])", format(std::forward(argument)), file, line), getLogIndentation() - 2); + template + inline void ConsoleLogger::trace(view file, uint64 line, view pattern, Argument&&... arguments) { + writeTraceLog(file, line, pattern, std::forward(arguments)...); + } - stream << '\n'; + template + inline void ConsoleLogger::debug(Argument&& argument) { + writeDebugLog(argumentInjectionPattern, std::forward(argument)); } template - void ConsoleLogger::trace(view file, uint32 line, view pattern, Argument&&... arguments) { - if (LogLevel::TRACE < minLogLevel) { - return; - } + inline void ConsoleLogger::debug(view pattern, Argument&&... arguments) { + writeDebugLog(pattern, std::forward(arguments)...); + } + + template + inline void ConsoleLogger::info(Argument&& argument) { + writeInfoLog(argumentInjectionPattern, std::forward(argument)); + } - std::ostream& stream = std::cerr; + template + inline void ConsoleLogger::info(view pattern, Argument&&... arguments) { + writeInfoLog(pattern, std::forward(arguments)...); + } - writeLogHeader(stream, source, "TRACE", ConsoleEscapeCode::BACKGROUND_COLOR_WHITE, ConsoleEscapeCode::FOREGROUND_COLOR_BLACK); - writeIndented(stream, format("[] (at []:[])", format(pattern, std::forward(arguments)...), file, line), getLogIndentation() - 2); + template + inline void ConsoleLogger::warning(Argument&& argument) { + writeWarningLog(argumentInjectionPattern, std::forward(argument)); + } - stream << '\n'; + template + inline void ConsoleLogger::warning(view pattern, Argument&&... arguments) { + writeWarningLog(pattern, std::forward(arguments)...); } template - void ConsoleLogger::debug(Argument&& argument) { - if (LogLevel::DEBUG < minLogLevel) { - return; - } + inline void ConsoleLogger::error(view function, view file, uint64 line, Argument&& argument) { + writeErrorLog(function, file, line, argumentInjectionPattern, std::forward(argument)); + } - std::ostream& stream = std::cerr; + template + inline void ConsoleLogger::error(view function, view file, uint64 line, view pattern, Argument&&... arguments) { + writeErrorLog(function, file, line, pattern, std::forward(arguments)...); + } - writeLogHeader(stream, source, "DEBUG", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_GRAY, ConsoleEscapeCode::FOREGROUND_COLOR_BLACK); - writeIndented(stream, format(std::forward(argument)), getLogIndentation() - 2); + template + inline uint64 ConsoleLogger::writeConsoleLog(view level, uint64 levelSize, view pattern, Argument&&... arguments) { + static constexpr view LOG_BUFFER_TEMPLATE = "\033[2m[00:00:00.000000]\033[22m "; - stream << '\n'; + return writeLog(5, LOG_BUFFER_TEMPLATE, level, levelSize, pattern, std::forward(arguments)...); } template - void ConsoleLogger::debug(view pattern, Argument&&... arguments) { - if (LogLevel::DEBUG < minLogLevel) { + inline void ConsoleLogger::writeTraceLog(view file, uint64 line, view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "\033[107;30m TRACE \033[49;39m "; + + if (LogLevel::TRACE < minLogLevel || redirected) { return; } - std::ostream& stream = std::cerr; + uint64 offset = writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); + + write(" (at ", offset); + write(file, offset); + write(':', offset); - writeLogHeader(stream, source, "DEBUG", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_GRAY, ConsoleEscapeCode::FOREGROUND_COLOR_BLACK); - writeIndented(stream, format(pattern, std::forward(arguments)...), getLogIndentation() - 2); + const std::string formattedLine = toString(line); - stream << '\n'; + write(&formattedLine[0], offset); + write(')', offset); + write('\n', offset); + + flushLog(offset); } - template - void ConsoleLogger::info(Argument&& argument) { - if (LogLevel::INFO < minLogLevel) { + template + inline void ConsoleLogger::writeDebugLog(view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "\033[47;30m DEBUG \033[49;39m "; + + if (LogLevel::DEBUG < minLogLevel || redirected) { return; } - std::ostream& stream = std::cout; + uint64 offset = writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); - writeLogHeader(stream, source, "INFO", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_BLUE, ConsoleEscapeCode::FOREGROUND_COLOR_WHITE); - writeIndented(stream, format(std::forward(argument)), getLogIndentation() - 3); + write('\n', offset); - stream << '\n'; + flushLog(offset); } template - void ConsoleLogger::info(view pattern, Argument&&... arguments) { - if (LogLevel::INFO < minLogLevel) { + inline void ConsoleLogger::writeInfoLog(view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "\033[104;97m INFO \033[49;39m "; + + if (LogLevel::INFO < minLogLevel || redirected) { return; } - std::ostream& stream = std::cout; + uint64 offset = writeConsoleLog(LOG_LEVEL, 7, pattern, std::forward(arguments)...); - writeLogHeader(stream, source, "INFO", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_BLUE, ConsoleEscapeCode::FOREGROUND_COLOR_WHITE); - writeIndented(stream, format(pattern, std::forward(arguments)...), getLogIndentation() - 3); + write('\n', offset); - stream << '\n'; + flushLog(offset); } - template - void ConsoleLogger::warning(Argument&& argument) { - if (LogLevel::WARNING < minLogLevel) { + template + inline void ConsoleLogger::writeWarningLog(view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "\033[103;30m WARNING \033[49;39m \033[93m"; + + if (LogLevel::WARNING < minLogLevel || redirected) { return; } - std::ostream& stream = std::cerr; + uint64 offset = writeConsoleLog(LOG_LEVEL, 9, pattern, std::forward(arguments)...); - writeLogHeader(stream, source, "WARNING", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_YELLOW, ConsoleEscapeCode::FOREGROUND_COLOR_BLACK); - stream << "\033[" << ConsoleEscapeCode::FOREGROUND_COLOR_LIGHT_YELLOW << 'm'; - writeIndented(stream, format(std::forward(argument)), getLogIndentation()); - stream << "\033[" << ConsoleEscapeCode::RESET_FOREGROUND_COLOR << "m\n"; + write("\033[39m\n", offset); + + flushLog(offset); } template - void ConsoleLogger::warning(view pattern, Argument&&... arguments) { - if (LogLevel::WARNING < minLogLevel) { + inline void ConsoleLogger::writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "\033[101;97m ERROR \033[49;39m \033[91m"; + + if (LogLevel::ERROR < minLogLevel || redirected) { return; } - std::ostream& stream = std::cerr; + uint64 offset = writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); - writeLogHeader(stream, source, "WARNING", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_YELLOW, ConsoleEscapeCode::FOREGROUND_COLOR_BLACK); - stream << "\033[" << ConsoleEscapeCode::FOREGROUND_COLOR_LIGHT_YELLOW << 'm'; - writeIndented(stream, format(pattern, std::forward(arguments)...), getLogIndentation()); - stream << "\033[" << ConsoleEscapeCode::RESET_FOREGROUND_COLOR << "m\n"; - } + write(" (in ", offset); + write(function, offset); + write(", at ", offset); + write(file, offset); + write(':', offset); - template - void ConsoleLogger::error(view function, view file, uint64 line, Argument&& argument) { - if (LogLevel::ERROR < minLogLevel) { - return; - } + const std::string formattedLine = toString(line); - std::ostream& stream = std::cerr; + write(&formattedLine[0], offset); + write(")\033[39m\n", offset); - writeLogHeader(stream, source, "ERROR", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_RED, ConsoleEscapeCode::FOREGROUND_COLOR_WHITE); - stream << "\033[" << ConsoleEscapeCode::FOREGROUND_COLOR_LIGHT_RED << 'm'; - writeIndented(stream, format("[] (in [], at []:[])", format(std::forward(argument)), function, file, line), getLogIndentation() - 2); - stream << "\033[" << ConsoleEscapeCode::RESET_FOREGROUND_COLOR << "m\n"; + flushLog(offset); } - template - void ConsoleLogger::error(view function, view file, uint64 line, view pattern, Argument&&... arguments) { - if (LogLevel::ERROR < minLogLevel) { - return; - } - - std::ostream& stream = std::cerr; + inline void ConsoleLogger::flushLog(uint64 size) const { + ATL_ASSERT(size <= MAX_LOG_BUFFER_SIZE); - writeLogHeader(stream, source, "ERROR", ConsoleEscapeCode::BACKGROUND_COLOR_LIGHT_RED, ConsoleEscapeCode::FOREGROUND_COLOR_WHITE); - stream << "\033[" << ConsoleEscapeCode::FOREGROUND_COLOR_LIGHT_RED << 'm'; - writeIndented(stream, format("[] (in [], at []:[])", format(pattern, std::forward(arguments)...), function, file, line), getLogIndentation() - 2); - stream << "\033[" << ConsoleEscapeCode::RESET_FOREGROUND_COLOR << "m\n"; + std::clog.write(&logBuffer[0], size); } } \ No newline at end of file diff --git a/scroll/FileLogger/FileLogger.hpp b/scroll/FileLogger/FileLogger.hpp index 2daef70..a3f79a7 100644 --- a/scroll/FileLogger/FileLogger.hpp +++ b/scroll/FileLogger/FileLogger.hpp @@ -12,10 +12,10 @@ namespace scroll { explicit FileLogger(std::ofstream& stream, LogLevel minLogLevel, view source); template - void trace(view file, uint32 line, Argument&& argument); + void trace(view file, uint64 line, Argument&& argument); template - void trace(view file, uint32 line, view pattern, Argument&&... arguments); + void trace(view file, uint64 line, view pattern, Argument&&... arguments); template void debug(Argument&& argument); @@ -42,7 +42,25 @@ namespace scroll { void error(view function, view file, uint64 line, view pattern, Argument&&... arguments); private: - void writeLogHeader(view levelName); + template + uint64 writeFileLog(view level, view pattern, Argument&&... arguments); + + template + void writeTraceLog(view file, uint64 line, view pattern, Argument&&... arguments); + + template + void writeDebugLog(view pattern, Argument&&... arguments); + + template + void writeInfoLog(view pattern, Argument&&... arguments); + + template + void writeWarningLog(view pattern, Argument&&... arguments); + + template + void writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments); + + void flushLog(uint64 size); public: std::ofstream& stream; diff --git a/scroll/FileLogger/FileLogger.ipp b/scroll/FileLogger/FileLogger.ipp index 1d5d309..65763d6 100644 --- a/scroll/FileLogger/FileLogger.ipp +++ b/scroll/FileLogger/FileLogger.ipp @@ -10,132 +10,158 @@ namespace scroll { } template - void FileLogger::trace(view file, uint32 line, Argument&& argument) { - if (LogLevel::TRACE < minLogLevel) { - return; - } + inline void FileLogger::trace(view file, uint64 line, Argument&& argument) { + writeTraceLog(file, line, argumentInjectionPattern, std::forward(argument)); + } - writeLogHeader("TRACE"); - writeIndented(stream, format("[] (at []:[])", format(std::forward(argument)), file, line), getLogIndentation() - 4); + template + inline void FileLogger::trace(view file, uint64 line, view pattern, Argument&&... arguments) { + writeTraceLog(file, line, pattern, std::forward(arguments)...); + } - stream << '\n'; + template + inline void FileLogger::debug(Argument&& argument) { + writeDebugLog(argumentInjectionPattern, std::forward(argument)); } template - void FileLogger::trace(view file, uint32 line, view pattern, Argument&&... arguments) { - if (LogLevel::TRACE < minLogLevel) { - return; - } + inline void FileLogger::debug(view pattern, Argument&&... arguments) { + writeDebugLog(pattern, std::forward(arguments)...); + } - writeLogHeader("TRACE"); - writeIndented(stream, format("[] (at []:[])", format(pattern, std::forward(arguments)...), file, line), getLogIndentation() - 4); + template + inline void FileLogger::info(Argument&& argument) { + writeInfoLog(argumentInjectionPattern, std::forward(argument)); + } - stream << '\n'; + template + inline void FileLogger::info(view pattern, Argument&&... arguments) { + writeInfoLog(pattern, std::forward(arguments)...); } template - void FileLogger::debug(Argument&& argument) { - if (LogLevel::DEBUG < minLogLevel) { - return; - } + inline void FileLogger::warning(Argument&& argument) { + writeWarningLog(argumentInjectionPattern, std::forward(argument)); + } - writeLogHeader("DEBUG"); - writeIndented(stream, format(std::forward(argument)), getLogIndentation() - 4); + template + inline void FileLogger::warning(view pattern, Argument&&... arguments) { + writeWarningLog(pattern, std::forward(arguments)...); + } - stream << '\n'; + template + inline void FileLogger::error(view function, view file, uint64 line, Argument&& argument) { + writeErrorLog(function, file, line, argumentInjectionPattern, std::forward(argument)); } template - void FileLogger::debug(view pattern, Argument&&... arguments) { - if (LogLevel::DEBUG < minLogLevel) { - return; - } + inline void FileLogger::error(view function, view file, uint64 line, view pattern, Argument&&... arguments) { + writeErrorLog(function, file, line, pattern, std::forward(arguments)...); + } - writeLogHeader("DEBUG"); - writeIndented(stream, format(pattern, std::forward(arguments)...), getLogIndentation() - 4); + template + inline uint64 FileLogger::writeFileLog(view level, view pattern, Argument&&... arguments) { + static constexpr view LOG_BUFFER_TEMPLATE = "[00:00:00.000000] "; - stream << '\n'; + return writeLog(1, LOG_BUFFER_TEMPLATE, level, level.count(), pattern, std::forward(arguments)...); } - template - void FileLogger::info(Argument&& argument) { - if (LogLevel::INFO < minLogLevel) { + template + inline void FileLogger::writeTraceLog(view file, uint64 line, view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "TRACE "; + + if (LogLevel::TRACE < minLogLevel) { return; } - writeLogHeader("INFO"); - writeIndented(stream, format(std::forward(argument)), getLogIndentation() - 5); + uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + + write(" (at ", offset); + write(file, offset); + write(':', offset); - stream << '\n'; + const std::string formattedLine = toString(line); + + write(&formattedLine[0], offset); + write(')', offset); + write('\n', offset); + + flushLog(offset); } template - void FileLogger::info(view pattern, Argument&&... arguments) { - if (LogLevel::INFO < minLogLevel) { + inline void FileLogger::writeDebugLog(view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "DEBUG "; + + if (LogLevel::DEBUG < minLogLevel) { return; } - writeLogHeader("INFO"); - writeIndented(stream, format(pattern, std::forward(arguments)...), getLogIndentation() - 5); + uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); - stream << '\n'; + write('\n', offset); + + flushLog(offset); } - template - void FileLogger::warning(Argument&& argument) { - if (LogLevel::WARNING < minLogLevel) { + template + inline void FileLogger::writeInfoLog(view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "INFO "; + + if (LogLevel::INFO < minLogLevel) { return; } - writeLogHeader("WARNING"); - writeIndented(stream, format(std::forward(argument)), getLogIndentation() - 2); + uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + + write('\n', offset); - stream << '\n'; + flushLog(offset); } template - void FileLogger::warning(view pattern, Argument&&... arguments) { + inline void FileLogger::writeWarningLog(view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "WARNING "; + if (LogLevel::WARNING < minLogLevel) { return; } - writeLogHeader("WARNING"); - writeIndented(stream, format(pattern, std::forward(arguments)...), getLogIndentation() - 2); + uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + + write('\n', offset); - stream << '\n'; + flushLog(offset); } - template - void FileLogger::error(view function, view file, uint64 line, Argument&& argument) { + template + inline void FileLogger::writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments) { + static constexpr view LOG_LEVEL = "ERROR "; + if (LogLevel::ERROR < minLogLevel) { return; } - writeLogHeader("ERROR"); - writeIndented(stream, format("[] (in [], at []:[])", format(std::forward(argument)), function, file, line), getLogIndentation() - 4); + uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); - stream << '\n'; - } + write(" (in ", offset); + write(function, offset); + write(", at ", offset); + write(file, offset); + write(':', offset); - template - void FileLogger::error(view function, view file, uint64 line, view pattern, Argument&&... arguments) { - if (LogLevel::ERROR < minLogLevel) { - return; - } + const std::string formattedLine = toString(line); - writeLogHeader("ERROR"); - writeIndented(stream, format("[] (in [], at []:[])", format(pattern, std::forward(arguments)...), function, file, line), getLogIndentation() - 4); + write(&formattedLine[0], offset); + write(')', offset); + write('\n', offset); - stream << '\n'; + flushLog(offset); } - inline void FileLogger::writeLogHeader(view levelName) { - stream << '[' << timestamp() << "] "; - - if (source.count() > 0) { - stream << source << ' '; - } + inline void FileLogger::flushLog(uint64 size) { + ATL_ASSERT(size <= MAX_LOG_BUFFER_SIZE); - stream << levelName << ' '; + stream.write(&logBuffer[0], size); } } \ No newline at end of file diff --git a/scroll/Logger/Logger.hpp b/scroll/Logger/Logger.hpp index 1855e86..579a22f 100644 --- a/scroll/Logger/Logger.hpp +++ b/scroll/Logger/Logger.hpp @@ -7,11 +7,12 @@ namespace scroll { template - struct ArgumentInjectionPattern { - static sequence argumentInjectionPattern; + class BaseLogger { + protected: + static sequence argumentInjectionPattern; }; - class Logger : public ArgumentInjectionPattern<> { + class Logger : public BaseLogger<> { public: // Returns the current argument injection pattern. static view getArgumentInjectionPattern(); @@ -20,20 +21,45 @@ namespace scroll { static void setArgumentInjectionPattern(view pattern); template - static sequence format(Argument&& argument); + static std::string toString(Argument argument); - template - static sequence format(view pattern, HeadArgument&& headArgument, Argument&&... arguments); + static sequence format(const sequence& pattern); - static sequence timestamp(); + template + static sequence format(const sequence& pattern, CurrentArgument&& argument, Argument&&... arguments) { + const uint64 argumentInjectionPatternOffset = view(pattern).find(argumentInjectionPattern, 0); - protected: - // NOTE: `indentation` must **not** include the size of `text`. - static void writeIndented(std::ostream& stream, view text, uint64 indentation); + if (argumentInjectionPatternOffset >= pattern.count()) { + return pattern; + } + + const std::string formattedArgument = toString(argument); + + sequence updatedPattern(pattern.count() - argumentInjectionPattern.count() + formattedArgument.size()); + + copy(&pattern[0], &pattern[argumentInjectionPatternOffset], &updatedPattern[0]); + copy(formattedArgument.begin(), formattedArgument.end(), &updatedPattern[argumentInjectionPatternOffset]); + + if (argumentInjectionPatternOffset + argumentInjectionPattern.count() < pattern.count()) { + copy(&pattern[argumentInjectionPatternOffset + argumentInjectionPattern.count()], pattern.end(), &updatedPattern[argumentInjectionPatternOffset + formattedArgument.size()]); + } + + return format(updatedPattern, std::forward(arguments)...); + } private: - static constexpr uint64 TIMESTAMP_SIZE = 15; - static constexpr uint64 MAX_LOG_LEVEL_NAME_SIZE = 7; + static sequence createIndentationString(uint64 indentation) { + sequence indentationString(indentation); + + for (char8& character : indentationString) { + character = ' '; + } + + return indentationString; + } + + protected: + static constexpr uint64 MAX_LOG_BUFFER_SIZE = 2048; public: LogLevel getMinLogLevel() const; @@ -43,11 +69,145 @@ namespace scroll { protected: explicit Logger(LogLevel minLogLevel, view source); - uint16 getLogIndentation() const; + void write(char8 character, uint64& offset); + void write(view text, uint64& offset); + void write(view text, uint64& offset, uint64 padding); + + template + uint64 writeLog(uint64 offset, view bufferTemplate, view level, uint64 levelSize, view pattern, Argument&&... arguments) { + #ifdef _MSC_VER + const errno_t error = strncpy_s(&logBuffer[0], bufferTemplate.count() + 1, &bufferTemplate[0], bufferTemplate.count()); + + ATL_ASSERT(error == 0); + #else + std::strncpy(&logBuffer[0], &bufferTemplate[0], bufferTemplate.count()); + #endif + + uint64 indentation = 18; + + writeTimestamp(offset); + + offset = bufferTemplate.count(); + + if (source.count() > 0) { + write(source, offset); + write(' ', offset); + + indentation += source.count() + 1; + } + + write(level, offset); + + indentation += levelSize; + + const sequence indentationString = createIndentationString(indentation); + + writeFormattedArguments(pattern, offset, indentationString, std::forward(arguments)...); + + return offset; + } + + private: + uint64 writeIndented(view pattern, uint64& offset, const sequence& indentationString) { + uint64 previousLineOffset = 0; + uint64 lineOffset = 0; + + while (true) { + lineOffset = pattern.find('\n', previousLineOffset); + + if (lineOffset == previousLineOffset) { + break; + } + + write(view(&pattern[previousLineOffset], lineOffset - previousLineOffset), offset); + + if (lineOffset >= pattern.count()) { + break; + } + + write('\n', offset); + write(indentationString, offset); + + previousLineOffset = lineOffset + 1; + } + + return offset; + } + + uint64 writeFormattedArguments(view pattern, uint64& offset, const sequence& indentationString); + + template + uint64 writeFormattedArguments(view pattern, uint64& offset, const sequence& indentationString, Argument&& argument, PackedArgument&&... arguments) { + const uint64 argumentInjectionPatternOffset = pattern.find(argumentInjectionPattern, 0); + const view preformatted(&pattern[0], argumentInjectionPatternOffset); + + write(preformatted, offset); + + if (argumentInjectionPatternOffset >= pattern.count()) { + return offset; + } + + const std::string formattedArgument = toString(argument); + + writeIndented(&formattedArgument[0], offset, indentationString); + + const uint64 patternOffset = argumentInjectionPatternOffset + argumentInjectionPattern.count(); + + if (patternOffset >= pattern.count()) { + return offset; + } + + pattern = view(&pattern[patternOffset], pattern.count() - patternOffset); + + return writeFormattedArguments(pattern, offset, indentationString, std::forward(arguments)...); + } + + void writeTimestamp(uint64& offset) { + const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); + const uint64 us = std::chrono::duration_cast(now - std::chrono::time_point_cast(now)).count(); + const std::time_t time = std::chrono::system_clock::to_time_t(now); + + std::tm* dateTime; + + #ifdef _MSC_VER + std::tm _dateTime{}; + + const errno_t error = localtime_s(&_dateTime, &time); + + ATL_ASSERT(error == 0); + + dateTime = &_dateTime; + #else + dateTime = std::localtime(&time); + #endif + + std::string formatted = toString(dateTime->tm_hour); + + write(&formatted[0], offset, 2); + + offset += 1; + + formatted = toString(dateTime->tm_min); + + write(&formatted[0], offset, 2); + + offset += 1; + + formatted = toString(dateTime->tm_sec); + + write(&formatted[0], offset, 2); + + offset += 1; + + formatted = toString(us); + + write(&formatted[0], offset, 6); + } protected: LogLevel minLogLevel; view source; + char8 logBuffer[MAX_LOG_BUFFER_SIZE]{}; }; } diff --git a/scroll/Logger/Logger.ipp b/scroll/Logger/Logger.ipp index 11be602..e01fb16 100644 --- a/scroll/Logger/Logger.ipp +++ b/scroll/Logger/Logger.ipp @@ -3,42 +3,7 @@ namespace scroll { template - sequence ArgumentInjectionPattern::argumentInjectionPattern = "[]"; - - template - sequence Logger::format(Argument&& argument) { - static std::ostringstream stream; - - stream << argument; - - const sequence formattedArgument = stream.str().c_str(); - - stream.str({}); - - return formattedArgument; - } - - template - sequence Logger::format(view pattern, HeadArgument&& headArgument, Argument&&... arguments) { - const uint64 argumentInjectionPatternOffset = pattern.find(argumentInjectionPattern, 0); - - if (argumentInjectionPatternOffset >= pattern.count()) { - return pattern; - } - - const sequence formattedArgument = format(headArgument); - - sequence updatedPattern(pattern.count() - argumentInjectionPattern.count() + formattedArgument.count()); - - copy(&pattern[0], &pattern[argumentInjectionPatternOffset], &updatedPattern[0]); - copy(formattedArgument.begin(), formattedArgument.end(), &updatedPattern[argumentInjectionPatternOffset]); - - if (argumentInjectionPatternOffset + argumentInjectionPattern.count() < pattern.count()) { - copy(&pattern[argumentInjectionPatternOffset + argumentInjectionPattern.count()], pattern.end(), &updatedPattern[argumentInjectionPatternOffset + formattedArgument.count()]); - } - - return format(updatedPattern, std::forward(arguments)...); - } + sequence BaseLogger::argumentInjectionPattern = "[]"; inline view Logger::getArgumentInjectionPattern() { return argumentInjectionPattern; @@ -47,44 +12,21 @@ namespace scroll { inline void Logger::setArgumentInjectionPattern(view pattern) { ATL_ASSERT(pattern.count() > 0); - argumentInjectionPattern = &pattern[0]; + argumentInjectionPattern = pattern; } - inline sequence Logger::timestamp() { - static std::ostringstream usStream; - - const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); - const uint64 us = std::chrono::duration_cast(now - std::chrono::time_point_cast(now)).count(); - const std::time_t time = std::chrono::system_clock::to_time_t(now); - - std::tm* dateTime; - - #ifdef _MSC_VER - std::tm _dateTime{}; - - const errno_t error = localtime_s(&_dateTime, &time); - - ATL_ASSERT(error == 0); - - dateTime = &_dateTime; - #else - dateTime = std::localtime(&time); - #endif - - // Include null-terminating character. - sequence hmsString(9); - - const uint64 hmsCharacterCount = std::strftime(&hmsString[0], hmsString.count(), "%H:%M:%S", dateTime); - - ATL_ASSERT(hmsCharacterCount > 0); - - usStream << std::setw(6) << std::setfill('0') << us; - - const sequence timestamp = format("[].[]", hmsString, usStream.str()); + template + inline std::string Logger::toString(Argument argument) { + return std::to_string(argument); + } - usStream.str({}); + template<> + inline std::string Logger::toString(const char8* argument) { + return argument; + } - return timestamp; + inline sequence Logger::format(const sequence& pattern) { + return pattern; } inline LogLevel Logger::getMinLogLevel() const { @@ -100,41 +42,25 @@ namespace scroll { source(source) {} - inline uint16 Logger::getLogIndentation() const { - uint16 indentation = static_cast(TIMESTAMP_SIZE + MAX_LOG_LEVEL_NAME_SIZE + 6); - - if (source.count() > 0) { - indentation += static_cast(source.count()) + 1; - } + inline void Logger::write(char8 character, uint64& offset) { + logBuffer[offset] = character; - return indentation; + offset += 1; } - inline void Logger::writeIndented(std::ostream& stream, view text, uint64 indentation) { - // TODO: Create string with fixed indentation and write parts of it. - sequence indentationString(indentation); - - std::fill_n(&indentationString[0], indentation, ' '); - - uint64 previousOffset = 0; - uint64 offset = 0; + inline void Logger::write(view text, uint64& offset) { + copy(text.begin(), text.end(), &logBuffer[offset]); - while (true) { - offset = text.find('\n', previousOffset); - - if (offset == previousOffset) { - break; - } - - stream.write(&text[previousOffset], offset - previousOffset); + offset += text.count(); + } - if (offset >= text.count()) { - break; - } + inline void Logger::write(view text, uint64& offset, uint64 padding) { + copy(text.begin(), text.end(), &logBuffer[offset] + padding - text.count()); - previousOffset = offset + 1; + offset += padding; + } - stream << '\n' << indentationString; - } + inline uint64 Logger::writeFormattedArguments(view pattern, uint64& offset, const sequence& indentationString) { + return writeIndented(pattern, offset, indentationString); } } \ No newline at end of file diff --git a/scroll/base.hpp b/scroll/base.hpp index 31607de..5a6474d 100644 --- a/scroll/base.hpp +++ b/scroll/base.hpp @@ -4,12 +4,12 @@ #pragma once #include +#include #include #include #include #include #include -#include #ifndef ATL_MODULE_BASE #include "Base/Base/Base.hpp" @@ -19,14 +19,13 @@ #include #ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING - #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004 + #define ENABLE_VIRTUAL_TERMINAL_PROCESSING 4 #endif #endif namespace scroll { using atl::uint8; using atl::uint16; - using atl::uint32; using atl::uint64; using atl::char8; From afa419e239f6c6448ef01c63da502fb54426a610 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 13:04:27 +0100 Subject: [PATCH 3/9] wip: TextBuffer --- Base | 2 +- scroll/ConsoleLogger/ConsoleLogger.hpp | 4 +- scroll/ConsoleLogger/ConsoleLogger.ipp | 64 ++++-------- scroll/FileLogger/FileLogger.hpp | 4 +- scroll/FileLogger/FileLogger.ipp | 63 ++++-------- scroll/Logger/Logger.hpp | 72 ++++++-------- scroll/Logger/Logger.ipp | 32 +----- scroll/TextBuffer/TextBuffer.hpp | 34 +++++++ scroll/TextBuffer/TextBuffer.ipp | 130 +++++++++++++++++++++++++ scroll/base.hpp | 10 ++ 10 files changed, 250 insertions(+), 165 deletions(-) create mode 100644 scroll/TextBuffer/TextBuffer.hpp create mode 100644 scroll/TextBuffer/TextBuffer.ipp diff --git a/Base b/Base index fd8417f..caf9bd3 160000 --- a/Base +++ b/Base @@ -1 +1 @@ -Subproject commit fd8417f2c24e7191955812c54c34fe34123ce01c +Subproject commit caf9bd344fd3f938a00ded72965e12526d740170 diff --git a/scroll/ConsoleLogger/ConsoleLogger.hpp b/scroll/ConsoleLogger/ConsoleLogger.hpp index 9a45fe3..4a6608a 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.hpp +++ b/scroll/ConsoleLogger/ConsoleLogger.hpp @@ -78,7 +78,7 @@ namespace scroll { #endif template - uint64 writeConsoleLog(view level, uint64 levelSize, view pattern, Argument&&... arguments); + void writeConsoleLog(view level, uint64 levelSize, view pattern, Argument&&... arguments); template void writeTraceLog(view file, uint64 line, view pattern, Argument&&... arguments); @@ -95,7 +95,7 @@ namespace scroll { template void writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments); - void flushLog(uint64 size) const; + void flush() const; private: std::ostream* stream; diff --git a/scroll/ConsoleLogger/ConsoleLogger.ipp b/scroll/ConsoleLogger/ConsoleLogger.ipp index b0ed905..8837f26 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.ipp +++ b/scroll/ConsoleLogger/ConsoleLogger.ipp @@ -26,7 +26,7 @@ namespace scroll { stream->write("m", 1); } - *stream << argument; + *stream << toString(argument); return *this; } @@ -110,10 +110,10 @@ namespace scroll { } template - inline uint64 ConsoleLogger::writeConsoleLog(view level, uint64 levelSize, view pattern, Argument&&... arguments) { + inline void ConsoleLogger::writeConsoleLog(view level, uint64 levelSize, view pattern, Argument&&... arguments) { static constexpr view LOG_BUFFER_TEMPLATE = "\033[2m[00:00:00.000000]\033[22m "; - return writeLog(5, LOG_BUFFER_TEMPLATE, level, levelSize, pattern, std::forward(arguments)...); + writeLog(5, LOG_BUFFER_TEMPLATE, level, levelSize, pattern, std::forward(arguments)...); } template @@ -124,19 +124,10 @@ namespace scroll { return; } - uint64 offset = writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); + writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); + buffer << " (at " << file << ':' << line << ')' << '\n'; - write(" (at ", offset); - write(file, offset); - write(':', offset); - - const std::string formattedLine = toString(line); - - write(&formattedLine[0], offset); - write(')', offset); - write('\n', offset); - - flushLog(offset); + flush(); } template @@ -147,11 +138,10 @@ namespace scroll { return; } - uint64 offset = writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); + writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); + buffer << '\n'; - write('\n', offset); - - flushLog(offset); + flush(); } template @@ -162,11 +152,10 @@ namespace scroll { return; } - uint64 offset = writeConsoleLog(LOG_LEVEL, 7, pattern, std::forward(arguments)...); - - write('\n', offset); + writeConsoleLog(LOG_LEVEL, 7, pattern, std::forward(arguments)...); + buffer << '\n'; - flushLog(offset); + flush(); } template @@ -177,11 +166,10 @@ namespace scroll { return; } - uint64 offset = writeConsoleLog(LOG_LEVEL, 9, pattern, std::forward(arguments)...); + writeConsoleLog(LOG_LEVEL, 9, pattern, std::forward(arguments)...); + buffer << "\033[39m\n"; - write("\033[39m\n", offset); - - flushLog(offset); + flush(); } template @@ -192,25 +180,13 @@ namespace scroll { return; } - uint64 offset = writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); - - write(" (in ", offset); - write(function, offset); - write(", at ", offset); - write(file, offset); - write(':', offset); - - const std::string formattedLine = toString(line); + writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); + buffer << " (in " << function << ", at " << file << ':' << line << ")\033[39m\n"; - write(&formattedLine[0], offset); - write(")\033[39m\n", offset); - - flushLog(offset); + flush(); } - inline void ConsoleLogger::flushLog(uint64 size) const { - ATL_ASSERT(size <= MAX_LOG_BUFFER_SIZE); - - std::clog.write(&logBuffer[0], size); + inline void ConsoleLogger::flush() const { + std::clog.write(buffer.buffer, buffer.offset); } } \ No newline at end of file diff --git a/scroll/FileLogger/FileLogger.hpp b/scroll/FileLogger/FileLogger.hpp index a3f79a7..2a9b5a8 100644 --- a/scroll/FileLogger/FileLogger.hpp +++ b/scroll/FileLogger/FileLogger.hpp @@ -43,7 +43,7 @@ namespace scroll { private: template - uint64 writeFileLog(view level, view pattern, Argument&&... arguments); + void writeFileLog(view level, view pattern, Argument&&... arguments); template void writeTraceLog(view file, uint64 line, view pattern, Argument&&... arguments); @@ -60,7 +60,7 @@ namespace scroll { template void writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments); - void flushLog(uint64 size); + void flush(); public: std::ofstream& stream; diff --git a/scroll/FileLogger/FileLogger.ipp b/scroll/FileLogger/FileLogger.ipp index 65763d6..9a2500f 100644 --- a/scroll/FileLogger/FileLogger.ipp +++ b/scroll/FileLogger/FileLogger.ipp @@ -60,10 +60,10 @@ namespace scroll { } template - inline uint64 FileLogger::writeFileLog(view level, view pattern, Argument&&... arguments) { + inline void FileLogger::writeFileLog(view level, view pattern, Argument&&... arguments) { static constexpr view LOG_BUFFER_TEMPLATE = "[00:00:00.000000] "; - return writeLog(1, LOG_BUFFER_TEMPLATE, level, level.count(), pattern, std::forward(arguments)...); + writeLog(1, LOG_BUFFER_TEMPLATE, level, level.count(), pattern, std::forward(arguments)...); } template @@ -74,19 +74,10 @@ namespace scroll { return; } - uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + buffer << " (at " << file << ':' << line << ')' << '\n'; - write(" (at ", offset); - write(file, offset); - write(':', offset); - - const std::string formattedLine = toString(line); - - write(&formattedLine[0], offset); - write(')', offset); - write('\n', offset); - - flushLog(offset); + flush(); } template @@ -97,11 +88,10 @@ namespace scroll { return; } - uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + buffer << '\n'; - write('\n', offset); - - flushLog(offset); + flush(); } template @@ -112,11 +102,10 @@ namespace scroll { return; } - uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); - - write('\n', offset); + writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + buffer << '\n'; - flushLog(offset); + flush(); } template @@ -127,11 +116,10 @@ namespace scroll { return; } - uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + buffer << '\n'; - write('\n', offset); - - flushLog(offset); + flush(); } template @@ -142,26 +130,13 @@ namespace scroll { return; } - uint64 offset = writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); - - write(" (in ", offset); - write(function, offset); - write(", at ", offset); - write(file, offset); - write(':', offset); - - const std::string formattedLine = toString(line); + writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); + buffer << " (in " << function << ", at " << file << ':' << line << ')' << '\n'; - write(&formattedLine[0], offset); - write(')', offset); - write('\n', offset); - - flushLog(offset); + flush(); } - inline void FileLogger::flushLog(uint64 size) { - ATL_ASSERT(size <= MAX_LOG_BUFFER_SIZE); - - stream.write(&logBuffer[0], size); + inline void FileLogger::flush() { + stream.write(&buffer.buffer[0], buffer.offset); } } \ No newline at end of file diff --git a/scroll/Logger/Logger.hpp b/scroll/Logger/Logger.hpp index 579a22f..feaaaa2 100644 --- a/scroll/Logger/Logger.hpp +++ b/scroll/Logger/Logger.hpp @@ -4,6 +4,7 @@ #pragma once #include "scroll/LogLevel.hpp" +#include "scroll/TextBuffer/TextBuffer.hpp" namespace scroll { template @@ -20,9 +21,6 @@ namespace scroll { // Replaces the current argument injection pattern. static void setArgumentInjectionPattern(view pattern); - template - static std::string toString(Argument argument); - static sequence format(const sequence& pattern); template @@ -58,9 +56,6 @@ namespace scroll { return indentationString; } - protected: - static constexpr uint64 MAX_LOG_BUFFER_SIZE = 2048; - public: LogLevel getMinLogLevel() const; @@ -69,46 +64,41 @@ namespace scroll { protected: explicit Logger(LogLevel minLogLevel, view source); - void write(char8 character, uint64& offset); - void write(view text, uint64& offset); - void write(view text, uint64& offset, uint64 padding); - template - uint64 writeLog(uint64 offset, view bufferTemplate, view level, uint64 levelSize, view pattern, Argument&&... arguments) { + void writeLog(uint64 offset, view bufferTemplate, view level, uint64 levelSize, view pattern, Argument&&... arguments) { #ifdef _MSC_VER - const errno_t error = strncpy_s(&logBuffer[0], bufferTemplate.count() + 1, &bufferTemplate[0], bufferTemplate.count()); + const errno_t error = strncpy_s(&buffer.buffer[0], bufferTemplate.count() + 1, &bufferTemplate[0], bufferTemplate.count()); ATL_ASSERT(error == 0); #else - std::strncpy(&logBuffer[0], &bufferTemplate[0], bufferTemplate.count()); + std::strncpy(&buffer.buffer[0], &bufferTemplate[0], bufferTemplate.count()); #endif - uint64 indentation = 18; + buffer.seek(offset); + + writeTimestamp(); - writeTimestamp(offset); + buffer.seek(bufferTemplate.count()); - offset = bufferTemplate.count(); + uint64 indentation = 18; if (source.count() > 0) { - write(source, offset); - write(' ', offset); + buffer << source << ' '; indentation += source.count() + 1; } - write(level, offset); + buffer << level; indentation += levelSize; const sequence indentationString = createIndentationString(indentation); - writeFormattedArguments(pattern, offset, indentationString, std::forward(arguments)...); - - return offset; + writeFormattedArguments(pattern, indentationString, std::forward(arguments)...); } private: - uint64 writeIndented(view pattern, uint64& offset, const sequence& indentationString) { + void writeIndented(view pattern, const sequence& indentationString) { uint64 previousLineOffset = 0; uint64 lineOffset = 0; @@ -119,50 +109,47 @@ namespace scroll { break; } - write(view(&pattern[previousLineOffset], lineOffset - previousLineOffset), offset); + buffer << view(&pattern[previousLineOffset], lineOffset - previousLineOffset); if (lineOffset >= pattern.count()) { break; } - write('\n', offset); - write(indentationString, offset); + buffer << '\n' << indentationString; previousLineOffset = lineOffset + 1; } - - return offset; } - uint64 writeFormattedArguments(view pattern, uint64& offset, const sequence& indentationString); + void writeFormattedArguments(view pattern, const sequence& indentationString); template - uint64 writeFormattedArguments(view pattern, uint64& offset, const sequence& indentationString, Argument&& argument, PackedArgument&&... arguments) { + void writeFormattedArguments(view pattern, const sequence& indentationString, Argument&& argument, PackedArgument&&... arguments) { const uint64 argumentInjectionPatternOffset = pattern.find(argumentInjectionPattern, 0); const view preformatted(&pattern[0], argumentInjectionPatternOffset); - write(preformatted, offset); + buffer << preformatted; if (argumentInjectionPatternOffset >= pattern.count()) { - return offset; + return; } const std::string formattedArgument = toString(argument); - writeIndented(&formattedArgument[0], offset, indentationString); + writeIndented(&formattedArgument[0], indentationString); const uint64 patternOffset = argumentInjectionPatternOffset + argumentInjectionPattern.count(); if (patternOffset >= pattern.count()) { - return offset; + return; } pattern = view(&pattern[patternOffset], pattern.count() - patternOffset); - return writeFormattedArguments(pattern, offset, indentationString, std::forward(arguments)...); + writeFormattedArguments(pattern, indentationString, std::forward(arguments)...); } - void writeTimestamp(uint64& offset) { + void writeTimestamp() { const std::chrono::system_clock::time_point now = std::chrono::system_clock::now(); const uint64 us = std::chrono::duration_cast(now - std::chrono::time_point_cast(now)).count(); const std::time_t time = std::chrono::system_clock::to_time_t(now); @@ -181,11 +168,11 @@ namespace scroll { dateTime = std::localtime(&time); #endif - std::string formatted = toString(dateTime->tm_hour); - - write(&formatted[0], offset, 2); + // TODO + /* std::string formatted = toString(dateTime->tm_hour); - offset += 1; + buffer.padLeft(&formatted[0], 2); + buffer.jump(1); formatted = toString(dateTime->tm_min); @@ -201,13 +188,14 @@ namespace scroll { formatted = toString(us); - write(&formatted[0], offset, 6); + write(&formatted[0], offset, 6); */ } protected: LogLevel minLogLevel; view source; - char8 logBuffer[MAX_LOG_BUFFER_SIZE]{}; + + TextBuffer buffer; }; } diff --git a/scroll/Logger/Logger.ipp b/scroll/Logger/Logger.ipp index e01fb16..d316241 100644 --- a/scroll/Logger/Logger.ipp +++ b/scroll/Logger/Logger.ipp @@ -15,16 +15,6 @@ namespace scroll { argumentInjectionPattern = pattern; } - template - inline std::string Logger::toString(Argument argument) { - return std::to_string(argument); - } - - template<> - inline std::string Logger::toString(const char8* argument) { - return argument; - } - inline sequence Logger::format(const sequence& pattern) { return pattern; } @@ -42,25 +32,7 @@ namespace scroll { source(source) {} - inline void Logger::write(char8 character, uint64& offset) { - logBuffer[offset] = character; - - offset += 1; - } - - inline void Logger::write(view text, uint64& offset) { - copy(text.begin(), text.end(), &logBuffer[offset]); - - offset += text.count(); - } - - inline void Logger::write(view text, uint64& offset, uint64 padding) { - copy(text.begin(), text.end(), &logBuffer[offset] + padding - text.count()); - - offset += padding; - } - - inline uint64 Logger::writeFormattedArguments(view pattern, uint64& offset, const sequence& indentationString) { - return writeIndented(pattern, offset, indentationString); + inline void Logger::writeFormattedArguments(view pattern, const sequence& indentationString) { + writeIndented(pattern, indentationString); } } \ No newline at end of file diff --git a/scroll/TextBuffer/TextBuffer.hpp b/scroll/TextBuffer/TextBuffer.hpp new file mode 100644 index 0000000..6112139 --- /dev/null +++ b/scroll/TextBuffer/TextBuffer.hpp @@ -0,0 +1,34 @@ +#pragma once + +namespace scroll { + template + std::string toString(Argument argument) { + // should never be here + ATL_ASSERT(false); + + return ""; + } + + class TextBuffer { + protected: + static constexpr uint64 MAX_LOG_BUFFER_SIZE = 2048; + + public: + void jump(uint64 offset); + void seek(uint64 offset); + + template + TextBuffer& operator<<(Argument argument); + + TextBuffer& padLeft(view text, uint64 padding); + TextBuffer& padRight(view text, uint64 padding); + + void clear(); + + public: + char8 buffer[MAX_LOG_BUFFER_SIZE]{}; + uint64 offset = 0; + }; +} + +#include "scroll/TextBuffer/TextBuffer.ipp" \ No newline at end of file diff --git a/scroll/TextBuffer/TextBuffer.ipp b/scroll/TextBuffer/TextBuffer.ipp new file mode 100644 index 0000000..d2f02e3 --- /dev/null +++ b/scroll/TextBuffer/TextBuffer.ipp @@ -0,0 +1,130 @@ +namespace scroll { + template<> + inline std::string toString(bool argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(uint8 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(uint16 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(uint32 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(uint64 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(sint8 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(sint16 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(sint32 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(sint64 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(char8 argument) { + return std::string(1, argument); + } + + template<> + inline std::string toString(float32 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(float64 argument) { + return std::to_string(argument); + } + + template<> + inline std::string toString(const char8* argument) { + return argument; + } + + template<> + inline std::string toString(const sequence& argument) { + return std::string(&argument[0], argument.count()); + } + + template<> + inline std::string toString(view argument) { + return std::string(&argument[0], argument.count()); + } + + template<> + inline std::string toString(const std::string& argument) { + return argument; + } + + inline void TextBuffer::jump(uint64 offset) { + ATL_ASSERT(this->offset + offset < MAX_LOG_BUFFER_SIZE); + + this->offset += offset; + } + + inline void TextBuffer::seek(uint64 offset) { + ATL_ASSERT(offset < MAX_LOG_BUFFER_SIZE); + + this->offset = offset; + } + + template + inline TextBuffer& TextBuffer::operator<<(Argument argument) { + const std::string string = toString(argument); + + copy(string.begin(), string.end(), &buffer[offset]); + jump(string.size()); + + return *this; + } + + template<> + inline TextBuffer& TextBuffer::operator<<(char8 argument) { + buffer[offset] = argument; + + jump(1); + + return *this; + } + + inline TextBuffer& TextBuffer::padLeft(view text, uint64 padding) { + offset += ATL_MAX(0, padding - text.count()); + + return operator<<(text); + } + + inline TextBuffer& TextBuffer::padRight(view text, uint64 padding) { + TextBuffer& textBuffer = operator<<(text); + + offset += ATL_MAX(0, padding - text.count()); + + return textBuffer; + } + + inline void TextBuffer::clear() { + offset = 0; + } +} \ No newline at end of file diff --git a/scroll/base.hpp b/scroll/base.hpp index 5a6474d..9f173b0 100644 --- a/scroll/base.hpp +++ b/scroll/base.hpp @@ -26,12 +26,22 @@ namespace scroll { using atl::uint8; using atl::uint16; + using atl::uint32; using atl::uint64; + using atl::sint8; + using atl::sint16; + using atl::sint32; + using atl::sint64; + using atl::char8; + using atl::float32; + using atl::float64; + using atl::sequence; using atl::view; using atl::copy; + using atl::pointer_cast; } \ No newline at end of file From dcf556e0ea67e5f9c7ea22a02f6bb0d5068c9b09 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 13:25:17 +0100 Subject: [PATCH 4/9] wip: Replace logBuffer with TextBuffer --- scroll/ConsoleLogger/ConsoleLogger.hpp | 2 -- scroll/ConsoleLogger/ConsoleLogger.ipp | 23 ++++++++--------------- scroll/FileLogger/FileLogger.hpp | 2 -- scroll/FileLogger/FileLogger.ipp | 19 +++++-------------- scroll/Logger/Logger.hpp | 25 +++++++++++-------------- scroll/TextBuffer/TextBuffer.hpp | 2 ++ scroll/TextBuffer/TextBuffer.ipp | 24 ++++++++++++++++++++---- 7 files changed, 46 insertions(+), 51 deletions(-) diff --git a/scroll/ConsoleLogger/ConsoleLogger.hpp b/scroll/ConsoleLogger/ConsoleLogger.hpp index 4a6608a..8e2846d 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.hpp +++ b/scroll/ConsoleLogger/ConsoleLogger.hpp @@ -95,8 +95,6 @@ namespace scroll { template void writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments); - void flush() const; - private: std::ostream* stream; bool redirected = false; diff --git a/scroll/ConsoleLogger/ConsoleLogger.ipp b/scroll/ConsoleLogger/ConsoleLogger.ipp index 8837f26..f6c1941 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.ipp +++ b/scroll/ConsoleLogger/ConsoleLogger.ipp @@ -42,7 +42,9 @@ namespace scroll { stream->write(";", 1); } - *stream << static_cast(argument); + const std::string string = toString(argument); + + stream->write(&string[0], string.size()); return *this; } @@ -126,8 +128,7 @@ namespace scroll { writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); buffer << " (at " << file << ':' << line << ')' << '\n'; - - flush(); + buffer.flush(std::clog); } template @@ -140,8 +141,7 @@ namespace scroll { writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); buffer << '\n'; - - flush(); + buffer.flush(std::clog); } template @@ -154,8 +154,7 @@ namespace scroll { writeConsoleLog(LOG_LEVEL, 7, pattern, std::forward(arguments)...); buffer << '\n'; - - flush(); + buffer.flush(std::clog); } template @@ -168,8 +167,7 @@ namespace scroll { writeConsoleLog(LOG_LEVEL, 9, pattern, std::forward(arguments)...); buffer << "\033[39m\n"; - - flush(); + buffer.flush(std::clog); } template @@ -182,11 +180,6 @@ namespace scroll { writeConsoleLog(LOG_LEVEL, 8, pattern, std::forward(arguments)...); buffer << " (in " << function << ", at " << file << ':' << line << ")\033[39m\n"; - - flush(); - } - - inline void ConsoleLogger::flush() const { - std::clog.write(buffer.buffer, buffer.offset); + buffer.flush(std::clog); } } \ No newline at end of file diff --git a/scroll/FileLogger/FileLogger.hpp b/scroll/FileLogger/FileLogger.hpp index 2a9b5a8..ada2ad1 100644 --- a/scroll/FileLogger/FileLogger.hpp +++ b/scroll/FileLogger/FileLogger.hpp @@ -60,8 +60,6 @@ namespace scroll { template void writeErrorLog(view function, view file, uint64 line, view pattern, Argument&&... arguments); - void flush(); - public: std::ofstream& stream; }; diff --git a/scroll/FileLogger/FileLogger.ipp b/scroll/FileLogger/FileLogger.ipp index 9a2500f..36244ad 100644 --- a/scroll/FileLogger/FileLogger.ipp +++ b/scroll/FileLogger/FileLogger.ipp @@ -76,8 +76,7 @@ namespace scroll { writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); buffer << " (at " << file << ':' << line << ')' << '\n'; - - flush(); + buffer.flush(stream); } template @@ -90,8 +89,7 @@ namespace scroll { writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); buffer << '\n'; - - flush(); + buffer.flush(stream); } template @@ -104,8 +102,7 @@ namespace scroll { writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); buffer << '\n'; - - flush(); + buffer.flush(stream); } template @@ -118,8 +115,7 @@ namespace scroll { writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); buffer << '\n'; - - flush(); + buffer.flush(stream); } template @@ -132,11 +128,6 @@ namespace scroll { writeFileLog(LOG_LEVEL, pattern, std::forward(arguments)...); buffer << " (in " << function << ", at " << file << ':' << line << ')' << '\n'; - - flush(); - } - - inline void FileLogger::flush() { - stream.write(&buffer.buffer[0], buffer.offset); + buffer.flush(stream); } } \ No newline at end of file diff --git a/scroll/Logger/Logger.hpp b/scroll/Logger/Logger.hpp index feaaaa2..db6dfb0 100644 --- a/scroll/Logger/Logger.hpp +++ b/scroll/Logger/Logger.hpp @@ -126,12 +126,13 @@ namespace scroll { template void writeFormattedArguments(view pattern, const sequence& indentationString, Argument&& argument, PackedArgument&&... arguments) { const uint64 argumentInjectionPatternOffset = pattern.find(argumentInjectionPattern, 0); - const view preformatted(&pattern[0], argumentInjectionPatternOffset); - buffer << preformatted; + if (argumentInjectionPatternOffset > 0) { + buffer << view(&pattern[0], argumentInjectionPatternOffset); - if (argumentInjectionPatternOffset >= pattern.count()) { - return; + if (argumentInjectionPatternOffset >= pattern.count()) { + return; + } } const std::string formattedArgument = toString(argument); @@ -168,33 +169,29 @@ namespace scroll { dateTime = std::localtime(&time); #endif - // TODO - /* std::string formatted = toString(dateTime->tm_hour); + std::string formatted = toString(dateTime->tm_hour); buffer.padLeft(&formatted[0], 2); buffer.jump(1); formatted = toString(dateTime->tm_min); - write(&formatted[0], offset, 2); - - offset += 1; + buffer.padLeft(&formatted[0], 2); + buffer.jump(1); formatted = toString(dateTime->tm_sec); - write(&formatted[0], offset, 2); - - offset += 1; + buffer.padLeft(&formatted[0], 2); + buffer.jump(1); formatted = toString(us); - write(&formatted[0], offset, 6); */ + buffer.padLeft(&formatted[0], 6); } protected: LogLevel minLogLevel; view source; - TextBuffer buffer; }; } diff --git a/scroll/TextBuffer/TextBuffer.hpp b/scroll/TextBuffer/TextBuffer.hpp index 6112139..044cec5 100644 --- a/scroll/TextBuffer/TextBuffer.hpp +++ b/scroll/TextBuffer/TextBuffer.hpp @@ -23,6 +23,8 @@ namespace scroll { TextBuffer& padLeft(view text, uint64 padding); TextBuffer& padRight(view text, uint64 padding); + void flush(std::ostream& stream); + void clear(); public: diff --git a/scroll/TextBuffer/TextBuffer.ipp b/scroll/TextBuffer/TextBuffer.ipp index d2f02e3..a9a0fa2 100644 --- a/scroll/TextBuffer/TextBuffer.ipp +++ b/scroll/TextBuffer/TextBuffer.ipp @@ -95,10 +95,7 @@ inline TextBuffer& TextBuffer::operator<<(Argument argument) { const std::string string = toString(argument); - copy(string.begin(), string.end(), &buffer[offset]); - jump(string.size()); - - return *this; + return operator<<(view(&string[0], string.size())); } template<> @@ -110,6 +107,19 @@ return *this; } + template<> + inline TextBuffer& TextBuffer::operator<<(view argument) { + copy(argument.begin(), argument.end(), &buffer[offset]); + jump(argument.count()); + + return *this; + } + + template<> + inline TextBuffer& TextBuffer::operator<<(sequence argument) { + return operator<<(view(&argument[0], argument.count())); + } + inline TextBuffer& TextBuffer::padLeft(view text, uint64 padding) { offset += ATL_MAX(0, padding - text.count()); @@ -124,6 +134,12 @@ return textBuffer; } + inline void TextBuffer::flush(std::ostream& stream) { + stream.write(&buffer[0], offset); + + clear(); + } + inline void TextBuffer::clear() { offset = 0; } From 67d565c036c8123168b5635277217458558c1e91 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 15:38:51 +0100 Subject: [PATCH 5/9] wip: TextBuffer for global formatting --- scroll/ConsoleLogger/ConsoleLogger.ipp | 11 ++++-- scroll/Conversions.ipp | 4 +++ scroll/Logger/Logger.hpp | 50 +++++++++++++++----------- scroll/Logger/Logger.ipp | 13 +++++-- scroll/TextBuffer/TextBuffer.hpp | 19 +++++++--- scroll/TextBuffer/TextBuffer.ipp | 36 +++++++++++++++---- 6 files changed, 98 insertions(+), 35 deletions(-) diff --git a/scroll/ConsoleLogger/ConsoleLogger.ipp b/scroll/ConsoleLogger/ConsoleLogger.ipp index f6c1941..654432f 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.ipp +++ b/scroll/ConsoleLogger/ConsoleLogger.ipp @@ -3,9 +3,12 @@ namespace scroll { inline ConsoleLogger::ConsoleLogger(std::ostream& stream, LogLevel minLogLevel, view source) : - Logger(minLogLevel, source) + Logger(minLogLevel, source), + stream(&stream) { #if ATL_OPERATING_SYSTEM == ATL_OPERATING_SYSTEM_WINDOWS + SetConsoleOutputCP(CP_UTF8); + setConsoleMode(STD_OUTPUT_HANDLE); #endif } @@ -26,7 +29,11 @@ namespace scroll { stream->write("m", 1); } - *stream << toString(argument); + buffer << argument; + + *stream << buffer.getText(); + + buffer.clear(); return *this; } diff --git a/scroll/Conversions.ipp b/scroll/Conversions.ipp index b47c45a..5aaeca6 100644 --- a/scroll/Conversions.ipp +++ b/scroll/Conversions.ipp @@ -6,6 +6,10 @@ namespace scroll { return stream.write(&view[0], view.count()); } + inline std::ostream& operator<<(std::ostream& stream, const sequence& sequence) { + return stream << view(&sequence[0], sequence.count()); + } + inline std::ostream& operator<<(std::ostream& stream, ConsoleEscapeCode code) { return stream << static_cast(code); } diff --git a/scroll/Logger/Logger.hpp b/scroll/Logger/Logger.hpp index db6dfb0..5cef4d8 100644 --- a/scroll/Logger/Logger.hpp +++ b/scroll/Logger/Logger.hpp @@ -11,6 +11,7 @@ namespace scroll { class BaseLogger { protected: static sequence argumentInjectionPattern; + static TextBuffer formatBuffer; }; class Logger : public BaseLogger<> { @@ -21,28 +22,39 @@ namespace scroll { // Replaces the current argument injection pattern. static void setArgumentInjectionPattern(view pattern); - static sequence format(const sequence& pattern); + static sequence format(view pattern); template - static sequence format(const sequence& pattern, CurrentArgument&& argument, Argument&&... arguments) { + static sequence format(view pattern, CurrentArgument&& argument, Argument&&... arguments) { const uint64 argumentInjectionPatternOffset = view(pattern).find(argumentInjectionPattern, 0); + if (argumentInjectionPatternOffset > 0) { + formatBuffer << view(&pattern[0], argumentInjectionPatternOffset); + } + if (argumentInjectionPatternOffset >= pattern.count()) { - return pattern; + const sequence text = formatBuffer.getText(); + + formatBuffer.clear(); + + return text; } - const std::string formattedArgument = toString(argument); + formatBuffer << argument; - sequence updatedPattern(pattern.count() - argumentInjectionPattern.count() + formattedArgument.size()); + const uint64 patternOffset = argumentInjectionPatternOffset + argumentInjectionPattern.count(); + + if (patternOffset >= pattern.count()) { + const sequence text = formatBuffer.getText(); - copy(&pattern[0], &pattern[argumentInjectionPatternOffset], &updatedPattern[0]); - copy(formattedArgument.begin(), formattedArgument.end(), &updatedPattern[argumentInjectionPatternOffset]); + formatBuffer.clear(); - if (argumentInjectionPatternOffset + argumentInjectionPattern.count() < pattern.count()) { - copy(&pattern[argumentInjectionPatternOffset + argumentInjectionPattern.count()], pattern.end(), &updatedPattern[argumentInjectionPatternOffset + formattedArgument.size()]); + return text; } - return format(updatedPattern, std::forward(arguments)...); + pattern = view(&pattern[patternOffset], pattern.count() - patternOffset); + + return format(pattern, std::forward(arguments)...); } private: @@ -105,12 +117,10 @@ namespace scroll { while (true) { lineOffset = pattern.find('\n', previousLineOffset); - if (lineOffset == previousLineOffset) { - break; + if (lineOffset > previousLineOffset) { + buffer << view(&pattern[previousLineOffset], lineOffset - previousLineOffset); } - buffer << view(&pattern[previousLineOffset], lineOffset - previousLineOffset); - if (lineOffset >= pattern.count()) { break; } @@ -128,16 +138,14 @@ namespace scroll { const uint64 argumentInjectionPatternOffset = pattern.find(argumentInjectionPattern, 0); if (argumentInjectionPatternOffset > 0) { - buffer << view(&pattern[0], argumentInjectionPatternOffset); - - if (argumentInjectionPatternOffset >= pattern.count()) { - return; - } + writeIndented(view(&pattern[0], argumentInjectionPatternOffset), indentationString); } - const std::string formattedArgument = toString(argument); + if (argumentInjectionPatternOffset >= pattern.count()) { + return; + } - writeIndented(&formattedArgument[0], indentationString); + buffer << argument; const uint64 patternOffset = argumentInjectionPatternOffset + argumentInjectionPattern.count(); diff --git a/scroll/Logger/Logger.ipp b/scroll/Logger/Logger.ipp index d316241..70610e0 100644 --- a/scroll/Logger/Logger.ipp +++ b/scroll/Logger/Logger.ipp @@ -5,6 +5,9 @@ namespace scroll { template sequence BaseLogger::argumentInjectionPattern = "[]"; + template + TextBuffer BaseLogger::formatBuffer; + inline view Logger::getArgumentInjectionPattern() { return argumentInjectionPattern; } @@ -15,8 +18,14 @@ namespace scroll { argumentInjectionPattern = pattern; } - inline sequence Logger::format(const sequence& pattern) { - return pattern; + inline sequence Logger::format(view pattern) { + formatBuffer << pattern; + + const sequence text = formatBuffer.getText(); + + formatBuffer.clear(); + + return text; } inline LogLevel Logger::getMinLogLevel() const { diff --git a/scroll/TextBuffer/TextBuffer.hpp b/scroll/TextBuffer/TextBuffer.hpp index 044cec5..487bb29 100644 --- a/scroll/TextBuffer/TextBuffer.hpp +++ b/scroll/TextBuffer/TextBuffer.hpp @@ -3,10 +3,8 @@ namespace scroll { template std::string toString(Argument argument) { - // should never be here - ATL_ASSERT(false); - - return ""; + // NOTE: Being here means that a toString() specialization for `argument` was not provided. + return "\xEF\xBF\xBD"; } class TextBuffer { @@ -14,12 +12,25 @@ namespace scroll { static constexpr uint64 MAX_LOG_BUFFER_SIZE = 2048; public: + sequence getText() const; + void jump(uint64 offset); void seek(uint64 offset); template TextBuffer& operator<<(Argument argument); + TextBuffer& operator<<(char8 argument); + TextBuffer& operator<<(const sequence& argument); + TextBuffer& operator<<(const std::string& argument); + TextBuffer& operator<<(char8* argument); + TextBuffer& operator<<(const char8* argument); + TextBuffer& operator<<(view argument); + + #if ATL_STANDARD >= ATL_STANDARD_CPP17 + TextBuffer& operator<<(std::string_view argument); + #endif + TextBuffer& padLeft(view text, uint64 padding); TextBuffer& padRight(view text, uint64 padding); diff --git a/scroll/TextBuffer/TextBuffer.ipp b/scroll/TextBuffer/TextBuffer.ipp index a9a0fa2..587581e 100644 --- a/scroll/TextBuffer/TextBuffer.ipp +++ b/scroll/TextBuffer/TextBuffer.ipp @@ -79,6 +79,15 @@ return argument; } + template<> + inline std::string toString(ConsoleEscapeCode argument) { + return std::to_string(static_cast(argument)); + } + + inline sequence TextBuffer::getText() const { + return sequence(&buffer[0], offset); + } + inline void TextBuffer::jump(uint64 offset) { ATL_ASSERT(this->offset + offset < MAX_LOG_BUFFER_SIZE); @@ -98,7 +107,6 @@ return operator<<(view(&string[0], string.size())); } - template<> inline TextBuffer& TextBuffer::operator<<(char8 argument) { buffer[offset] = argument; @@ -107,7 +115,22 @@ return *this; } - template<> + inline TextBuffer& TextBuffer::operator<<(const sequence& argument) { + return operator<<(view(&argument[0], argument.count())); + } + + inline TextBuffer& TextBuffer::operator<<(const std::string& argument) { + return operator<<(view(&argument[0], argument.size())); + } + + inline TextBuffer& TextBuffer::operator<<(char8* argument) { + return operator<<(view(argument)); + } + + inline TextBuffer& TextBuffer::operator<<(const char8* argument) { + return operator<<(view(argument)); + } + inline TextBuffer& TextBuffer::operator<<(view argument) { copy(argument.begin(), argument.end(), &buffer[offset]); jump(argument.count()); @@ -115,10 +138,11 @@ return *this; } - template<> - inline TextBuffer& TextBuffer::operator<<(sequence argument) { - return operator<<(view(&argument[0], argument.count())); - } + #if ATL_STANDARD >= ATL_STANDARD_CPP17 + inline TextBuffer& TextBuffer::operator<<(std::string_view argument) { + return operator<<(view(&argument[0], argument.size())); + } + #endif inline TextBuffer& TextBuffer::padLeft(view text, uint64 padding) { offset += ATL_MAX(0, padding - text.count()); From d402e10214d07429e0f547e2ed3668fc789941b6 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 16:04:17 +0100 Subject: [PATCH 6/9] fix: sequence formatting to std::ostream --- scroll/Conversions.ipp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scroll/Conversions.ipp b/scroll/Conversions.ipp index 5aaeca6..143c690 100644 --- a/scroll/Conversions.ipp +++ b/scroll/Conversions.ipp @@ -7,7 +7,7 @@ namespace scroll { } inline std::ostream& operator<<(std::ostream& stream, const sequence& sequence) { - return stream << view(&sequence[0], sequence.count()); + return stream << &sequence[0]; } inline std::ostream& operator<<(std::ostream& stream, ConsoleEscapeCode code) { From 3bc95956f92f53de208048a5b0a566e33ac1d5ba Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 16:22:51 +0100 Subject: [PATCH 7/9] fix: Correctly indent newlines in log arguments --- scroll/Logger/Logger.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scroll/Logger/Logger.hpp b/scroll/Logger/Logger.hpp index 5cef4d8..f3bc217 100644 --- a/scroll/Logger/Logger.hpp +++ b/scroll/Logger/Logger.hpp @@ -145,7 +145,9 @@ namespace scroll { return; } - buffer << argument; + const std::string formattedArgument = toString(argument); + + writeIndented(&formattedArgument[0], indentationString); const uint64 patternOffset = argumentInjectionPatternOffset + argumentInjectionPattern.count(); From cf73666337f6b7b0fa3ec24c1cc103fc6ec1cc35 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 16:25:06 +0100 Subject: [PATCH 8/9] feat: Double text buffer max size --- scroll/TextBuffer/TextBuffer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scroll/TextBuffer/TextBuffer.hpp b/scroll/TextBuffer/TextBuffer.hpp index 487bb29..6e8e6e6 100644 --- a/scroll/TextBuffer/TextBuffer.hpp +++ b/scroll/TextBuffer/TextBuffer.hpp @@ -9,7 +9,7 @@ namespace scroll { class TextBuffer { protected: - static constexpr uint64 MAX_LOG_BUFFER_SIZE = 2048; + static constexpr uint64 MAX_LOG_BUFFER_SIZE = 4096; public: sequence getText() const; From 8200eda9cc0a9395ea2de9a71a71e571c2101a80 Mon Sep 17 00:00:00 2001 From: matteokeole Date: Sun, 23 Nov 2025 16:33:31 +0100 Subject: [PATCH 9/9] docs: Update copyright license header --- .github/workflows/check_copyright_license_headers.yaml | 2 +- Base | 2 +- scripts/check_copyright_license_headers.sh | 4 ++-- scroll/ConsoleEscapeCode.hpp | 4 ++-- scroll/ConsoleLogger/ConsoleLogger.hpp | 4 ++-- scroll/ConsoleLogger/ConsoleLogger.ipp | 4 ++-- scroll/Conversions.hpp | 4 ++-- scroll/Conversions.ipp | 4 ++-- scroll/FileLogger/FileLogger.hpp | 4 ++-- scroll/FileLogger/FileLogger.ipp | 4 ++-- scroll/LogLevel.hpp | 4 ++-- scroll/Logger/Logger.hpp | 4 ++-- scroll/Logger/Logger.ipp | 4 ++-- scroll/TextBuffer/TextBuffer.hpp | 5 ++++- scroll/TextBuffer/TextBuffer.ipp | 5 ++++- scroll/base.hpp | 4 ++-- scroll/scroll.hpp | 4 ++-- 17 files changed, 36 insertions(+), 30 deletions(-) diff --git a/.github/workflows/check_copyright_license_headers.yaml b/.github/workflows/check_copyright_license_headers.yaml index fabc664..912fc1f 100644 --- a/.github/workflows/check_copyright_license_headers.yaml +++ b/.github/workflows/check_copyright_license_headers.yaml @@ -22,4 +22,4 @@ jobs: env: GITHUB_BASE_REF: ${{github.base_ref}} GITHUB_HEAD_REF: ${{github.head_ref}} - GITHUB_TREE_URL: ${{github.server_url}}/${{github.repository}}/tree/${{github.head_ref}} \ No newline at end of file + GITHUB_HEAD_URL: ${{github.server_url}}/${{github.repository}}/tree/${{github.head_ref}} \ No newline at end of file diff --git a/Base b/Base index caf9bd3..9133e93 160000 --- a/Base +++ b/Base @@ -1 +1 @@ -Subproject commit caf9bd344fd3f938a00ded72965e12526d740170 +Subproject commit 9133e933321726778890ef16b83eda7e00021f7f diff --git a/scripts/check_copyright_license_headers.sh b/scripts/check_copyright_license_headers.sh index 1a2037e..c5a3a48 100644 --- a/scripts/check_copyright_license_headers.sh +++ b/scripts/check_copyright_license_headers.sh @@ -1,6 +1,6 @@ #!/bin/bash -HEADER=$'// Copyright 2025 Atalante.\n// Licensed under MIT.' +HEADER=$'// Copyright 2025 Atalante Studio.\n// Distributed under the MIT License.' files=$(git diff --diff-filter=d --name-only origin/$GITHUB_BASE_REF origin/$GITHUB_HEAD_REF -- *.{cpp,hpp,ipp}) unlicensed_files=() @@ -17,7 +17,7 @@ if [[ ${#unlicensed_files[@]} -gt 0 ]]; then echo "The following file(s) don't have a valid copyright license header." >> $GITHUB_STEP_SUMMARY for file in "${unlicensed_files[@]}"; do - echo "- [$file]($GITHUB_TREE_URL/$file)" >> $GITHUB_STEP_SUMMARY + echo "- [$file]($GITHUB_HEAD_URL/$file)" >> $GITHUB_STEP_SUMMARY done exit 1 diff --git a/scroll/ConsoleEscapeCode.hpp b/scroll/ConsoleEscapeCode.hpp index 7f15861..e7a9cef 100644 --- a/scroll/ConsoleEscapeCode.hpp +++ b/scroll/ConsoleEscapeCode.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/ConsoleLogger/ConsoleLogger.hpp b/scroll/ConsoleLogger/ConsoleLogger.hpp index 8e2846d..dafcdef 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.hpp +++ b/scroll/ConsoleLogger/ConsoleLogger.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/ConsoleLogger/ConsoleLogger.ipp b/scroll/ConsoleLogger/ConsoleLogger.ipp index 654432f..2c3fe99 100644 --- a/scroll/ConsoleLogger/ConsoleLogger.ipp +++ b/scroll/ConsoleLogger/ConsoleLogger.ipp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. namespace scroll { inline ConsoleLogger::ConsoleLogger(std::ostream& stream, LogLevel minLogLevel, view source) : diff --git a/scroll/Conversions.hpp b/scroll/Conversions.hpp index cf8565c..ac838b2 100644 --- a/scroll/Conversions.hpp +++ b/scroll/Conversions.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/Conversions.ipp b/scroll/Conversions.ipp index 143c690..cd8bfa7 100644 --- a/scroll/Conversions.ipp +++ b/scroll/Conversions.ipp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. namespace scroll { inline std::ostream& operator<<(std::ostream& stream, view view) { diff --git a/scroll/FileLogger/FileLogger.hpp b/scroll/FileLogger/FileLogger.hpp index ada2ad1..f6029bd 100644 --- a/scroll/FileLogger/FileLogger.hpp +++ b/scroll/FileLogger/FileLogger.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/FileLogger/FileLogger.ipp b/scroll/FileLogger/FileLogger.ipp index 36244ad..974c0fd 100644 --- a/scroll/FileLogger/FileLogger.ipp +++ b/scroll/FileLogger/FileLogger.ipp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. namespace scroll { inline FileLogger::FileLogger(std::ofstream& stream, LogLevel minLogLevel, view source) : diff --git a/scroll/LogLevel.hpp b/scroll/LogLevel.hpp index 693c299..2f46c5e 100644 --- a/scroll/LogLevel.hpp +++ b/scroll/LogLevel.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/Logger/Logger.hpp b/scroll/Logger/Logger.hpp index f3bc217..f86aac8 100644 --- a/scroll/Logger/Logger.hpp +++ b/scroll/Logger/Logger.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/Logger/Logger.ipp b/scroll/Logger/Logger.ipp index 70610e0..7f51a35 100644 --- a/scroll/Logger/Logger.ipp +++ b/scroll/Logger/Logger.ipp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. namespace scroll { template diff --git a/scroll/TextBuffer/TextBuffer.hpp b/scroll/TextBuffer/TextBuffer.hpp index 6e8e6e6..3447153 100644 --- a/scroll/TextBuffer/TextBuffer.hpp +++ b/scroll/TextBuffer/TextBuffer.hpp @@ -1,4 +1,7 @@ -#pragma once +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. + +#pragma once namespace scroll { template diff --git a/scroll/TextBuffer/TextBuffer.ipp b/scroll/TextBuffer/TextBuffer.ipp index 587581e..2aea00e 100644 --- a/scroll/TextBuffer/TextBuffer.ipp +++ b/scroll/TextBuffer/TextBuffer.ipp @@ -1,4 +1,7 @@ -namespace scroll { +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. + +namespace scroll { template<> inline std::string toString(bool argument) { return std::to_string(argument); diff --git a/scroll/base.hpp b/scroll/base.hpp index 9f173b0..91a4134 100644 --- a/scroll/base.hpp +++ b/scroll/base.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once diff --git a/scroll/scroll.hpp b/scroll/scroll.hpp index 3e8933a..6490257 100644 --- a/scroll/scroll.hpp +++ b/scroll/scroll.hpp @@ -1,5 +1,5 @@ -// Copyright 2025 Atalante. -// Licensed under MIT. +// Copyright 2025 Atalante Studio. +// Distributed under the MIT License. #pragma once