Riyyi
2 years ago
8 changed files with 888 additions and 0 deletions
@ -0,0 +1,6 @@
|
||||
# -*- yaml -*- |
||||
|
||||
--- |
||||
# FIXME: Figure out why NOLINTBEGIN/NOLINTEND doesnt work |
||||
Checks: -misc-unused-using-decls |
||||
... |
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#include <cstddef> // size_t |
||||
#include <iomanip> // setprecision |
||||
#include <ios> // fixed |
||||
#include <limits> // numeric_limits |
||||
#include <sstream> // stringstream |
||||
#include <string> |
||||
#include <string_view> |
||||
|
||||
#include "util/format/builder.h" |
||||
|
||||
namespace Util::Format { |
||||
|
||||
void Builder::putLiteral(std::string_view literal) |
||||
{ |
||||
for (size_t i = 0; i < literal.length(); ++i) { |
||||
putCharacter(literal[i]); |
||||
if (literal[i] == '{' || literal[i] == '}') { |
||||
++i; |
||||
} |
||||
} |
||||
} |
||||
|
||||
void Builder::putF32(float number, size_t precision) const |
||||
{ |
||||
precision = (precision > std::numeric_limits<float>::digits10) ? m_precision : precision; |
||||
|
||||
std::stringstream stream; |
||||
stream |
||||
<< std::fixed |
||||
<< std::setprecision(precision) |
||||
<< number; |
||||
std::string string = stream.str(); |
||||
string = string.substr(0, string.find_first_of('0', string.find('.'))); |
||||
m_builder << string; |
||||
} |
||||
|
||||
void Builder::putF64(double number, size_t precision) const |
||||
{ |
||||
precision = (precision > std::numeric_limits<double>::digits10) ? m_precision : precision; |
||||
|
||||
std::stringstream stream; |
||||
stream |
||||
<< std::fixed |
||||
<< std::setprecision(precision) |
||||
<< number; |
||||
std::string string = stream.str(); |
||||
string = string.substr(0, string.find_first_of('0', string.find('.'))); |
||||
m_builder << string; |
||||
} |
||||
|
||||
void Builder::resetSpecifiers() |
||||
{ |
||||
setPrecision(); |
||||
} |
||||
|
||||
} // namespace Util::Format
|
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#ifndef UTIL_FORMAT_BUILDER_H |
||||
#define UTIL_FORMAT_BUILDER_H |
||||
|
||||
#include <cstddef> // size_t |
||||
#include <cstdint> // int32_t, uint32_t, int64_t |
||||
#include <sstream> // stringstream |
||||
#include <string_view> |
||||
|
||||
namespace Util::Format { |
||||
|
||||
class Builder { |
||||
public: |
||||
explicit Builder(std::stringstream& builder) |
||||
: m_precision(6) |
||||
, m_builder(builder) |
||||
{ |
||||
} |
||||
|
||||
void putLiteral(std::string_view literal); |
||||
|
||||
void putI32(int32_t number) const { m_builder << number; } // int
|
||||
void putU32(uint32_t number) const { m_builder << number; } // unsigned int
|
||||
void putI64(int64_t number) const { m_builder << number; } // long int
|
||||
void putU64(size_t number) const { m_builder << number; } // long unsigned int
|
||||
void putF32(float number, size_t precision = -1) const; |
||||
void putF64(double number, size_t precision = -1) const; |
||||
void putCharacter(char character) const { m_builder.write(&character, 1); } |
||||
void putString(const std::string_view string) const { m_builder.write(string.data(), string.length()); } |
||||
void putPointer(const void* pointer) const { m_builder << pointer; } |
||||
|
||||
void resetSpecifiers(); |
||||
void setPrecision(size_t precision = 6) { m_precision = precision; }; |
||||
|
||||
const std::stringstream& builder() const { return m_builder; } |
||||
std::stringstream& builder() { return m_builder; } |
||||
|
||||
private: |
||||
size_t m_precision { 6 }; |
||||
std::stringstream& m_builder; |
||||
}; |
||||
|
||||
} // namespace Util::Format
|
||||
|
||||
#endif // UTIL_FORMAT_BUILDER_H
|
@ -0,0 +1,216 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#include <sstream> // stringstream |
||||
#include <string> |
||||
#include <string_view> |
||||
|
||||
#include "util/format/builder.h" |
||||
#include "util/format/format.h" |
||||
#include "util/format/parser.h" |
||||
|
||||
namespace Util::Format { |
||||
|
||||
void variadicFormatImpl(Builder& builder, Parser& parser, TypeErasedParameters& parameters) |
||||
{ |
||||
const auto literal = parser.consumeLiteral(); |
||||
builder.putLiteral(literal); |
||||
|
||||
if (!parameters.isEOF()) { |
||||
std::string_view specifier; |
||||
if (parser.consumeSpecifier(specifier)) { |
||||
parser.applySpecifier(builder, specifier); |
||||
} |
||||
|
||||
auto& parameter = parameters.parameter(parameters.tell()); |
||||
parameter.format(builder, parameter.value); |
||||
parameters.ignore(); |
||||
|
||||
builder.resetSpecifiers(); |
||||
} |
||||
|
||||
if (!parser.isEOF()) { |
||||
variadicFormatImpl(builder, parser, parameters); |
||||
} |
||||
} |
||||
|
||||
void variadicFormat(std::stringstream& stream, std::string_view format, TypeErasedParameters& parameters) |
||||
{ |
||||
Builder builder { stream }; |
||||
Parser parser { format, parameters.size() }; |
||||
|
||||
variadicFormatImpl(builder, parser, parameters); |
||||
} |
||||
|
||||
// -----------------------------------------
|
||||
|
||||
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::Danger: |
||||
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::Danger: |
||||
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 danger() |
||||
{ |
||||
return Dbg(Type::Danger, false); |
||||
} |
||||
|
||||
Dbg dangerb() |
||||
{ |
||||
return Dbg(Type::Danger, 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_builder(m_stream) |
||||
{ |
||||
} |
||||
|
||||
Str::~Str() |
||||
{ |
||||
m_fill = m_stream.str(); |
||||
} |
||||
|
||||
Str str(std::string& fill) |
||||
{ |
||||
return Str(fill); |
||||
} |
||||
|
||||
} // namespace Util::Format
|
@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#ifndef UTIL_FORMAT_FORMAT_H |
||||
#define UTIL_FORMAT_FORMAT_H |
||||
|
||||
#include <cstddef> // size_t |
||||
#include <sstream> // stringstream |
||||
#include <string> |
||||
#include <string_view> |
||||
#include <vector> |
||||
|
||||
#include "util/format/builder.h" |
||||
#include "util/format/parser.h" |
||||
#include "util/format/toformat.h" |
||||
|
||||
namespace Util::Format { |
||||
|
||||
struct Parameter { |
||||
const void* value; |
||||
void (*format)(Builder& builder, const void* value); |
||||
}; |
||||
|
||||
template<typename T> |
||||
void formatParameterValue(Builder& builder, const void* value) |
||||
{ |
||||
format(builder, *static_cast<const T*>(value)); |
||||
} |
||||
|
||||
class TypeErasedParameters { |
||||
public: |
||||
const Parameter parameter(size_t index) { return m_parameters[index]; } |
||||
|
||||
size_t tell() const { return m_index; } |
||||
size_t size() const { return m_parameters.size(); } |
||||
bool isEOF() const { return m_index >= m_parameters.size(); } |
||||
void ignore() { m_index++; } |
||||
|
||||
protected: |
||||
size_t m_index { 0 }; |
||||
std::vector<Parameter> m_parameters; |
||||
}; |
||||
|
||||
template<typename... Parameters> |
||||
class VariadicParameters final : public TypeErasedParameters { |
||||
public: |
||||
VariadicParameters(const Parameters&... parameters) |
||||
{ |
||||
m_parameters = { { ¶meters, formatParameterValue<Parameters> }... }; |
||||
} |
||||
}; |
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void variadicFormatImpl(Builder& builder, Parser& parser, TypeErasedParameters& parameters); |
||||
void variadicFormat(std::stringstream& stream, std::string_view format, TypeErasedParameters& parameters); |
||||
|
||||
// -----------------------------------------
|
||||
|
||||
enum class Type { |
||||
None, // Foreground
|
||||
Info, // Blue
|
||||
Warn, // Yellow
|
||||
Danger, // 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(dangerln, Danger, false); |
||||
FORMAT_FUNCTION(dangerbln, Danger, 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); |
||||
return debug; |
||||
} |
||||
|
||||
Dbg dbg(); |
||||
Dbg dbgb(); |
||||
Dbg info(); |
||||
Dbg infob(); |
||||
Dbg warn(); |
||||
Dbg warnb(); |
||||
Dbg danger(); |
||||
Dbg dangerb(); |
||||
Dbg success(); |
||||
Dbg successb(); |
||||
Dbg comment(); |
||||
Dbg commentb(); |
||||
|
||||
// -----------------------------------------
|
||||
|
||||
template<typename... Parameters> |
||||
void strln(std::string& fill, std::string_view format, const Parameters&... parameters) |
||||
{ |
||||
std::stringstream stream; |
||||
VariadicParameters variadicParameters { parameters... }; |
||||
variadicFormat(stream, format, variadicParameters); |
||||
fill = stream.str(); |
||||
} |
||||
|
||||
class Str { |
||||
public: |
||||
Str(std::string& fill); |
||||
virtual ~Str(); |
||||
|
||||
Builder& builder() { return m_builder; } |
||||
|
||||
private: |
||||
std::string& m_fill; |
||||
std::stringstream m_stream; |
||||
Builder m_builder; |
||||
}; |
||||
|
||||
template<typename T> |
||||
const Str& operator<<(const Str& string, const T& value) |
||||
{ |
||||
format(const_cast<Str&>(string).builder(), value); |
||||
return string; |
||||
} |
||||
|
||||
Str str(std::string& fill); |
||||
|
||||
} // namespace Util::Format
|
||||
|
||||
using Util::Format::commentbln; |
||||
using Util::Format::commentln; |
||||
using Util::Format::dangerbln; |
||||
using Util::Format::dangerln; |
||||
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::danger; |
||||
using Util::Format::dangerb; |
||||
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; |
||||
|
||||
#endif // UTIL_FORMAT_FORMAT_H
|
@ -0,0 +1,151 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#include <algorithm> // replace |
||||
#include <cassert> // assert |
||||
#include <cstddef> // size_t |
||||
#include <string> |
||||
#include <string_view> |
||||
|
||||
#include "util/format/builder.h" |
||||
#include "util/format/parser.h" |
||||
|
||||
namespace Util::Format { |
||||
|
||||
Parser::Parser(std::string_view format, size_t parameterCount) |
||||
: GenericLexer(format) |
||||
, m_parameterCount(parameterCount) |
||||
{ |
||||
checkFormatParameterConsistency(); |
||||
} |
||||
|
||||
Parser::~Parser() |
||||
{ |
||||
} |
||||
|
||||
// -----------------------------------------
|
||||
|
||||
void Parser::checkFormatParameterConsistency() |
||||
{ |
||||
size_t length = m_input.length(); |
||||
|
||||
// Format string does not reference all passed parameters
|
||||
assert(length >= m_parameterCount * 2); |
||||
|
||||
size_t braceOpen = 0; |
||||
size_t braceClose = 0; |
||||
while (!isEOF()) { |
||||
char peek0 = peek(); |
||||
char peek1 = peek(1); |
||||
|
||||
if (peek0 == '{' && peek1 == '{') { |
||||
ignore(2); |
||||
continue; |
||||
} |
||||
|
||||
if (peek0 == '}' && peek1 == '}') { |
||||
ignore(2); |
||||
continue; |
||||
} |
||||
|
||||
if (peek0 == '{') { |
||||
braceOpen++; |
||||
|
||||
// Only empty references {} or specified references {:} are valid
|
||||
assert(peek1 == '}' || peek1 == ':'); |
||||
} |
||||
if (peek0 == '}') { |
||||
braceClose++; |
||||
} |
||||
|
||||
ignore(); |
||||
} |
||||
m_index = 0; |
||||
|
||||
// Extra open braces in format string
|
||||
assert(!(braceOpen < braceClose)); |
||||
|
||||
// Extra closing braces in format string
|
||||
assert(!(braceOpen > braceClose)); |
||||
|
||||
// Format string does not reference all passed parameters
|
||||
assert(!(braceOpen < m_parameterCount)); |
||||
|
||||
// Format string references nonexistent parameter
|
||||
assert(!(braceOpen > m_parameterCount)); |
||||
} |
||||
|
||||
std::string_view Parser::consumeLiteral() |
||||
{ |
||||
const auto begin = tell(); |
||||
|
||||
while (!isEOF()) { |
||||
char peek0 = peek(); |
||||
char peek1 = peek(1); |
||||
|
||||
if (peek0 == '{' && peek1 == '{') { |
||||
ignore(2); |
||||
continue; |
||||
} |
||||
|
||||
if (peek0 == '}' && peek1 == '}') { |
||||
ignore(2); |
||||
continue; |
||||
} |
||||
|
||||
// Get literal before the specifier {}
|
||||
if (peek0 == '{' || peek0 == '}') { |
||||
return m_input.substr(begin, tell() - begin); |
||||
} |
||||
|
||||
ignore(); |
||||
} |
||||
|
||||
return m_input.substr(begin); |
||||
} |
||||
|
||||
bool Parser::consumeSpecifier(std::string_view& specifier) |
||||
{ |
||||
if (!consumeSpecific('{')) { |
||||
return false; |
||||
} |
||||
|
||||
if (!consumeSpecific(':')) { |
||||
assert(consumeSpecific('}')); |
||||
specifier = ""; |
||||
} |
||||
else { |
||||
const auto begin = tell(); |
||||
|
||||
// Go until AFTER the closing brace
|
||||
while (peek(-1) != '}') { |
||||
consume(); |
||||
} |
||||
|
||||
specifier = m_input.substr(begin, tell() - begin - 1); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
void Parser::applySpecifier(Builder& builder, std::string_view specifier) |
||||
{ |
||||
if (specifier[0] == '.') { |
||||
size_t value = 0; |
||||
|
||||
for (size_t i = 1; i < specifier.length(); ++i) { |
||||
if (specifier[i] < '0' || specifier[i] > '9') { |
||||
return; |
||||
} |
||||
value *= 10; |
||||
value += specifier[i] - '0'; // Subtract ASCII 48 to get the number
|
||||
} |
||||
|
||||
builder.setPrecision(value); |
||||
} |
||||
} |
||||
|
||||
} // namespace Util::Format
|
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#ifndef UTIL_FORMAT_PARSER_H |
||||
#define UTIL_FORMAT_PARSER_H |
||||
|
||||
#include <cstddef> // size_t |
||||
#include <string_view> |
||||
|
||||
#include "util/genericlexer.h" |
||||
|
||||
namespace Util::Format { |
||||
|
||||
class Builder; |
||||
|
||||
class Parser final : public GenericLexer { |
||||
public: |
||||
Parser(std::string_view format, size_t parameterCount); |
||||
virtual ~Parser(); |
||||
|
||||
void checkFormatParameterConsistency(); |
||||
|
||||
std::string_view consumeLiteral(); |
||||
bool consumeSpecifier(std::string_view& specifier); |
||||
|
||||
void applySpecifier(Builder& builder, std::string_view specifier); |
||||
|
||||
private: |
||||
size_t m_parameterCount { 0 }; |
||||
}; |
||||
|
||||
} // namespace Util::Format
|
||||
|
||||
#endif // UTIL_FORMAT_PARSER_H
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Riyyi |
||||
* |
||||
* SPDX-License-Identifier: MIT |
||||
*/ |
||||
|
||||
#ifndef UTIL_TO_FORMAT_H |
||||
#define UTIL_TO_FORMAT_H |
||||
|
||||
#include <cstddef> // nullptr_t |
||||
#include <cstdint> // int64_t |
||||
#include <cstring> // strlen |
||||
#include <iterator> // next |
||||
#include <map> |
||||
#include <string> |
||||
#include <string_view> |
||||
#include <unordered_map> |
||||
#include <utility> // forward |
||||
#include <vector> |
||||
|
||||
#include "util/meta/odr.h" |
||||
|
||||
namespace Util::Format { |
||||
|
||||
namespace Detail { |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, std::nullptr_t) |
||||
{ |
||||
builder.putString("(nil)"); |
||||
} |
||||
|
||||
template<typename FormatBuilder, typename T> |
||||
void format(FormatBuilder& builder, T* pointer) |
||||
{ |
||||
builder.putPointer(static_cast<const void*>(pointer)); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, bool boolean) |
||||
{ |
||||
builder.putString(boolean ? "true" : "false"); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, int32_t number) // int
|
||||
{ |
||||
builder.putI32(number); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, uint32_t number) // unsigned int
|
||||
{ |
||||
builder.putU32(number); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, int64_t number) // long int
|
||||
{ |
||||
builder.putI64(number); |
||||
} |
||||
|
||||
template<typename FormatBuilder> // uint64_t
|
||||
void format(FormatBuilder& builder, size_t number) // long unsigned int
|
||||
{ |
||||
builder.putU64(number); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, float number) |
||||
{ |
||||
builder.putF32(number); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, double number) |
||||
{ |
||||
builder.putF64(number); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, char character) |
||||
{ |
||||
builder.putCharacter(character); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, const char* string) |
||||
{ |
||||
builder.putString({ string, strlen(string) }); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, const std::string& string) |
||||
{ |
||||
builder.putString(string); |
||||
} |
||||
|
||||
template<typename FormatBuilder> |
||||
void format(FormatBuilder& builder, std::string_view string) |
||||
{ |
||||
builder.putString(string); |
||||
} |
||||
|
||||
template<typename FormatBuilder, typename T> |
||||
void format(FormatBuilder& builder, const std::vector<T>& array) |
||||
{ |
||||
builder.putString("{\n"); |
||||
for (auto it = array.cbegin(); it != array.cend(); ++it) { |
||||
builder.putString(" "); |
||||
format(builder, *it); |
||||
|
||||
// Add comma, except after the last element
|
||||
if (it != std::prev(array.end(), 1)) { |
||||
builder.putCharacter(','); |
||||
} |
||||
builder.putCharacter('\n'); |
||||
} |
||||
builder.putCharacter('}'); |
||||
} |
||||
|
||||
#define FORMAT_MAP \ |
||||
builder.putString("{\n"); \
|
||||
auto last = map.end(); \
|
||||
for (auto it = map.begin(); it != last; ++it) { \
|
||||
builder.putString(R"( ")"); \
|
||||
format(builder, it->first); \
|
||||
builder.putString(R"(": )"); \
|
||||
format(builder, it->second); \
|
||||
\
|
||||
/* Add comma, except after the last element */ \
|
||||
if (std::next(it) != last) { \
|
||||
builder.putCharacter(','); \
|
||||
} \
|
||||
\
|
||||
builder.putCharacter('\n'); \
|
||||
} \
|
||||
builder.putCharacter('}'); |
||||
|
||||
template<typename FormatBuilder, typename K, typename V> |
||||
void format(FormatBuilder& builder, const std::map<K, V>& map) |
||||
{ |
||||
FORMAT_MAP; |
||||
} |
||||
|
||||
template<typename FormatBuilder, typename K, typename V> |
||||
void format(FormatBuilder& builder, const std::unordered_map<K, V>& map) |
||||
{ |
||||
FORMAT_MAP; |
||||
} |
||||
|
||||
struct formatFunction { |
||||
template<typename FormatBuilder, typename T> |
||||
auto operator()(FormatBuilder& builder, T&& value) const |
||||
{ |
||||
return format(builder, std::forward<T>(value)); |
||||
} |
||||
}; |
||||
|
||||
} // namespace Detail
|
||||
|
||||
namespace { |
||||
constexpr const auto& format = Util::Detail::staticConst<Detail::formatFunction>; // NOLINT(misc-definitions-in-headers,clang-diagnostic-unused-variable)
|
||||
} // namespace
|
||||
|
||||
} // namespace Util::Format
|
||||
|
||||
#endif // UTIL_TO_FORMAT_H
|
Loading…
Reference in new issue