Add BufferedLogStream
This commit is contained in:
@@ -1,12 +1,99 @@
|
||||
#include "inferno/assert.h"
|
||||
#include "inferno/io/log.h"
|
||||
|
||||
#include <cstring> // strlen
|
||||
#include <cstddef> // size_t
|
||||
#include <cstdio> // fwrite, snprintf
|
||||
#include <cstdlib> // malloc, free
|
||||
#include <cstring> // memcpy, strlen
|
||||
#include <string> // std::string
|
||||
#include <string_view> // 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<unsigned char*>(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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#ifndef LOG_H
|
||||
#define LOG_H
|
||||
|
||||
#include <cstdio> // printf
|
||||
#define BUFFER_SIZE 128
|
||||
|
||||
#include <cstddef> // size_t
|
||||
#include <cstring> // memcpy
|
||||
#include <string> // std::string
|
||||
#include <string_view> // std::string_view
|
||||
#include <utility> // 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 DebugLogStream final : public LogStream {
|
||||
class BufferedLogStream : public LogStream {
|
||||
public:
|
||||
BufferedLogStream() {}
|
||||
virtual ~BufferedLogStream();
|
||||
|
||||
inline virtual void write(const char* characters, int length) const override
|
||||
{
|
||||
write(reinterpret_cast<const unsigned char*>(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 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);
|
||||
|
||||
Reference in New Issue
Block a user