Browse Source

Util+Test: Separate formatting and printing into different files

master
Riyyi 2 years ago
parent
commit
33df4bef39
  1. 161
      src/util/format/format.cpp
  2. 135
      src/util/format/format.h
  3. 143
      src/util/format/print.cpp
  4. 124
      src/util/format/print.h
  5. 2
      src/util/format/toformat.h
  6. 4
      src/util/json/value.cpp
  7. 4
      src/util/json/value.h
  8. 8
      src/util/meta/assert.h
  9. 46
      test/unit/testutilformat.cpp

161
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) FormatAngleBracket::FormatAngleBracket(std::string& output)
{ : m_output(output)
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)
, m_stream() , m_stream()
, m_builder(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 } // namespace Util::Format

135
src/util/format/format.h

@ -26,7 +26,7 @@ struct Parameter {
template<typename T> template<typename T>
void formatParameterValue(Builder& builder, const void* value) void formatParameterValue(Builder& builder, const void* value)
{ {
format(builder, *static_cast<const T*>(value)); _format(builder, *static_cast<const T*>(value));
} }
// Type erasure improves both compile time and binary size significantly // 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 { template<typename... Parameters>
None, // Foreground std::string format(std::string_view format, const Parameters&... parameters)
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<size_t N, typename... Parameters> \
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<typename T>
const Dbg& operator<<(const Dbg& debug, const T& value)
{ {
format(const_cast<Dbg&>(debug).builder(), value); std::stringstream stream;
return debug; 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<typename... Parameters> template<typename... Parameters>
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; std::stringstream stream;
VariadicParameters variadicParameters { parameters... }; VariadicParameters variadicParameters { parameters... };
variadicFormat(stream, format, variadicParameters); variadicFormat(stream, format, variadicParameters);
stream << '\n'; output += stream.str();
fill = stream.str();
} }
class Str { // -----------------------------------------
class FormatAngleBracket {
public: public:
Str(std::string& fill); FormatAngleBracket(std::string& output);
virtual ~Str(); virtual ~FormatAngleBracket();
Builder& builder() { return m_builder; } Builder& builder() { return m_builder; }
private: private:
std::string& m_fill; std::string& m_output;
std::stringstream m_stream; std::stringstream m_stream;
Builder m_builder; Builder m_builder;
}; };
template<typename T> template<typename T>
const Str& operator<<(const Str& string, const T& value) const FormatAngleBracket& operator<<(const FormatAngleBracket& formatAngleBracket, const T& value)
{ {
format(const_cast<Str&>(string).builder(), value); _format(const_cast<FormatAngleBracket&>(formatAngleBracket).builder(), value);
return string; return formatAngleBracket;
} }
Str str(std::string& fill); FormatAngleBracket formatTo(std::string& output);
} // namespace Util::Format } // namespace Util::Format
using Util::Format::commentbln; namespace Util {
using Util::Format::commentln;
using Util::Format::criticalbln; using Util::Format::format;
using Util::Format::criticalln; using Util::Format::formatTo;
using Util::Format::dbgbln;
using Util::Format::dbgln; } // namespace Util
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;

143
src/util/format/print.cpp

@ -0,0 +1,143 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cstdio> // FILE, fputs
#include <iomanip> // setprecision
#include <ios> // defaultfloat, fixed
#include <sstream> // stringstream
#include <string>
#include <string_view>
#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

124
src/util/format/print.h

