From 774ae23a20b054e0a5996c45928f8388ec365578 Mon Sep 17 00:00:00 2001 From: Riyyi Date: Fri, 29 Jan 2021 00:00:40 +0100 Subject: [PATCH] Add BufferedLogStream --- inferno/src/inferno/io/log.cpp | 129 +++++++++++++++++++++++---------- inferno/src/inferno/io/log.h | 81 ++++++++++++++++----- 2 files changed, 151 insertions(+), 59 deletions(-) diff --git a/inferno/src/inferno/io/log.cpp b/inferno/src/inferno/io/log.cpp index 94a7437..9c3079d 100644 --- a/inferno/src/inferno/io/log.cpp +++ b/inferno/src/inferno/io/log.cpp @@ -1,12 +1,99 @@ #include "inferno/assert.h" #include "inferno/io/log.h" -#include // strlen +#include // size_t +#include // fwrite, snprintf +#include // malloc, free +#include // memcpy, strlen #include // std::string #include // std::string_view namespace Inferno { + BufferedLogStream::~BufferedLogStream() + { + // Free buffer memory + if (m_capacity > sizeof(m_buffer.stack)) { + free(m_buffer.heap); + } + } + + void BufferedLogStream::grow(size_t bytes) const + { + // Bitwise & ~ example, we use 127 as binary starts at 0 + // 0b001111111 127 ~ + // 0b100000100 260 & + // ----------- + // 0b110000000 384 + // 0b100000100 260 & + // ----------- + // 0b100000000 256 + + // Buffer is is chunks of 128 bytes + size_t newCapacity = (m_count + bytes + BUFFER_SIZE - 1) & ~(BUFFER_SIZE - 1); + + unsigned char* newBuffer = static_cast(malloc(newCapacity)); + + // Copy the non-heap data into the new buffer + if (m_capacity <= sizeof(m_buffer.stack)) { + memcpy(newBuffer, m_buffer.stack, m_count); + } + // Copy old heap-buffer data into the new buffer, free old heap-buffer + else if (m_buffer.heap) { + memcpy(newBuffer, m_buffer.heap, m_count); + free(m_buffer.heap); + } + + m_buffer.heap = newBuffer; + m_capacity = newCapacity; + } + +// ----------------------------------------- + + DebugLogStream::~DebugLogStream() + { + if (empty()) { + return; + } + + if (m_type != Log::None) { + const char* clear = "\033[0m"; + write(clear, strlen(clear)); + } + + if (m_newline) { + char newline = '\n'; + write(&newline, 1); + } + + fwrite(buffer(), 1, count(), stdout); + } + + void DebugLogStream::color() const + { + const char* color = ""; + + if (m_type == Log::Info) { + color = "\x1B[34m"; + } + else if (m_type == Log::Warn) { + color = "\x1B[33m"; + } + else if (m_type == Log::Danger) { + color = "\x1B[31m"; + } + else if (m_type == Log::Success) { + color = "\x1B[32m"; + } + else if (m_type == Log::Comment) { + color = "\x1B[37m"; + } + + write(color, strlen(color)); + } + +// ----------------------------------------- + const LogStream& operator<<(const LogStream& stream, const char* value) { if (value == nullptr) { @@ -166,6 +253,8 @@ namespace Inferno { return DebugLogStream(type, newline); } +// ----------------------------------------- + void dbgln(Log type, bool newline) { (void)type; dbg(newline); @@ -216,42 +305,4 @@ namespace Inferno { dbg(type, newline) << format; } -// ----------------------------------------- - - DebugLogStream::~DebugLogStream() - { - if (m_type != Log::None) { - write("\033[0m", 4); - } - - if (m_newline) { - char newline = '\n'; - write(&newline, 1); - } - } - - void DebugLogStream::color() const - { - const char* color = ""; - if (m_type == Log::Info) { - color = "\x1B[34m"; - } - else if (m_type == Log::Warn) { - color = "\x1B[33m"; - } - else if (m_type == Log::Danger) { - color = "\x1B[31m"; - } - else if (m_type == Log::Success) { - color = "\x1B[32m"; - } - else if (m_type == Log::Comment) { - color = "\x1B[37m"; - } - - if (color[0] != '\0') { - write(color, 5); - } - } - } diff --git a/inferno/src/inferno/io/log.h b/inferno/src/inferno/io/log.h index d4672cd..9ce2c8a 100644 --- a/inferno/src/inferno/io/log.h +++ b/inferno/src/inferno/io/log.h @@ -1,7 +1,10 @@ #ifndef LOG_H #define LOG_H -#include // printf +#define BUFFER_SIZE 128 + +#include // size_t +#include // memcpy #include // std::string #include // std::string_view #include // std::forward @@ -17,7 +20,7 @@ namespace Inferno { Comment, }; -// ---------------------------------------- +// ----------------------------------------- class LogStream { public: @@ -28,9 +31,59 @@ namespace Inferno { virtual void write(const unsigned char* characters, int length) const = 0; }; -// ---------------------------------------- +// ----------------------------------------- + + class BufferedLogStream : public LogStream { + public: + BufferedLogStream() {} + virtual ~BufferedLogStream(); + + inline virtual void write(const char* characters, int length) const override + { + write(reinterpret_cast(characters), length); + } + + inline virtual void write(const unsigned char* characters, int length) const override + { + size_t newSize = m_count + length; + + if (newSize > m_capacity) { + grow(length); + } + + // Append to buffer + memcpy(buffer() + m_count, characters, length); + + m_count = newSize; + } + + protected: + inline unsigned char* buffer() const + { + if (m_capacity <= sizeof(m_buffer.stack)) { + return m_buffer.stack; + } + + return m_buffer.heap; + } + + inline bool empty() const { return m_count == 0; } + inline size_t count() const { return m_count; } + + private: + void grow(size_t bytes) const; + + mutable size_t m_count { 0 }; + mutable size_t m_capacity { BUFFER_SIZE }; + union { + mutable unsigned char* heap { nullptr }; + mutable unsigned char stack[BUFFER_SIZE]; + } m_buffer; + }; + +// ----------------------------------------- - class DebugLogStream final : public LogStream { + class DebugLogStream final : public BufferedLogStream { public: DebugLogStream(): m_newline(true), m_type(Log::None) {} @@ -44,26 +97,12 @@ namespace Inferno { void color() const; - inline virtual void write(const char* characters, int length) const override - { - for (int i = 0; i < length; i++) { - printf("%c", characters[i]); - } - } - - inline virtual void write(const unsigned char* characters, int length) const override - { - for (int i = 0; i < length; i++) { - printf("%c", characters[i]); - } - } - private: bool m_newline; Log m_type; }; -// ---------------------------------------- +// ----------------------------------------- const LogStream& operator<<(const LogStream& stream, const char* value); const LogStream& operator<<(const LogStream& stream, const unsigned char* value); @@ -83,13 +122,15 @@ namespace Inferno { const LogStream& operator<<(const LogStream& stream, bool value); const LogStream& operator<<(const LogStream& stream, Log value); -// ---------------------------------------- +// ----------------------------------------- DebugLogStream dbg(); DebugLogStream dbg(bool newline); DebugLogStream dbg(Log type); DebugLogStream dbg(Log type, bool newline); +// ----------------------------------------- + void dbgln(Log type, bool newline); void dbgln(const char* format); void dbgln(Log type, const char* format);