diff --git a/src/util/format/format.cpp b/src/util/format/format.cpp index dbb6517..c2c5812 100644 --- a/src/util/format/format.cpp +++ b/src/util/format/format.cpp @@ -47,170 +47,21 @@ void variadicFormat(std::stringstream& stream, std::string_view format, TypeEras // ----------------------------------------- -void prettyVariadicFormat(Type type, bool bold, std::string_view format, TypeErasedParameters& parameters) -{ - std::stringstream stream; - - if (type != Type::None || bold) { - stream << "\033["; - switch (type) { - case Type::Info: - stream << "34"; - break; - case Type::Warn: - stream << "33"; - break; - case Type::Critital: - stream << "31"; - break; - case Type::Success: - stream << "32"; - break; - case Type::Comment: - stream << "37"; - break; - default: - break; - }; - - if (bold) { - stream << ";1"; - } - stream << "m"; - } - - variadicFormat(stream, format, parameters); - - if (type != Type::None || bold) { - stream << "\033[0m"; - } - - printf("%s\n", stream.str().c_str()); -} - -// ----------------------------------------- - -Dbg::Dbg(Type type, bool bold) - : m_type(type) - , m_bold(bold) - , m_stream() - , m_builder(m_stream) -{ - if (type != Type::None || m_bold) { - m_stream << "\033["; - switch (type) { - case Type::Info: - m_stream << "34"; - break; - case Type::Warn: - m_stream << "33"; - break; - case Type::Critical: - m_stream << "31"; - break; - case Type::Success: - m_stream << "32"; - break; - case Type::Comment: - m_stream << "37"; - break; - default: - break; - }; - - if (m_bold) { - m_stream << ";1"; - } - m_stream << "m"; - } -} - -Dbg::~Dbg() -{ - if (m_type != Type::None || m_bold) { - m_stream << "\033[0m"; - } - - printf("%s", m_stream.str().c_str()); -} - -Dbg dbg() -{ - return Dbg(Type::None, false); -} - -Dbg dbgb() -{ - return Dbg(Type::None, true); -} - -Dbg info() -{ - return Dbg(Type::Info, false); -} - -Dbg infob() -{ - return Dbg(Type::Info, true); -} - -Dbg warn() -{ - return Dbg(Type::Warn, false); -} - -Dbg warnb() -{ - return Dbg(Type::Warn, true); -} - -Dbg critical() -{ - return Dbg(Type::Critical, false); -} - -Dbg criticalb() -{ - return Dbg(Type::Critical, true); -} - -Dbg success() -{ - return Dbg(Type::Success, false); -} - -Dbg successb() -{ - return Dbg(Type::Success, true); -} - -Dbg comment() -{ - return Dbg(Type::Comment, false); -} - -Dbg commentb() -{ - return Dbg(Type::Comment, true); -} - -// ----------------------------------------- - -Str::Str(std::string& fill) - : m_fill(fill) +FormatAngleBracket::FormatAngleBracket(std::string& output) + : m_output(output) , m_stream() , m_builder(m_stream) { } -Str::~Str() +FormatAngleBracket::~FormatAngleBracket() { - m_fill = m_stream.str(); + m_output = m_stream.str(); } -Str str(std::string& fill) +FormatAngleBracket formatTo(std::string& output) { - return Str(fill); + return FormatAngleBracket(output); } } // namespace Util::Format diff --git a/src/util/format/format.h b/src/util/format/format.h index 6bb1dd6..665834e 100644 --- a/src/util/format/format.h +++ b/src/util/format/format.h @@ -26,7 +26,7 @@ struct Parameter { template void formatParameterValue(Builder& builder, const void* value) { - format(builder, *static_cast(value)); + _format(builder, *static_cast(value)); } // Type erasure improves both compile time and binary size significantly @@ -64,138 +64,53 @@ void variadicFormat(std::stringstream& stream, std::string_view format, TypeEras // ----------------------------------------- -enum class Type { - None, // Foreground - Info, // Blue - Warn, // Yellow - Critical, // Red - Success, // Green - Comment, // White -}; - -void prettyVariadicFormat(Type type, bool bold, std::string_view format, TypeErasedParameters& parameters); - -#define FORMAT_FUNCTION(name, type, bold) \ - template \ - void name(const char(&format)[N] = "", const Parameters&... parameters) \ - { \ - VariadicParameters variadicParameters { parameters... }; \ - prettyVariadicFormat(Type::type, bold, { format, N - 1 }, variadicParameters); \ - } - -FORMAT_FUNCTION(dbgln, None, false); -FORMAT_FUNCTION(dbgbln, None, true); -FORMAT_FUNCTION(infoln, Info, false); -FORMAT_FUNCTION(infobln, Info, true); -FORMAT_FUNCTION(warnln, Warn, false); -FORMAT_FUNCTION(warnbln, Warn, true); -FORMAT_FUNCTION(criticalln, Critical, false); -FORMAT_FUNCTION(criticalbln, Critical, true); -FORMAT_FUNCTION(successln, Success, false); -FORMAT_FUNCTION(successbln, Success, true); -FORMAT_FUNCTION(commentln, Comment, false); -FORMAT_FUNCTION(commentbln, Comment, true); - -// ----------------------------------------- - -class Dbg { -public: - Dbg(Type type, bool bold); - virtual ~Dbg(); - - Builder& builder() { return m_builder; } - -private: - Type m_type; - bool m_bold; - - std::stringstream m_stream; - Builder m_builder; -}; - -template -const Dbg& operator<<(const Dbg& debug, const T& value) +template +std::string format(std::string_view format, const Parameters&... parameters) { - format(const_cast(debug).builder(), value); - return debug; + std::stringstream stream; + VariadicParameters variadicParameters { parameters... }; + variadicFormat(stream, format, variadicParameters); + return stream.str(); } -Dbg dbg(); -Dbg dbgb(); -Dbg info(); -Dbg infob(); -Dbg warn(); -Dbg warnb(); -Dbg critical(); -Dbg criticalb(); -Dbg success(); -Dbg successb(); -Dbg comment(); -Dbg commentb(); - -// ----------------------------------------- - template -void strln(std::string& fill, std::string_view format, const Parameters&... parameters) +void formatTo(std::string& output, std::string_view format, const Parameters&... parameters) { std::stringstream stream; VariadicParameters variadicParameters { parameters... }; variadicFormat(stream, format, variadicParameters); - stream << '\n'; - fill = stream.str(); + output += stream.str(); } -class Str { +// ----------------------------------------- + +class FormatAngleBracket { public: - Str(std::string& fill); - virtual ~Str(); + FormatAngleBracket(std::string& output); + virtual ~FormatAngleBracket(); Builder& builder() { return m_builder; } private: - std::string& m_fill; + std::string& m_output; std::stringstream m_stream; Builder m_builder; }; template -const Str& operator<<(const Str& string, const T& value) +const FormatAngleBracket& operator<<(const FormatAngleBracket& formatAngleBracket, const T& value) { - format(const_cast(string).builder(), value); - return string; + _format(const_cast(formatAngleBracket).builder(), value); + return formatAngleBracket; } -Str str(std::string& fill); +FormatAngleBracket formatTo(std::string& output); } // namespace Util::Format -using Util::Format::commentbln; -using Util::Format::commentln; -using Util::Format::criticalbln; -using Util::Format::criticalln; -using Util::Format::dbgbln; -using Util::Format::dbgln; -using Util::Format::infobln; -using Util::Format::infoln; -using Util::Format::successbln; -using Util::Format::successln; -using Util::Format::warnbln; -using Util::Format::warnln; - -using Util::Format::comment; -using Util::Format::commentb; -using Util::Format::critical; -using Util::Format::criticalb; -using Util::Format::dbg; -using Util::Format::dbgb; -using Util::Format::info; -using Util::Format::infob; -using Util::Format::success; -using Util::Format::successb; -using Util::Format::warn; -using Util::Format::warnb; - -using Util::Format::str; -using Util::Format::strln; - -using FormatBuilder = Util::Format::Builder; +namespace Util { + +using Util::Format::format; +using Util::Format::formatTo; + +} // namespace Util diff --git a/src/util/format/print.cpp b/src/util/format/print.cpp new file mode 100644 index 0000000..1916612 --- /dev/null +++ b/src/util/format/print.cpp @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include // FILE, fputs +#include // setprecision +#include // defaultfloat, fixed +#include // stringstream +#include +#include + +#include "util/format/print.h" + +namespace Util::Format { + +void printTimeElapsedAndTypePrefix(std::stringstream& stream, Type type, bool bold) +{ + stream << std::fixed << std::setprecision(3) + << s_timer.elapsedNanoseconds() / 1000000000.0 << "s " + << std::defaultfloat << std::setprecision(6); + + stream << "[\033["; + if (bold) { + stream << "1"; + } + switch (type) { + case Type::None: + stream << ";35mdebug"; + break; + case Type::Info: + stream << ";34minfo"; + break; + case Type::Warn: + stream << ";33mwarn"; + break; + case Type::Critical: + stream << ";31mcritical"; + break; + case Type::Success: + stream << ";32msuccess"; + break; + case Type::Comment: + stream << "mcomment"; + break; + default: + break; + }; + stream << "\033[0m] "; +} + +void prettyVariadicFormat(FILE* file, Type type, bool bold, std::string_view format, TypeErasedParameters& parameters) +{ + std::stringstream stream; + + printTimeElapsedAndTypePrefix(stream, type, bold); + + variadicFormat(stream, format, parameters); + + std::string string = stream.str(); + fputs(string.c_str(), file); +} + +// ----------------------------------------- + +FormatPrint::FormatPrint(FILE* file, Type type, bool bold) + : m_file(file) + , m_type(type) + , m_bold(bold) + , m_stream() + , m_builder(m_stream) +{ + printTimeElapsedAndTypePrefix(m_stream, type, bold); +} + +FormatPrint::~FormatPrint() +{ + std::string string = m_stream.str(); + fputs(string.c_str(), stdout); +} + +FormatPrint dbg() +{ + return FormatPrint(stdout, Type::None, false); +} + +FormatPrint dbgb() +{ + return FormatPrint(stdout, Type::None, true); +} + +FormatPrint info() +{ + return FormatPrint(stdout, Type::Info, false); +} + +FormatPrint infob() +{ + return FormatPrint(stdout, Type::Info, true); +} + +FormatPrint warn() +{ + return FormatPrint(stdout, Type::Warn, false); +} + +FormatPrint warnb() +{ + return FormatPrint(stdout, Type::Warn, true); +} + +FormatPrint critical() +{ + return FormatPrint(stderr, Type::Critical, false); +} + +FormatPrint criticalb() +{ + return FormatPrint(stderr, Type::Critical, true); +} + +FormatPrint success() +{ + return FormatPrint(stdout, Type::Success, false); +} + +FormatPrint successb() +{ + return FormatPrint(stdout, Type::Success, true); +} + +FormatPrint comment() +{ + return FormatPrint(stdout, Type::Comment, false); +} + +FormatPrint commentb() +{ + return FormatPrint(stdout, Type::Comment, true); +} + +} // namespace Util::Format diff --git a/src/util/format/print.h b/src/util/format/print.h new file mode 100644 index 0000000..bae06d4 --- /dev/null +++ b/src/util/format/print.h @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2022 Riyyi + * + * SPDX-License-Identifier: MIT + */ + +#include // FILE + +#include "util/format/format.h" +#include "util/timer.h" + +namespace Util::Format { + +static Util::Timer s_timer; + +enum class Type { + None, // Foreground + Info, // Blue + Warn, // Yellow + Critical, // Red + Success, // Green + Comment, // White +}; + +void prettyVariadicFormat(FILE* file, Type type, bool bold, std::string_view format, TypeErasedParameters& parameters); + +#define FORMAT_FUNCTION(name, type, bold) \ + template \ + void name(const char(&format)[N] = "", const Parameters&... parameters) \ + { \ + VariadicParameters variadicParameters { parameters... }; \ + prettyVariadicFormat(stdout, Type::type, bold, { format, N - 1 }, variadicParameters); \ + } \ + template \ + void name(FILE* file, const char(&format)[N] = "", const Parameters&... parameters) \ + { \ + VariadicParameters variadicParameters { parameters... }; \ + prettyVariadicFormat(file, Type::type, bold, { format, N - 1 }, variadicParameters); \ + } + +FORMAT_FUNCTION(dbgln, None, false); +FORMAT_FUNCTION(dbgbln, None, true); +FORMAT_FUNCTION(infoln, Info, false); +FORMAT_FUNCTION(infobln, Info, true); +FORMAT_FUNCTION(warnln, Warn, false); +FORMAT_FUNCTION(warnbln, Warn, true); +FORMAT_FUNCTION(criticalln, Critical, false); +FORMAT_FUNCTION(criticalbln, Critical, true); +FORMAT_FUNCTION(successln, Success, false); +FORMAT_FUNCTION(successbln, Success, true); +FORMAT_FUNCTION(commentln, Comment, false); +FORMAT_FUNCTION(commentbln, Comment, true); + +// ----------------------------------------- + +class FormatPrint { +public: + FormatPrint(FILE* file, Type type, bool bold); + virtual ~FormatPrint(); + + Builder& builder() { return m_builder; } + +private: + FILE* m_file; + Type m_type; + bool m_bold; + + std::stringstream m_stream; + Builder m_builder; +}; + +template +const FormatPrint& operator<<(const FormatPrint& formatPrint, const T& value) +{ + _format(const_cast(formatPrint).builder(), value); + return formatPrint; +} + +FormatPrint dbg(); +FormatPrint dbgb(); +FormatPrint info(); +FormatPrint infob(); +FormatPrint warn(); +FormatPrint warnb(); +FormatPrint critical(); +FormatPrint criticalb(); +FormatPrint success(); +FormatPrint successb(); +FormatPrint comment(); +FormatPrint commentb(); + +// ----------------------------------------- + +} // namespace Util::Format + +namespace Util { + +using Util::Format::commentbln; +using Util::Format::commentln; +using Util::Format::criticalbln; +using Util::Format::criticalln; +using Util::Format::dbgbln; +using Util::Format::dbgln; +using Util::Format::infobln; +using Util::Format::infoln; +using Util::Format::successbln; +using Util::Format::successln; +using Util::Format::warnbln; +using Util::Format::warnln; + +using Util::Format::comment; +using Util::Format::commentb; +using Util::Format::critical; +using Util::Format::criticalb; +using Util::Format::dbg; +using Util::Format::dbgb; +using Util::Format::info; +using Util::Format::infob; +using Util::Format::success; +using Util::Format::successb; +using Util::Format::warn; +using Util::Format::warnb; + +} // namespace Util diff --git a/src/util/format/toformat.h b/src/util/format/toformat.h index 0fba7f8..62dbfed 100644 --- a/src/util/format/toformat.h +++ b/src/util/format/toformat.h @@ -159,7 +159,7 @@ struct formatFunction { } // namespace Detail namespace { -constexpr const auto& format = Util::Detail::staticConst; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable) +constexpr const auto& _format = Util::Detail::staticConst; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable) } // namespace } // namespace Util::Format diff --git a/src/util/json/value.cpp b/src/util/json/value.cpp index 984e392..2182983 100644 --- a/src/util/json/value.cpp +++ b/src/util/json/value.cpp @@ -12,7 +12,7 @@ #include #include // move, swap -#include "util/format/format.h" +#include "util/format/builder.h" #include "util/json/array.h" #include "util/json/job.h" #include "util/json/object.h" @@ -332,7 +332,7 @@ std::ostream& operator<<(std::ostream& output, const Value& value) return output << value.dump(4); } -void format(FormatBuilder& builder, const Value& value) +void format(Util::Format::Builder& builder, const Value& value) { builder.putString(value.dump(4)); } diff --git a/src/util/json/value.h b/src/util/json/value.h index 9963d13..52ea1a6 100644 --- a/src/util/json/value.h +++ b/src/util/json/value.h @@ -13,7 +13,7 @@ #include #include // forward -#include "util/format/format.h" +#include "util/format/builder.h" #include "util/json/fromjson.h" #include "util/json/tojson.h" @@ -134,7 +134,7 @@ private: std::istream& operator>>(std::istream& input, Value& value); std::ostream& operator<<(std::ostream& output, const Value& value); -void format(FormatBuilder& builder, const Value& value); +void format(Util::Format::Builder& builder, const Value& value); } // namespace Util::JSON diff --git a/src/util/meta/assert.h b/src/util/meta/assert.h index 3b47831..2b305a4 100644 --- a/src/util/meta/assert.h +++ b/src/util/meta/assert.h @@ -67,20 +67,16 @@ inline void __assertion_failed(const char* assertion, const char* file, uint32_t // Cant use the formatting library to print asserts caused by the formatting library if (!std::string_view(function).starts_with("Util::Format::")) { std::string message; - strln(message, parameters...); + formatTo(message, parameters...); fprintf(stderr, "%s", message.c_str()); } else { fprintf(stderr, parameters...); - fprintf(stderr, "\n"); } } - else { - fprintf(stderr, "\n"); - } // Code line - fprintf(stderr, " %u | %s\033[31;1m%s\033[0m%s\n", line, + fprintf(stderr, "\n %u | %s\033[31;1m%s\033[0m%s\n", line, content.substr(0, column).c_str(), // Whitespace at front content.substr(column, assertionLength).c_str(), // Error portion content.substr(column + assertionLength).c_str()); // Rest of the line diff --git a/test/unit/testutilformat.cpp b/test/unit/testutilformat.cpp index 2e003bc..9dcc183 100644 --- a/test/unit/testutilformat.cpp +++ b/test/unit/testutilformat.cpp @@ -22,44 +22,44 @@ TEST_CASE(FormatBasicTypes) { std::string result; - strln(result, ""); + result = Util::format(""); EXPECT_EQ(result, ""); - strln(result, "{}", nullptr); + result = Util::format("{}", nullptr); EXPECT_EQ(result, "(nil)"); int* number = new int(3); - strln(result, "{}", number); + result = Util::format("{}", number); EXPECT_EQ(result.substr(0, 2), "0x"); - strln(result, "{}", true); + result = Util::format("{}", true); EXPECT_EQ(result, "true"); - strln(result, "{}", false); + result = Util::format("{}", false); EXPECT_EQ(result, "false"); - strln(result, "{}", 'c'); + result = Util::format("{}", 'c'); EXPECT_EQ(result, "c"); const char* cString = "C string"; - strln(result, "{}", cString); + result = Util::format("{}", cString); EXPECT_EQ(result, "C string"); std::string string = "string"; - strln(result, "{}", string); + result = Util::format("{}", string); EXPECT_EQ(result, "string"); std::string_view stringView = "string_view"; - strln(result, "{}", stringView); + result = Util::format("{}", stringView); EXPECT_EQ(result, "string_view"); - strln(result, "{} {}", "Hello", "World"); + result = Util::format("{} {}", "Hello", "World"); EXPECT_EQ(result, "Hello World"); - strln(result, "{{escaped braces}}"); + result = Util::format("{{escaped braces}}"); EXPECT_EQ(result, "{escaped braces}"); - strln(result, "{{braces{}}}", "Something"); + result = Util::format("{{braces{}}}", "Something"); EXPECT_EQ(result, "{bracesSomething}"); } @@ -68,35 +68,35 @@ TEST_CASE(FormatNumbers) std::string result; int32_t i32 = 68766; - strln(result, "{}", i32); // int + result = Util::format("{}", i32); // int EXPECT_EQ(result, "68766"); uint32_t u32 = 123841; // unsigned int - strln(result, "{}", u32); + result = Util::format("{}", u32); EXPECT_EQ(result, "123841"); int64_t i64 = 237942768427; // long int - strln(result, "{}", i64); + result = Util::format("{}", i64); EXPECT_EQ(result, "237942768427"); size_t u64 = 1337; // long unsigned int - strln(result, "{}", u64); + result = Util::format("{}", u64); EXPECT_EQ(result, "1337"); float f32R = 245789.70000; - strln(result, "{}", f32R); + result = Util::format("{}", f32R); EXPECT_EQ(result, "245789.7"); float f32 = 45645.3233; - strln(result, "{}", f32); + result = Util::format("{}", f32); EXPECT_EQ(result, "45645.324219"); double f64 = 87522.300000000; - strln(result, "{}", f64); + result = Util::format("{}", f64); EXPECT_EQ(result, "87522.3"); double pi = 3.14159265359; - strln(result, "{:.15}", pi); + result = Util::format("{:.15}", pi); EXPECT_EQ(result, "3.14159265359"); } @@ -105,7 +105,7 @@ TEST_CASE(FormatContainers) std::string result; std::vector vector { "thing1", "thing2", "thing3" }; - strln(result, "{}", vector); + result = Util::format("{}", vector); EXPECT_EQ(result, R"({ thing1, thing2, @@ -113,7 +113,7 @@ TEST_CASE(FormatContainers) })"); std::map map { { "thing3", 3 }, { "thing2", 2 }, { "thing1", 1 } }; - strln(result, "{}", map); + result = Util::format("{}", map); EXPECT_EQ(result, R"({ "thing1": 1, "thing2": 2, @@ -126,7 +126,7 @@ TEST_CASE(FormatContainers) { "thing1", "thing2", "thing3" }, { "thing1", "thing2", "thing3" } }; - strln(result, "{}", twoDimensionalVector); + result = Util::format("{}", twoDimensionalVector); EXPECT_EQ(result, R"({ { thing1,