From 0c8e77b367ca617beb2c30cd7e032cd9b24aeea4 Mon Sep 17 00:00:00 2001 From: Felix Morgner Date: Thu, 18 Dec 2025 13:59:50 +0100 Subject: kstd: finish integral formatting implementation --- libs/kstd/include/kstd/bits/format_context.hpp | 2 +- libs/kstd/include/kstd/bits/formatter.hpp | 104 +++++++++++++++---------- 2 files changed, 62 insertions(+), 44 deletions(-) diff --git a/libs/kstd/include/kstd/bits/format_context.hpp b/libs/kstd/include/kstd/bits/format_context.hpp index 69f0629..b5c7d21 100644 --- a/libs/kstd/include/kstd/bits/format_context.hpp +++ b/libs/kstd/include/kstd/bits/format_context.hpp @@ -12,7 +12,7 @@ namespace kstd { using writer_function = void(void *, std::string_view); - writer_function writer; + writer_function * writer; void * user_data; constexpr auto push(std::string_view string) -> void diff --git a/libs/kstd/include/kstd/bits/formatter.hpp b/libs/kstd/include/kstd/bits/formatter.hpp index ce29b59..0fea5ef 100644 --- a/libs/kstd/include/kstd/bits/formatter.hpp +++ b/libs/kstd/include/kstd/bits/formatter.hpp @@ -12,6 +12,7 @@ #include #include #include +#include namespace kstd { @@ -31,7 +32,17 @@ namespace kstd auto format(T value, format_context & context) -> void { - using unsigned_T = std::make_unsigned; + enum struct base + { + bin = 2, + oct = 8, + dec = 10, + hex = 16, + }; + + constexpr auto static maximum_digits = 80; + + using unsigned_T = std::make_unsigned_t; auto absolute_value = static_cast(value); auto is_negative = false; @@ -50,31 +61,33 @@ namespace kstd case 'x': case 'X': case 'p': - return 16; + return base::hex; case 'b': case 'B': - return 2; + return base::bin; case 'o': - return 8; + return base::oct; default: - return 10; + return base::dec; } }(); - auto buffer = std::array{}; - auto digits = (base == 16) ? "0123456789abcdef" : "0123456789"; + auto buffer = std::array{}; + auto digits = (base == base::hex) ? "0123456789abcdef" : "0123456789"; auto current = buffer.rbegin(); if (absolute_value == 0) { - *std::next(current) = '0'; + *current = '0'; + std::advance(current, 1); } else { while (absolute_value != 0) { - *std::next(current) = digits[absolute_value % base]; - absolute_value /= base; + *current = digits[absolute_value % std::to_underlying(base)]; + std::advance(current, 1); + absolute_value /= std::to_underlying(base); } } @@ -82,19 +95,21 @@ namespace kstd auto prefix_length = 0uz; if (specs.alternative_form && value != 0) { - if (base == 16) + switch (base) { - prefix[1] = specs.type == 'X' ? 'X' : 'x'; - prefix_length = 2; - } - else if (base == 8) - { - prefix_length = 1; - } - else if (base == 2) - { - prefix[1] = specs.type == 'B' ? 'B' : 'b'; - prefix_length = 2; + case base::bin: + prefix[1] = specs.type == 'B' ? 'B' : 'b'; + prefix_length = 2; + break; + case base::oct: + prefix_length = 1; + break; + case base::hex: + prefix[1] = specs.type == 'X' ? 'X' : 'x'; + prefix_length = 2; + break; + default: + break; } } @@ -156,38 +171,41 @@ namespace kstd struct format_arg { + using formatting_function = std::string_view(void const *, std::string_view, format_context &); + void const * value; - auto (*format)(void const *, std::string_view, format_context &) -> std::string_view; + formatting_function * format; }; - template - auto format_dispatcher(void const * val, std::string_view spec, format_context & ctx) -> std::string_view + struct format_args { - formatter f; - auto const remainder = f.parse(spec); - f.format(*static_cast(val), ctx); - return remainder; - } - - class format_args - { - format_arg const * args_; - std::size_t count_; - - public: - constexpr format_args(format_arg const * args, std::size_t count) - : args_(args) - , count_(count) + constexpr format_args(format_arg const * args, std::size_t number_of_args) + : m_args(args) + , m_number_of_args(number_of_args) {} - [[nodiscard]] constexpr auto get(std::size_t idx) const -> format_arg + [[nodiscard]] constexpr auto get(std::size_t index) const -> format_arg { - if (idx >= count_) + if (index >= m_number_of_args) return {.value = nullptr, .format = nullptr}; - return args_[idx]; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + return m_args[index]; } + + private: + format_arg const * m_args; + std::size_t m_number_of_args; }; + template + auto format_dispatcher(void const * value, std::string_view format_spec, format_context & context) -> std::string_view + { + auto formatter_for_T = formatter{}; + auto const remainder = formatter_for_T.parse(format_spec); + formatter_for_T.format(*static_cast(value), context); + return remainder; + } + } // namespace kstd #endif \ No newline at end of file -- cgit v1.2.3