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)
{
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

135
src/util/format/format.h

@ -26,7 +26,7 @@ struct Parameter {
template<typename T>
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
@ -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<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)
template<typename... Parameters>
std::string format(std::string_view format, const Parameters&... parameters)
{
format(const_cast<Dbg&>(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<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;
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<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);
return string;
_format(const_cast<FormatAngleBracket&>(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

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 {
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 Util::Format

4
src/util/json/value.cpp

@ -12,7 +12,7 @@
#include <string>
#include <utility> // 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));
}

4
src/util/json/value.h

@ -13,7 +13,7 @@
#include <string>
#include <utility> // 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

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
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

46
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<std::string> 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<std::string, int> 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,

Loading…
Cancel
Save