@ -0,0 +1,124 @@
/*
* Copyright (C) 2022 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cstdio> // 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<size_t N, typename... Parameters> \
void name(const char(&format)[N] = "", const Parameters&... parameters) \
{ \
VariadicParameters variadicParameters { parameters... }; \
prettyVariadicFormat(stdout, Type::type, bold, { format, N - 1 }, variadicParameters); \
} \
template<size_t N, typename... Parameters> \
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<typename T>
const FormatPrint& operator<<(const FormatPrint& formatPrint, const T& value)
{
_format(const_cast<FormatPrint&>(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

2
src/util/format/toformat.h

@ -159,7 +159,7 @@ struct formatFunction {
} // namespace Detail } // namespace Detail
namespace { namespace {
constexpr const auto& format = Util::Detail::staticConst<Detail::formatFunction>; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable) constexpr const auto& _format = Util::Detail::staticConst<Detail::formatFunction>; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable)
} // namespace } // namespace
} // namespace Util::Format } // namespace Util::Format

4
src/util/json/value.cpp

@ -12,7 +12,7 @@
#include <string> #include <string>
#include <utility> // move, swap #include <utility> // move, swap
#include "util/format/format.h" #include "util/format/builder.h"
#include "util/json/array.h" #include "util/json/array.h"
#include "util/json/job.h" #include "util/json/job.h"
#include "util/json/object.h" #include "util/json/object.h"
@ -332,7 +332,7 @@ std::ostream& operator<<(std::ostream& output, const Value& value)
return output << value.dump(4); 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)); builder.putString(value.dump(4));
} }

4
src/util/json/value.h

@ -13,7 +13,7 @@
#include <string> #include <string>
#include <utility> // forward #include <utility> // forward
#include "util/format/format.h" #include "util/format/builder.h"
#include "util/json/fromjson.h" #include "util/json/fromjson.h"
#include "util/json/tojson.h" #include "util/json/tojson.h"
@ -134,7 +134,7 @@ private:
std::istream& operator>>(std::istream& input, Value& value); std::istream& operator>>(std::istream& input, Value& value);
std::ostream& operator<<(std::ostream& output, const 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 } // namespace Util::JSON

8
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 // Cant use the formatting library to print asserts caused by the formatting library
if (!std::string_view(function).starts_with("Util::Format::")) { if (!std::string_view(function).starts_with("Util::Format::")) {
std::string message; std::string message;
strln(message, parameters...); formatTo(message, parameters...);
fprintf(stderr, "%s", message.c_str()); fprintf(stderr, "%s", message.c_str());
} }
else { else {
fprintf(stderr, parameters...); fprintf(stderr, parameters...);
fprintf(stderr, "\n");
} }
} }
else {
fprintf(stderr, "\n");
}
// Code line // 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(0, column).c_str(), // Whitespace at front
content.substr(column, assertionLength).c_str(), // Error portion content.substr(column, assertionLength).c_str(), // Error portion
content.substr(column + assertionLength).c_str()); // Rest of the line content.substr(column + assertionLength).c_str()); // Rest of the line

46
test/unit/testutilformat.cpp

@ -22,44 +22,44 @@ TEST_CASE(FormatBasicTypes)
{ {
std::string result; std::string result;
strln(result, ""); result = Util::format("");
EXPECT_EQ(result, ""); EXPECT_EQ(result, "");
strln(result, "{}", nullptr); result = Util::format("{}", nullptr);
EXPECT_EQ(result, "(nil)"); EXPECT_EQ(result, "(nil)");
int* number = new int(3); int* number = new int(3);
strln(result, "{}", number); result = Util::format("{}", number);
EXPECT_EQ(result.substr(0, 2), "0x"); EXPECT_EQ(result.substr(0, 2), "0x");
strln(result, "{}", true); result = Util::format("{}", true);
EXPECT_EQ(result, "true"); EXPECT_EQ(result, "true");
strln(result, "{}", false); result = Util::format("{}", false);
EXPECT_EQ(result, "false"); EXPECT_EQ(result, "false");
strln(result, "{}", 'c'); result = Util::format("{}", 'c');
EXPECT_EQ(result, "c"); EXPECT_EQ(result, "c");
const char* cString = "C string"; const char* cString = "C string";
strln(result, "{}", cString); result = Util::format("{}", cString);
EXPECT_EQ(result, "C string"); EXPECT_EQ(result, "C string");
std::string string = "string"; std::string string = "string";
strln(result, "{}", string); result = Util::format("{}", string);
EXPECT_EQ(result, "string"); EXPECT_EQ(result, "string");
std::string_view stringView = "string_view"; std::string_view stringView = "string_view";
strln(result, "{}", stringView); result = Util::format("{}", stringView);
EXPECT_EQ(result, "string_view"); EXPECT_EQ(result, "string_view");
strln(result, "{} {}", "Hello", "World"); result = Util::format("{} {}", "Hello", "World");
EXPECT_EQ(result, "Hello World"); EXPECT_EQ(result, "Hello World");
strln(result, "{{escaped braces}}"); result = Util::format("{{escaped braces}}");
EXPECT_EQ(result, "{escaped braces}"); EXPECT_EQ(result, "{escaped braces}");
strln(result, "{{braces{}}}", "Something"); result = Util::format("{{braces{}}}", "Something");
EXPECT_EQ(result, "{bracesSomething}"); EXPECT_EQ(result, "{bracesSomething}");
} }
@ -68,35 +68,35 @@ TEST_CASE(FormatNumbers)
std::string result; std::string result;
int32_t i32 = 68766; int32_t i32 = 68766;
strln(result, "{}", i32); // int result = Util::format("{}", i32); // int
EXPECT_EQ(result, "68766"); EXPECT_EQ(result, "68766");
uint32_t u32 = 123841; // unsigned int uint32_t u32 = 123841; // unsigned int
strln(result, "{}", u32); result = Util::format("{}", u32);
EXPECT_EQ(result, "123841"); EXPECT_EQ(result, "123841");
int64_t i64 = 237942768427; // long int int64_t i64 = 237942768427; // long int
strln(result, "{}", i64); result = Util::format("{}", i64);
EXPECT_EQ(result, "237942768427"); EXPECT_EQ(result, "237942768427");
size_t u64 = 1337; // long unsigned int size_t u64 = 1337; // long unsigned int
strln(result, "{}", u64); result = Util::format("{}", u64);
EXPECT_EQ(result, "1337"); EXPECT_EQ(result, "1337");
float f32R = 245789.70000; float f32R = 245789.70000;
strln(result, "{}", f32R); result = Util::format("{}", f32R);
EXPECT_EQ(result, "245789.7"); EXPECT_EQ(result, "245789.7");
float f32 = 45645.3233; float f32 = 45645.3233;
strln(result, "{}", f32); result = Util::format("{}", f32);
EXPECT_EQ(result, "45645.324219"); EXPECT_EQ(result, "45645.324219");
double f64 = 87522.300000000; double f64 = 87522.300000000;
strln(result, "{}", f64); result = Util::format("{}", f64);
EXPECT_EQ(result, "87522.3"); EXPECT_EQ(result, "87522.3");
double pi = 3.14159265359; double pi = 3.14159265359;
strln(result, "{:.15}", pi); result = Util::format("{:.15}", pi);
EXPECT_EQ(result, "3.14159265359"); EXPECT_EQ(result, "3.14159265359");
} }
@ -105,7 +105,7 @@ TEST_CASE(FormatContainers)
std::string result; std::string result;
std::vector<std::string> vector { "thing1", "thing2", "thing3" }; std::vector<std::string> vector { "thing1", "thing2", "thing3" };
strln(result, "{}", vector); result = Util::format("{}", vector);
EXPECT_EQ(result, R"({ EXPECT_EQ(result, R"({
thing1, thing1,
thing2, thing2,
@ -113,7 +113,7 @@ TEST_CASE(FormatContainers)
})"); })");
std::map<std::string, int> map { { "thing3", 3 }, { "thing2", 2 }, { "thing1", 1 } }; std::map<std::string, int> map { { "thing3", 3 }, { "thing2", 2 }, { "thing1", 1 } };
strln(result, "{}", map); result = Util::format("{}", map);
EXPECT_EQ(result, R"({ EXPECT_EQ(result, R"({
"thing1": 1, "thing1": 1,
"thing2": 2, "thing2": 2,
@ -126,7 +126,7 @@ TEST_CASE(FormatContainers)
{ "thing1", "thing2", "thing3" }, { "thing1", "thing2", "thing3" },
{ "thing1", "thing2", "thing3" } { "thing1", "thing2", "thing3" }
}; };
strln(result, "{}", twoDimensionalVector); result = Util::format("{}", twoDimensionalVector);
EXPECT_EQ(result, R"({ EXPECT_EQ(result, R"({
{ {
thing1, thing1,

Loading…
Cancel
Save