/* * Copyright (C) 2022 Riyyi * * SPDX-License-Identifier: MIT */ #pragma once #include // size_t #include // int8_t, int32_t, int64_t, uint8_t, uint32_t #include #include #include #include // is_integral_v, is_same #include #include #include "util/format/builder.h" #include "util/format/parser.h" #include "util/meta/concepts.h" namespace Util::Format { enum class PresentationType : uint8_t { None, // Defaults are any of: 'dgcsp', depending on the type // Interger Binary = 98, // 'b' BinaryUppercase = 66, // 'B' Decimal = 100, // 'd' Octal = 111, // 'o' Hex = 120, // 'x' HexUppercase = 88, // 'X' // Floating-point Hexfloat = 97, // 'a' HexfloatUppercase = 65, // 'A' Exponent = 101, // 'e' ExponentUppercase = 69, // 'E' FixedPoint = 102, // 'f' FixedPointUppercase = 70, // 'F' General = 103, // 'g' GeneralUppercase = 71, // 'G' // Character Character = 99, // 'c' // String String = 115, // 's' // Pointer Pointer = 112, // 'p' }; struct Specifier { char fill = ' '; Builder::Align align = Builder::Align::None; Builder::Sign sign = Builder::Sign::None; bool alternativeForm = false; bool zeroPadding = false; size_t width = 0; int8_t precision = -1; PresentationType type = PresentationType::None; }; template struct Formatter { Specifier specifier; constexpr void parse(Parser& parser) { if (std::is_same_v) { parser.parseSpecifier(specifier, Parser::ParameterType::Char); } else if (std::is_same_v) { parser.parseSpecifier(specifier, Parser::ParameterType::String); } } void format(Builder&, T) const {} }; // Integral template struct Formatter { Specifier specifier; void parse(Parser& parser) { parser.parseSpecifier(specifier, Parser::ParameterType::Integral); } void format(Builder& builder, T value) const { if (std::is_signed_v) { builder.putI64(value); } if (std::is_unsigned_v) { builder.putU64(value); } } }; // Floating point template struct Formatter { Specifier specifier; 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 template<> void Formatter::format(Builder& builder, char value) const; template<> void Formatter::format(Builder& builder, bool value) const; // String template<> void Formatter::format(Builder& builder, std::string_view value) const; template<> struct Formatter : Formatter { }; template<> struct Formatter : Formatter { void parse(Parser& parser); void format(Builder& builder, const char* value) const; }; template<> struct Formatter : Formatter { }; template struct Formatter : Formatter { }; // Pointer template struct Formatter { Specifier specifier; constexpr void parse(Parser& parser) { parser.parseSpecifier(specifier, Parser::ParameterType::Pointer); } void format(Builder& builder, T* value) const { value == nullptr ? builder.putString("nullptr") : builder.putPointer(static_cast(value)); } }; template<> struct Formatter : Formatter { void format(Builder& builder, std::nullptr_t) const; }; // Container template struct Formatter> : Formatter { void format(Builder& builder, const std::vector& value) const { builder.putString("{\n"); for (auto it = value.cbegin(); it != value.cend(); ++it) { builder.putString(" "); Formatter::format(builder, *it); // Add comma, except after the last element if (it != std::prev(value.end(), 1)) { builder.putCharacter(','); } builder.putCharacter('\n'); } builder.putCharacter('}'); } }; #define UTIL_FORMAT_FORMAT_AS_MAP(type) \ template \ struct Formatter> \ : Formatter \ , Formatter { \ void format(Builder& builder, const type& value) const \ { \ builder.putString("{\n"); \ auto last = value.end(); \ for (auto it = value.begin(); it != last; ++it) { \ builder.putString(R"( ")"); \ Formatter::format(builder, it->first); \ builder.putString(R"(": )"); \ Formatter::format(builder, it->second); \ \ /* Add comma, except after the last element */ \ if (std::next(it) != last) { \ builder.putCharacter(','); \ } \ \ builder.putCharacter('\n'); \ } \ builder.putCharacter('}'); \ } \ } UTIL_FORMAT_FORMAT_AS_MAP(std::map); UTIL_FORMAT_FORMAT_AS_MAP(std::unordered_map); } // namespace Util::Format