Browse Source

Util: Use C++20 concepts for integral and floating-point types

master
Riyyi 2 years ago
parent
commit
9758c3e425
  1. 13
      src/util/format/builder.cpp
  2. 7
      src/util/format/builder.h
  3. 50
      src/util/format/formatter.cpp
  4. 59
      src/util/format/formatter.h
  5. 22
      src/util/meta/concepts.h

13
src/util/format/builder.cpp

@ -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
{
precision = std::min(precision, static_cast<uint8_t>(std::numeric_limits<double>::digits10));

7
src/util/format/builder.h

@ -36,11 +36,8 @@ public:
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, uint8_t precision = 6) const;
void putI64(int64_t number) const { m_builder << number; } // long int
void putU64(size_t number) const { m_builder << number; } // long unsigned int
void putF64(double number, uint8_t precision = 6) const;
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;

50
src/util/format/formatter.cpp

@ -16,56 +16,6 @@
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
template<>

59
src/util/format/formatter.h

@ -17,6 +17,7 @@
#include "util/format/builder.h"
#include "util/format/parser.h"
#include "util/meta/concepts.h"
namespace Util::Format {
@ -66,13 +67,7 @@ struct Formatter {
constexpr void parse(Parser& parser)
{
if (std::is_integral_v<T>) {
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>) {
if (std::is_same_v<T, char>) {
parser.parseSpecifier(specifier, Parser::ParameterType::Char);
}
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
template<>
void Formatter<int32_t>::format(Builder& builder, int32_t value) const;
template<>
void Formatter<uint32_t>::format(Builder& builder, uint32_t value) const;
template<Integral T>
struct Formatter<T> {
Specifier specifier;
template<>
void Formatter<int64_t>::format(Builder& builder, int64_t value) const;
void parse(Parser& parser)
{
parser.parseSpecifier(specifier, Parser::ParameterType::Integral);
}
template<>
void Formatter<size_t>::format(Builder& builder, size_t value) const; // uint64_t
void format(Builder& builder, T value) const
{
if (std::is_signed_v<T>) {
builder.putI64(value);
}
if (std::is_unsigned_v<T>) {
builder.putU64(value);
}
}
};
// Floating point
template<>
void Formatter<float>::format(Builder& builder, float value) const;
template<FloatingPoint T>
struct Formatter<T> {
Specifier specifier;
template<>
void Formatter<double>::format(Builder& builder, double value) const;
void parse(Parser& parser)
{
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

22
src/util/meta/concepts.h

@ -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;
Loading…
Cancel
Save