diff options
| -rw-r--r-- | kernel/kstd/print.cpp | 80 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/arg.hpp | 63 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/args.hpp | 100 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/formatter/bool.hpp | 2 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/formatter/cstring.hpp | 6 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/formatter/integral.hpp | 2 |
6 files changed, 230 insertions, 23 deletions
diff --git a/kernel/kstd/print.cpp b/kernel/kstd/print.cpp index db03816..beee2e5 100644 --- a/kernel/kstd/print.cpp +++ b/kernel/kstd/print.cpp @@ -127,13 +127,81 @@ namespace kstd::os if (index < args.size()) { auto const & arg = args[index]; - if (arg.format_function) + switch (arg.type) { - arg.format_function(arg.value_pointer, parse_context, context); - } - else - { - context.push("{?}"); + case kstd::bits::format::arg_type::boolean: + { + auto fmt = kstd::formatter<bool>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.boolean, context); + break; + } + case kstd::bits::format::arg_type::character: + { + auto fmt = kstd::formatter<char>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.character, context); + break; + } + case kstd::bits::format::arg_type::integer: + { + auto fmt = kstd::formatter<long long>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.integer, context); + break; + } + case kstd::bits::format::arg_type::unsigned_integer: + { + auto fmt = kstd::formatter<unsigned long long>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.unsigned_integer, context); + break; + } + case kstd::bits::format::arg_type::string_view: + { + auto fmt = kstd::formatter<std::string_view>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.string_view, context); + break; + } + case kstd::bits::format::arg_type::c_string: + { + auto fmt = kstd::formatter<char const *>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.c_string, context); + break; + } + case kstd::bits::format::arg_type::pointer: + { + auto fmt = kstd::formatter<void const *>{}; + auto const parsed = fmt.parse(parse_context); + parse_context.advance_to(parsed); + fmt.format(arg.value.pointer, context); + break; + } + case kstd::bits::format::arg_type::user_defined: + { + if (arg.value.user_defined.format) + { + arg.value.user_defined.format(arg.value.user_defined.pointer, parse_context, context); + } + else + { + context.push("{?}"); + } + break; + } + default: + { + context.push("{fmt-err: unknown-type}"); + break; + } } } else 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>; |
