aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-03-20 15:22:37 +0100
committerFelix Morgner <felix.morgner@ost.ch>2026-03-20 15:22:37 +0100
commit8ae0f5a9a83aa58f2bd9eacfb51369b0bf966809 (patch)
treeb6de15d463081a7209f57bd78e54541fc2382d32 /libs/kstd
parente92343922bc8dce0c5653b83789498d4c97ade62 (diff)
downloadteachos-8ae0f5a9a83aa58f2bd9eacfb51369b0bf966809.tar.xz
teachos-8ae0f5a9a83aa58f2bd9eacfb51369b0bf966809.zip
kstd/format: use tagged union to reduce template bloat
Diffstat (limited to 'libs/kstd')
-rw-r--r--libs/kstd/include/kstd/bits/format/arg.hpp63
-rw-r--r--libs/kstd/include/kstd/bits/format/args.hpp100
-rw-r--r--libs/kstd/include/kstd/bits/format/formatter/bool.hpp2
-rw-r--r--libs/kstd/include/kstd/bits/format/formatter/cstring.hpp6
-rw-r--r--libs/kstd/include/kstd/bits/format/formatter/integral.hpp2
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>;