diff --git a/src/util/format/builder.cpp b/src/util/format/builder.cpp index 49d7664..991938f 100644 --- a/src/util/format/builder.cpp +++ b/src/util/format/builder.cpp @@ -36,7 +36,6 @@ void Builder::putF32(float number, size_t precision) const << number << std::defaultfloat << std::setprecision(6); std::string string = stream.str(); - string = string.substr(0, string.find_first_of('0', string.find('.'))); m_builder << string; } @@ -50,7 +49,6 @@ void Builder::putF64(double number, size_t precision) const << number << std::defaultfloat << std::setprecision(6); std::string string = stream.str(); - string = string.substr(0, string.find_first_of('0', string.find('.'))); m_builder << string; } diff --git a/src/util/format/log.cpp b/src/util/format/log.cpp new file mode 100644 index 0000000..7e2a47c --- /dev/null +++ b/src/util/format/log.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include // FILE +#include + +#include "util/format/color.h" +#include "util/format/log.h" + +namespace Util::Format { + +std::string formatTimeElapsed() +{ + return format("{:.3}s ", s_timer.elapsedNanoseconds() / 1000000000.0); +} + +std::string formatType(Type type) +{ + std::string output; + + formatTo(output, "["); + switch (type) { + case Type::Trace: + formatTo(output, "trace"); + break; + case Type::Debug: + formatTo(output, fg(TerminalColor::Magenta), "debug"); + break; + case Type::Success: + formatTo(output, fg(TerminalColor::Green), "success"); + break; + case Type::Info: + formatTo(output, fg(TerminalColor::Blue), "info"); + break; + case Type::Warn: + formatTo(output, Emphasis::Bold | fg(TerminalColor::Yellow), "warn"); + break; + case Type::Error: + formatTo(output, Emphasis::Bold | fg(TerminalColor::Red), "error"); + break; + case Type::Critical: + formatTo(output, Emphasis::Bold | fg(TerminalColor::White) | bg(TerminalColor::Red), "critical"); + break; + default: + break; + }; + formatTo(output, "] "); + + return output; +} + +// ----------------------------------------- + +LogOperatorStyle::LogOperatorStyle(FILE* file, Type type) + : m_file(file) + , m_type(type) + , m_stream() + , m_builder(m_stream) +{ + m_stream << formatTimeElapsed(); + m_stream << formatType(type); +} + +LogOperatorStyle::~LogOperatorStyle() +{ + m_stream.write("\n", 1); + std::string string = m_stream.str(); + fputs(string.c_str(), m_file); +} + +LogOperatorStyle trace() +{ + return LogOperatorStyle(stdout, Type::Trace); +} + +LogOperatorStyle debug() +{ + return LogOperatorStyle(stdout, Type::Debug); +} + +LogOperatorStyle success() +{ + return LogOperatorStyle(stdout, Type::Success); +} + +LogOperatorStyle info() +{ + return LogOperatorStyle(stdout, Type::Info); +} + +LogOperatorStyle warn() +{ + return LogOperatorStyle(stderr, Type::Warn); +} + +LogOperatorStyle error() +{ + return LogOperatorStyle(stderr, Type::Error); +} + +LogOperatorStyle critical() +{ + return LogOperatorStyle(stderr, Type::Critical); +} + +} // namespace Util::Format diff --git a/src/util/format/log.h b/src/util/format/log.h new file mode 100644 index 0000000..509a839 --- /dev/null +++ b/src/util/format/log.h @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#pragma once + +#include // FILE, stderr, stdout +#include +#include + +#include "util/format/format.h" +#include "util/format/print.h" +#include "util/timer.h" + +namespace Util::Format { + +static Util::Timer s_timer; + +enum class Type : uint8_t { + Trace, // White + Debug, // Purple + Success, // Green + Info, // Blue + Warn, // Bold yellow + Error, // Bold red + Critical, // Bold on red +}; + +std::string formatTimeElapsed(); +std::string formatType(Type type); + +#define LOG_FUNCTION(name, file, type) \ + template \ + void name(const char(&format)[N], const Parameters&... parameters) \ + { \ + print(file, "{}", formatTimeElapsed()); \ + print(file, "{}", formatType(type)); \ + VariadicParameters variadicParameters { parameters... }; \ + print(file, format, variadicParameters); \ + print(file, "\n"); \ + } + +LOG_FUNCTION(trace, stdout, Type::Trace); +LOG_FUNCTION(debug, stdout, Type::Debug); +LOG_FUNCTION(success, stdout, Type::Success); +LOG_FUNCTION(info, stdout, Type::Info); +LOG_FUNCTION(warn, stderr, Type::Warn); +LOG_FUNCTION(error, stderr, Type::Error); +LOG_FUNCTION(critical, stderr, Type::Critical); + +// ----------------------------------------- + +class LogOperatorStyle { +public: + LogOperatorStyle(FILE* file, Type type); + virtual ~LogOperatorStyle(); + + Builder& builder() { return m_builder; } + +private: + FILE* m_file; + Type m_type; + + std::stringstream m_stream; + Builder m_builder; +}; + +template +const LogOperatorStyle& operator<<(const LogOperatorStyle& logOperatorStyle, const T& value) +{ + _format(const_cast(logOperatorStyle).builder(), value); + return logOperatorStyle; +} + +LogOperatorStyle trace(); +LogOperatorStyle debug(); +LogOperatorStyle success(); +LogOperatorStyle info(); +LogOperatorStyle warn(); +LogOperatorStyle error(); +LogOperatorStyle critical(); + +} // namespace Util::Format + +namespace Util { + +using Util::Format::critical; +using Util::Format::debug; +using Util::Format::error; +using Util::Format::info; +using Util::Format::success; +using Util::Format::trace; +using Util::Format::warn; + +} // namespace Util diff --git a/test/unit/testutilformat.cpp b/test/unit/testutilformat.cpp index 9dcc183..0a3ed4f 100644 --- a/test/unit/testutilformat.cpp +++ b/test/unit/testutilformat.cpp @@ -85,7 +85,7 @@ TEST_CASE(FormatNumbers) float f32R = 245789.70000; result = Util::format("{}", f32R); - EXPECT_EQ(result, "245789.7"); + EXPECT_EQ(result, "245789.703125"); float f32 = 45645.3233; result = Util::format("{}", f32); @@ -93,11 +93,11 @@ TEST_CASE(FormatNumbers) double f64 = 87522.300000000; result = Util::format("{}", f64); - EXPECT_EQ(result, "87522.3"); + EXPECT_EQ(result, "87522.300000"); double pi = 3.14159265359; result = Util::format("{:.15}", pi); - EXPECT_EQ(result, "3.14159265359"); + EXPECT_EQ(result, "3.141592653590000"); } TEST_CASE(FormatContainers)