You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
119 lines
2.9 KiB
119 lines
2.9 KiB
/* |
|
* Copyright (C) 2022 Riyyi |
|
* |
|
* SPDX-License-Identifier: MIT |
|
*/ |
|
|
|
#pragma once |
|
|
|
#include <cstddef> // size_t |
|
#include <span> |
|
#include <sstream> // stringstream |
|
#include <string> |
|
#include <string_view> |
|
|
|
#include "util/format/formatter.h" |
|
|
|
namespace Util::Format { |
|
|
|
class Builder; |
|
class Parser; |
|
|
|
struct Parameter { |
|
const void* value; |
|
void (*format)(Builder& builder, Parser& parser, const void* value); |
|
}; |
|
|
|
template<typename T> |
|
void formatParameterValue(Builder& builder, Parser& parser, const void* value) |
|
{ |
|
Formatter<T> formatter; |
|
formatter.parse(parser); |
|
formatter.format(builder, *static_cast<const T*>(value)); |
|
} |
|
|
|
// Type erasure improves both compile time and binary size significantly |
|
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::span<const Parameter> m_parameters; |
|
}; |
|
|
|
template<typename... Parameters> |
|
class VariadicParameters final : public TypeErasedParameters { |
|
public: |
|
VariadicParameters(const Parameters&... parameters) |
|
: m_templatedParameters({ { ¶meters, formatParameterValue<Parameters> }... }) |
|
{ |
|
m_parameters = m_templatedParameters; |
|
} |
|
|
|
private: |
|
std::array<Parameter, sizeof...(Parameters)> m_templatedParameters; |
|
}; |
|
|
|
// ----------------------------------------- |
|
|
|
void variadicFormatImpl(Builder& builder, Parser& parser, TypeErasedParameters& parameters); |
|
void variadicFormat(std::stringstream& stream, std::string_view format, TypeErasedParameters& parameters); |
|
|
|
// ----------------------------------------- |
|
|
|
template<typename... Parameters> |
|
std::string format(std::string_view format, const Parameters&... parameters) |
|
{ |
|
std::stringstream stream; |
|
VariadicParameters variadicParameters { parameters... }; |
|
variadicFormat(stream, format, variadicParameters); |
|
return stream.str(); |
|
} |
|
|
|
template<typename... Parameters> |
|
void formatTo(std::string& output, std::string_view format, const Parameters&... parameters) |
|
{ |
|
std::stringstream stream; |
|
VariadicParameters variadicParameters { parameters... }; |
|
variadicFormat(stream, format, variadicParameters); |
|
output += stream.str(); |
|
} |
|
|
|
// ----------------------------------------- |
|
|
|
class FormatOperatorStyle { |
|
public: |
|
FormatOperatorStyle(std::string& output); |
|
virtual ~FormatOperatorStyle(); |
|
|
|
Builder& builder() { return m_builder; } |
|
|
|
private: |
|
std::string& m_output; |
|
std::stringstream m_stream; |
|
Builder m_builder; |
|
}; |
|
|
|
template<typename T> |
|
const FormatOperatorStyle& operator<<(const FormatOperatorStyle& formatOperatorStyle, const T& value) |
|
{ |
|
_format(const_cast<FormatOperatorStyle&>(formatOperatorStyle).builder(), value); |
|
return formatOperatorStyle; |
|
} |
|
|
|
FormatOperatorStyle formatTo(std::string& output); |
|
|
|
} // namespace Util::Format |
|
|
|
namespace Util { |
|
|
|
using Util::Format::format; |
|
using Util::Format::formatTo; |
|
|
|
} // namespace Util
|
|
|