diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-03-20 15:22:37 +0100 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-03-20 15:22:37 +0100 |
| commit | 8ae0f5a9a83aa58f2bd9eacfb51369b0bf966809 (patch) | |
| tree | b6de15d463081a7209f57bd78e54541fc2382d32 /libs | |
| parent | e92343922bc8dce0c5653b83789498d4c97ade62 (diff) | |
| download | teachos-8ae0f5a9a83aa58f2bd9eacfb51369b0bf966809.tar.xz teachos-8ae0f5a9a83aa58f2bd9eacfb51369b0bf966809.zip | |
kstd/format: use tagged union to reduce template bloat
Diffstat (limited to 'libs')
5 files changed, 156 insertions, 17 deletions
diff --git a/libs/kstd/include/kstd/bits/format/arg.hpp b/libs/kstd/include/kstd/bits/format/arg.hpp index 92e6431..a9a6ab5 100644 --- a/libs/kstd/include/kstd/bits/format/arg.hpp +++ b/libs/kstd/include/kstd/bits/format/arg.hpp @@ -3,24 +3,73 @@ // IWYU pragma: private, include <kstd/format> +#include "error.hpp" #include "fwd.hpp" #include <cstddef> +#include <cstdint> +#include <string_view> namespace kstd { - struct format_arg + namespace bits::format { - using format_function_type = auto(void const * value, format_parse_context & parse_context, - format_context & context) -> void; - using get_size_function_type = auto(void const * value) -> std::size_t; + enum struct arg_type : std::uint8_t + { + none, + boolean, + character, + integer, + unsigned_integer, + string_view, + c_string, + pointer, + user_defined, + }; + } // namespace bits::format - void const * value_pointer; - format_function_type * format_function; - get_size_function_type * get_size_function; + struct format_arg + { + bits::format::arg_type type{}; + union + { + bool boolean; + char character; + std::int64_t integer; + std::uint64_t unsigned_integer; + std::string_view string_view; + char const * c_string; + void const * pointer; + struct + { + void const * pointer; + auto (*format)(void const * value, format_parse_context & parse_context, format_context & context) -> void; + } user_defined; + } value{}; }; + namespace bits::format + { + constexpr auto extrat_dynamic_width(format_arg const & arg) -> std::size_t + { + if (arg.type == arg_type::unsigned_integer) + { + return static_cast<std::size_t>(arg.value.unsigned_integer); + } + else if (arg.type == arg_type::integer) + { + if (arg.value.integer < 0) + { + error("Dynamic width cannont be negative."); + } + return static_cast<std::size_t>(arg.value.integer); + } + error("Dynamic width argument is not an integral value."); + return 0; + } + } // namespace bits::format + } // namespace kstd #endif
\ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/format/args.hpp b/libs/kstd/include/kstd/bits/format/args.hpp index 5cca3ff..008cc03 100644 --- a/libs/kstd/include/kstd/bits/format/args.hpp +++ b/libs/kstd/include/kstd/bits/format/args.hpp @@ -3,14 +3,17 @@ // IWYU pragma: private, include <kstd/format> +#include "arg.hpp" #include "context.hpp" -#include "error.hpp" #include "fwd.hpp" #include "parse_context.hpp" #include <array> +#include <concepts> #include <cstddef> +#include <cstdint> #include <span> +#include <string_view> #include <type_traits> namespace kstd @@ -31,17 +34,98 @@ namespace kstd } template<typename ValueType> - auto get_size_trampoline(void const * value_pointer) -> std::size_t + constexpr auto determine_arg_type() -> arg_type { - if constexpr (is_width_v<ValueType>) + using decay_type = std::remove_cvref_t<std::decay_t<ValueType>>; + if constexpr (std::same_as<decay_type, bool>) { - return static_cast<std::size_t>(*static_cast<ValueType const *>(value_pointer)); + return arg_type::boolean; + } + else if constexpr (std::same_as<decay_type, char>) + { + return arg_type::character; + } + else if constexpr (std::integral<decay_type> && std::is_signed_v<decay_type>) + { + return arg_type::integer; + } + else if constexpr (std::integral<decay_type> && std::is_unsigned_v<decay_type>) + { + return arg_type::unsigned_integer; + } + else if constexpr (std::same_as<decay_type, std::string_view>) + { + return arg_type::string_view; + } + else if constexpr (std::same_as<decay_type, char *> || std::same_as<decay_type, char const *>) + { + return arg_type::c_string; + } + else if constexpr (std::is_pointer_v<decay_type> || std::same_as<decay_type, std::nullptr_t>) + { + if constexpr (std::same_as<decay_type, char *> || std::same_as<decay_type, char const *>) + { + return arg_type::user_defined; + } + else + { + return arg_type::pointer; + } + } + else + { + return arg_type::user_defined; + } + } + + template<typename ValueType> + constexpr auto make_single_arg(ValueType const & value) -> format_arg + { + auto result = format_arg{}; + constexpr auto type = determine_arg_type<ValueType>(); + result.type = type; + + if constexpr (type == arg_type::boolean) + { + result.value.boolean = value; + } + else if constexpr (type == arg_type::character) + { + result.value.character = value; + } + else if constexpr (type == arg_type::integer) + { + result.value.integer = static_cast<std::int64_t>(value); + } + else if constexpr (type == arg_type::unsigned_integer) + { + result.value.unsigned_integer = static_cast<std::uint64_t>(value); + } + else if constexpr (type == arg_type::string_view) + { + result.value.string_view = value; + } + else if constexpr (type == arg_type::c_string) + { + result.value.c_string = value; + } + else if constexpr (type == arg_type::pointer) + { + if constexpr (std::same_as<std::remove_cvref_t<ValueType>, std::nullptr_t>) + { + result.value.pointer = nullptr; + } + else + { + result.value.pointer = static_cast<void const *>(value); + } } else { - error("Dynamic width argument is not an integral value."); - return 0; + result.value.user_defined.pointer = &value; + result.value.user_defined.format = format_trampoline<ValueType>; } + return result; } } // namespace bits::format @@ -65,8 +149,8 @@ namespace kstd } else { - return format_arg_store<sizeof...(Arguments)>{std::array<format_arg, sizeof...(Arguments)>{ - format_arg{static_cast<void const *>(&args), format_trampoline<Arguments>, get_size_trampoline<Arguments>}...}}; + return format_arg_store<sizeof...(Arguments)>{ + std::array<format_arg, sizeof...(Arguments)>{make_single_arg(args)...}}; } } diff --git a/libs/kstd/include/kstd/bits/format/formatter/bool.hpp b/libs/kstd/include/kstd/bits/format/formatter/bool.hpp index b409e06..336e1b0 100644 --- a/libs/kstd/include/kstd/bits/format/formatter/bool.hpp +++ b/libs/kstd/include/kstd/bits/format/formatter/bool.hpp @@ -58,7 +58,7 @@ namespace kstd else if (specifiers.width_mode == bits::format::width_mode::dynamic_argument_id) { auto const & arg = context.arg(specifiers.width_value); - final_width = arg.get_size_function(arg.value_pointer); + final_width = bits::format::extrat_dynamic_width(arg); } auto padding = bits::format::calculate_format_padding(final_width, text.size(), specifiers.align, diff --git a/libs/kstd/include/kstd/bits/format/formatter/cstring.hpp b/libs/kstd/include/kstd/bits/format/formatter/cstring.hpp index 9afb974..bf52f2e 100644 --- a/libs/kstd/include/kstd/bits/format/formatter/cstring.hpp +++ b/libs/kstd/include/kstd/bits/format/formatter/cstring.hpp @@ -5,6 +5,7 @@ #include "../formatter.hpp" #include "string_view.hpp" +#include <cstddef> #include <string_view> namespace kstd @@ -24,6 +25,11 @@ namespace kstd { }; + template<std::size_t N> + struct formatter<char[N]> : formatter<std::string_view> // NOLINT + { + }; + } // namespace kstd #endif
\ No newline at end of file diff --git a/libs/kstd/include/kstd/bits/format/formatter/integral.hpp b/libs/kstd/include/kstd/bits/format/formatter/integral.hpp index d5cd6c5..4912a44 100644 --- a/libs/kstd/include/kstd/bits/format/formatter/integral.hpp +++ b/libs/kstd/include/kstd/bits/format/formatter/integral.hpp @@ -71,7 +71,7 @@ namespace kstd else if (specifiers.width_mode == bits::format::width_mode::dynamic_argument_id) { auto const & arg = context.arg(specifiers.width_value); - final_width = arg.get_size_function(arg.value_pointer); + final_width = bits::format::extrat_dynamic_width(arg); } using unsigned_T = std::make_unsigned_t<T>; |
