Util: Use C++20 concepts for integral and floating-point types
This commit is contained in:
@@ -28,19 +28,6 @@ void Builder::putLiteral(std::string_view literal)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Builder::putF32(float number, uint8_t precision) const
|
|
||||||
{
|
|
||||||
precision = std::min(precision, static_cast<uint8_t>(std::numeric_limits<float>::digits10));
|
|
||||||
|
|
||||||
std::stringstream stream;
|
|
||||||
stream
|
|
||||||
<< std::fixed << std::setprecision(precision)
|
|
||||||
<< number
|
|
||||||
<< std::defaultfloat << std::setprecision(6);
|
|
||||||
std::string string = stream.str();
|
|
||||||
m_builder << string;
|
|
||||||
}
|
|
||||||
|
|
||||||
void Builder::putF64(double number, uint8_t precision) const
|
void Builder::putF64(double number, uint8_t precision) const
|
||||||
{
|
{
|
||||||
precision = std::min(precision, static_cast<uint8_t>(std::numeric_limits<double>::digits10));
|
precision = std::min(precision, static_cast<uint8_t>(std::numeric_limits<double>::digits10));
|
||||||
|
|||||||
@@ -36,11 +36,8 @@ public:
|
|||||||
|
|
||||||
void putLiteral(std::string_view literal);
|
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 putI64(int64_t number) const { m_builder << number; } // long int
|
||||||
void putU64(size_t number) const { m_builder << number; } // long unsigned int
|
void putU64(size_t number) const { m_builder << number; } // long unsigned int
|
||||||
void putF32(float number, uint8_t precision = 6) const;
|
|
||||||
void putF64(double number, uint8_t precision = 6) const;
|
void putF64(double number, uint8_t precision = 6) const;
|
||||||
void putCharacter(char character) const { m_builder.write(&character, 1); }
|
void putCharacter(char character) const { m_builder.write(&character, 1); }
|
||||||
void putString(std::string_view string, size_t width = 0, Align align = Align::Left, char fill = ' ') const;
|
void putString(std::string_view string, size_t width = 0, Align align = Align::Left, char fill = ' ') const;
|
||||||
|
|||||||
@@ -16,56 +16,6 @@
|
|||||||
|
|
||||||
namespace Util::Format {
|
namespace Util::Format {
|
||||||
|
|
||||||
// Integral
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void Formatter<int32_t>::format(Builder& builder, int32_t value) const
|
|
||||||
{
|
|
||||||
builder.putI32(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void Formatter<uint32_t>::format(Builder& builder, uint32_t value) const
|
|
||||||
{
|
|
||||||
builder.putU32(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void Formatter<int64_t>::format(Builder& builder, int64_t value) const
|
|
||||||
{
|
|
||||||
builder.putI64(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void Formatter<size_t>::format(Builder& builder, size_t value) const
|
|
||||||
{
|
|
||||||
builder.putU64(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Floating point
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void Formatter<float>::format(Builder& builder, float value) const
|
|
||||||
{
|
|
||||||
if (specifier.precision < 0) {
|
|
||||||
builder.putF32(value);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
builder.putF32(value, specifier.precision);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<>
|
|
||||||
void Formatter<double>::format(Builder& builder, double value) const
|
|
||||||
{
|
|
||||||
if (specifier.precision < 0) {
|
|
||||||
builder.putF64(value);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.putF64(value, specifier.precision);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Char
|
// Char
|
||||||
|
|
||||||
template<>
|
template<>
|
||||||
|
|||||||
+38
-21
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
#include "util/format/builder.h"
|
#include "util/format/builder.h"
|
||||||
#include "util/format/parser.h"
|
#include "util/format/parser.h"
|
||||||
|
#include "util/meta/concepts.h"
|
||||||
|
|
||||||
namespace Util::Format {
|
namespace Util::Format {
|
||||||
|
|
||||||
@@ -66,13 +67,7 @@ struct Formatter {
|
|||||||
|
|
||||||
constexpr void parse(Parser& parser)
|
constexpr void parse(Parser& parser)
|
||||||
{
|
{
|
||||||
if (std::is_integral_v<T>) {
|
if (std::is_same_v<T, char>) {
|
||||||
parser.parseSpecifier(specifier, Parser::ParameterType::Integral);
|
|
||||||
}
|
|
||||||
else if (std::is_floating_point_v<T>) {
|
|
||||||
parser.parseSpecifier(specifier, Parser::ParameterType::FloatingPoint);
|
|
||||||
}
|
|
||||||
else if (std::is_same_v<T, char>) {
|
|
||||||
parser.parseSpecifier(specifier, Parser::ParameterType::Char);
|
parser.parseSpecifier(specifier, Parser::ParameterType::Char);
|
||||||
}
|
}
|
||||||
else if (std::is_same_v<T, std::string_view>) {
|
else if (std::is_same_v<T, std::string_view>) {
|
||||||
@@ -80,30 +75,52 @@ struct Formatter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void format(Builder& builder, T value) const { (void)builder, (void)value; }
|
void format(Builder&, T) const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Integral
|
// Integral
|
||||||
|
|
||||||
template<>
|
template<Integral T>
|
||||||
void Formatter<int32_t>::format(Builder& builder, int32_t value) const;
|
struct Formatter<T> {
|
||||||
|
Specifier specifier;
|
||||||
|
|
||||||
template<>
|
void parse(Parser& parser)
|
||||||
void Formatter<uint32_t>::format(Builder& builder, uint32_t value) const;
|
{
|
||||||
|
parser.parseSpecifier(specifier, Parser::ParameterType::Integral);
|
||||||
|
}
|
||||||
|
|
||||||
template<>
|
void format(Builder& builder, T value) const
|
||||||
void Formatter<int64_t>::format(Builder& builder, int64_t value) const;
|
{
|
||||||
|
if (std::is_signed_v<T>) {
|
||||||
template<>
|
builder.putI64(value);
|
||||||
void Formatter<size_t>::format(Builder& builder, size_t value) const; // uint64_t
|
}
|
||||||
|
if (std::is_unsigned_v<T>) {
|
||||||
|
builder.putU64(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Floating point
|
// Floating point
|
||||||
|
|
||||||
template<>
|
template<FloatingPoint T>
|
||||||
void Formatter<float>::format(Builder& builder, float value) const;
|
struct Formatter<T> {
|
||||||
|
Specifier specifier;
|
||||||
|
|
||||||
template<>
|
void parse(Parser& parser)
|
||||||
void Formatter<double>::format(Builder& builder, double value) const;
|
{
|
||||||
|
parser.parseSpecifier(specifier, Parser::ParameterType::FloatingPoint);
|
||||||
|
}
|
||||||
|
|
||||||
|
void format(Builder& builder, T value) const
|
||||||
|
{
|
||||||
|
if (specifier.precision < 0) {
|
||||||
|
builder.putF64(value);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.putF64(value, specifier.precision);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Char
|
// Char
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (C) 2022 Riyyi
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <type_traits> // is_integral_v, floating_point_v
|
||||||
|
|
||||||
|
namespace Util::Concepts {
|
||||||
|
|
||||||
|
template<class T>
|
||||||
|
concept Integral = std::is_integral_v<T>;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
concept FloatingPoint = std::is_floating_point_v<T>;
|
||||||
|
|
||||||
|
} // namespace Util::Concepts
|
||||||
|
|
||||||
|
using Util::Concepts::FloatingPoint;
|
||||||
|
using Util::Concepts::Integral;
|
||||||
Reference in New Issue
Block a user