aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFelix Morgner <felix.morgner@ost.ch>2026-04-13 14:56:39 +0200
committerFelix Morgner <felix.morgner@ost.ch>2026-04-13 14:56:39 +0200
commit45091789eb9e49856ea6c2f3606639d43f4584e7 (patch)
treef7e920f27be2616eca77d8337dbabddd52e852e9
parent98fc294deb6f7c27eda3f9ed3b616572a1ab2009 (diff)
downloadteachos-45091789eb9e49856ea6c2f3606639d43f4584e7.tar.xz
teachos-45091789eb9e49856ea6c2f3606639d43f4584e7.zip
kstd: move formatting implementation to kstd
-rw-r--r--kernel/kstd/print.cpp198
-rw-r--r--libs/kstd/CMakeLists.txt1
-rw-r--r--libs/kstd/include/kstd/bits/format/context.hpp5
-rw-r--r--libs/kstd/include/kstd/bits/format/formatter/bool.hpp4
-rw-r--r--libs/kstd/include/kstd/bits/format/formatter/integral.hpp4
-rw-r--r--libs/kstd/include/kstd/bits/format/specifiers.hpp6
-rw-r--r--libs/kstd/include/kstd/bits/format/vformat.hpp2
-rw-r--r--libs/kstd/include/kstd/vector2
-rw-r--r--libs/kstd/src/vformat.cpp224
9 files changed, 250 insertions, 196 deletions
diff --git a/kernel/kstd/print.cpp b/kernel/kstd/print.cpp
index a0bb7d6..7854027 100644
--- a/kernel/kstd/print.cpp
+++ b/kernel/kstd/print.cpp
@@ -35,16 +35,6 @@ namespace kstd::os
flush();
}
- auto flush() noexcept -> void
- {
- if (m_position > 0)
- {
- std::string_view chunk{m_buffer.data(), m_position};
- kapi::cio::write(m_stream, chunk);
- m_position = 0;
- }
- }
-
auto push(std::string_view text) -> void final
{
std::ranges::for_each(text, [this](auto c) { this->push(c); });
@@ -60,6 +50,16 @@ namespace kstd::os
}
private:
+ auto flush() noexcept -> void
+ {
+ if (m_position > 0)
+ {
+ std::string_view chunk{m_buffer.data(), m_position};
+ kapi::cio::write(m_stream, chunk);
+ m_position = 0;
+ }
+ }
+
output_stream m_stream;
std::array<char, size> m_buffer{};
std::size_t m_position{};
@@ -72,184 +72,6 @@ namespace kstd::os
auto writer = write_buffer{(sink == print_sink::stderr) ? kapi::cio::output_stream::stderr
: kapi::cio::output_stream::stdout};
kstd::bits::format::vformat_to(writer, format, args);
- // auto context = kstd::format_context{.writer = write_buffer::callback, .user_data = &writer, .args = args};
- // auto parse_context = kstd::format_parse_context{format, args.size()};
-
- // auto it = parse_context.begin();
- // auto end = parse_context.end();
-
- // while (it != end)
- // {
- // if (*it != '{' && *it != '}')
- // {
- // auto start = it;
- // while (it != end && *it != '{' && *it != '}')
- // {
- // std::advance(it, 1);
- // }
- // parse_context.advance_to(it);
- // context.push(std::string_view(start, it - start));
- // continue;
- // }
-
- // if (*it == '{')
- // {
- // std::advance(it, 1);
- // if (it != end && *it == '{')
- // {
- // context.push('{');
- // std::advance(it, 1);
- // parse_context.advance_to(it);
- // continue;
- // }
-
- // parse_context.advance_to(it);
- // auto index = 0uz;
-
- // if (it != end && *it >= '0' && *it <= '9')
- // {
- // while (it != end && *it >= '0' && *it <= '9')
- // {
- // index = index * 10 + static_cast<std::size_t>(*it - '0');
- // std::advance(it, 1);
- // }
- // parse_context.check_arg_id(index);
- // }
- // else
- // {
- // index = parse_context.next_arg_id();
- // }
-
- // if (it != end && *it == ':')
- // {
- // std::advance(it, 1);
- // }
-
- // parse_context.advance_to(it);
-
- // if (index < args.size())
- // {
- // auto const & arg = args[index];
- // switch (arg.type)
- // {
- // 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
- // {
- // context.push("{fmt-err: bound}");
- // }
-
- // it = parse_context.begin();
-
- // if (it != end && *it == '}')
- // {
- // std::advance(it, 1);
- // parse_context.advance_to(it);
- // }
- // else
- // {
- // context.push("{fmt-err: unconsumed}");
- // while (it != end && *it != '}')
- // {
- // std::advance(it, 1);
- // }
-
- // if (it != end)
- // {
- // std::advance(it, 1);
- // parse_context.advance_to(it);
- // }
- // }
- // }
- // else if (*it == '}')
- // {
- // std::advance(it, 1);
- // if (it != end && *it == '}')
- // {
- // context.push('}');
- // std::advance(it, 1);
- // parse_context.advance_to(it);
- // }
- // else
- // {
- // context.push("{fmt-err: unescaped}");
- // parse_context.advance_to(it);
- // }
- // }
- // }
}
} // namespace kstd::os
diff --git a/libs/kstd/CMakeLists.txt b/libs/kstd/CMakeLists.txt
index 240118e..f7c771b 100644
--- a/libs/kstd/CMakeLists.txt
+++ b/libs/kstd/CMakeLists.txt
@@ -21,6 +21,7 @@ target_sources("kstd" PRIVATE
"src/os/error.cpp"
"src/mutex.cpp"
+ "src/vformat.cpp"
)
file(GLOB_RECURSE KSTD_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "include/kstd/*")
diff --git a/libs/kstd/include/kstd/bits/format/context.hpp b/libs/kstd/include/kstd/bits/format/context.hpp
index e8d0302..7f392a0 100644
--- a/libs/kstd/include/kstd/bits/format/context.hpp
+++ b/libs/kstd/include/kstd/bits/format/context.hpp
@@ -33,6 +33,11 @@ namespace kstd
using format_args = std::span<format_arg const>;
format_args args{};
+ format_context(bits::format::output_buffer & buffer, format_args args)
+ : args{args}
+ , m_buffer{&buffer}
+ {}
+
[[nodiscard]] auto arg(std::size_t const id) const -> format_arg const &
{
if (id >= args.size())
diff --git a/libs/kstd/include/kstd/bits/format/formatter/bool.hpp b/libs/kstd/include/kstd/bits/format/formatter/bool.hpp
index 336e1b0..e371cec 100644
--- a/libs/kstd/include/kstd/bits/format/formatter/bool.hpp
+++ b/libs/kstd/include/kstd/bits/format/formatter/bool.hpp
@@ -51,11 +51,11 @@ namespace kstd
auto const text = value ? std::string_view{"true"} : std::string_view{"false"};
auto final_width = 0uz;
- if (specifiers.width_mode == bits::format::width_mode::static_value)
+ if (specifiers.mode == bits::format::width_mode::static_value)
{
final_width = specifiers.width_value;
}
- else if (specifiers.width_mode == bits::format::width_mode::dynamic_argument_id)
+ else if (specifiers.mode == bits::format::width_mode::dynamic_argument_id)
{
auto const & arg = context.arg(specifiers.width_value);
final_width = bits::format::extrat_dynamic_width(arg);
diff --git a/libs/kstd/include/kstd/bits/format/formatter/integral.hpp b/libs/kstd/include/kstd/bits/format/formatter/integral.hpp
index 4912a44..e5a234a 100644
--- a/libs/kstd/include/kstd/bits/format/formatter/integral.hpp
+++ b/libs/kstd/include/kstd/bits/format/formatter/integral.hpp
@@ -64,11 +64,11 @@ namespace kstd
auto format(T value, format_context & context) const -> void
{
auto final_width = 0uz;
- if (specifiers.width_mode == bits::format::width_mode::static_value)
+ if (specifiers.mode == bits::format::width_mode::static_value)
{
final_width = specifiers.width_value;
}
- else if (specifiers.width_mode == bits::format::width_mode::dynamic_argument_id)
+ else if (specifiers.mode == bits::format::width_mode::dynamic_argument_id)
{
auto const & arg = context.arg(specifiers.width_value);
final_width = bits::format::extrat_dynamic_width(arg);
diff --git a/libs/kstd/include/kstd/bits/format/specifiers.hpp b/libs/kstd/include/kstd/bits/format/specifiers.hpp
index 9bc66c7..18c6f66 100644
--- a/libs/kstd/include/kstd/bits/format/specifiers.hpp
+++ b/libs/kstd/include/kstd/bits/format/specifiers.hpp
@@ -43,7 +43,7 @@ namespace kstd::bits::format
bool alternative_form{};
bool zero_pad{};
- width_mode width_mode{};
+ width_mode mode{};
std::size_t width_value{};
char type{};
};
@@ -133,7 +133,7 @@ namespace kstd::bits::format
if (it != end && *it == '{')
{
- specs.width_mode = width_mode::dynamic_argument_id;
+ specs.mode = width_mode::dynamic_argument_id;
std::advance(it, 1);
auto argument_id = 0uz;
@@ -160,7 +160,7 @@ namespace kstd::bits::format
}
else if (it != end && *it >= '0' && *it <= '9')
{
- specs.width_mode = width_mode::static_value;
+ specs.mode = width_mode::static_value;
while (it != end && *it >= '0' && *it <= '9')
{
specs.width_value = specs.width_value * 10 + static_cast<std::size_t>(*it - '0');
diff --git a/libs/kstd/include/kstd/bits/format/vformat.hpp b/libs/kstd/include/kstd/bits/format/vformat.hpp
index 90b74a9..d032c3a 100644
--- a/libs/kstd/include/kstd/bits/format/vformat.hpp
+++ b/libs/kstd/include/kstd/bits/format/vformat.hpp
@@ -38,6 +38,8 @@ namespace kstd
struct string_iterator_writer : output_buffer
{
+ explicit string_iterator_writer(string::iterator iterator);
+
auto push(std::string_view text) -> void override;
auto push(char character) -> void override;
diff --git a/libs/kstd/include/kstd/vector b/libs/kstd/include/kstd/vector
index e51cbac..79593c6 100644
--- a/libs/kstd/include/kstd/vector
+++ b/libs/kstd/include/kstd/vector
@@ -111,7 +111,7 @@ namespace kstd
allocator_type const & allocator =
allocator_type{}) noexcept(std::is_nothrow_copy_constructible_v<allocator_type>)
: m_allocator{allocator}
- , m_size{std::ranges::distance(first, last)}
+ , m_size{static_cast<std::size_t>(std::ranges::distance(first, last))}
, m_capacity{m_size}
, m_data{allocate_n(m_capacity)}
{
diff --git a/libs/kstd/src/vformat.cpp b/libs/kstd/src/vformat.cpp
new file mode 100644
index 0000000..51aca84
--- /dev/null
+++ b/libs/kstd/src/vformat.cpp
@@ -0,0 +1,224 @@
+#include <kstd/format>
+#include <kstd/string>
+
+#include <algorithm>
+#include <cstddef>
+#include <iterator>
+#include <string_view>
+#include <utility>
+
+namespace kstd::bits::format
+{
+
+ auto vformat_to(output_buffer & buffer, std::string_view format, format_args args) -> void
+ {
+ auto context = kstd::format_context{buffer, args};
+ auto parse_context = kstd::format_parse_context{format, args.size()};
+
+ auto it = parse_context.begin();
+ auto end = parse_context.end();
+
+ while (it != end)
+ {
+ if (*it != '{' && *it != '}')
+ {
+ auto start = it;
+ while (it != end && *it != '{' && *it != '}')
+ {
+ std::advance(it, 1);
+ }
+ parse_context.advance_to(it);
+ context.push(std::string_view(start, it - start));
+ continue;
+ }
+
+ if (*it == '{')
+ {
+ std::advance(it, 1);
+ if (it != end && *it == '{')
+ {
+ context.push('{');
+ std::advance(it, 1);
+ parse_context.advance_to(it);
+ continue;
+ }
+
+ parse_context.advance_to(it);
+ auto index = 0uz;
+
+ if (it != end && *it >= '0' && *it <= '9')
+ {
+ while (it != end && *it >= '0' && *it <= '9')
+ {
+ index = index * 10 + static_cast<std::size_t>(*it - '0');
+ std::advance(it, 1);
+ }
+ parse_context.check_arg_id(index);
+ }
+ else
+ {
+ index = parse_context.next_arg_id();
+ }
+
+ if (it != end && *it == ':')
+ {
+ std::advance(it, 1);
+ }
+
+ parse_context.advance_to(it);
+
+ if (index < args.size())
+ {
+ auto const & arg = args[index];
+ switch (arg.type)
+ {
+ 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
+ {
+ context.push("{fmt-err: bound}");
+ }
+
+ it = parse_context.begin();
+
+ if (it != end && *it == '}')
+ {
+ std::advance(it, 1);
+ parse_context.advance_to(it);
+ }
+ else
+ {
+ context.push("{fmt-err: unconsumed}");
+ while (it != end && *it != '}')
+ {
+ std::advance(it, 1);
+ }
+
+ if (it != end)
+ {
+ std::advance(it, 1);
+ parse_context.advance_to(it);
+ }
+ }
+ }
+ else if (*it == '}')
+ {
+ std::advance(it, 1);
+ if (it != end && *it == '}')
+ {
+ context.push('}');
+ std::advance(it, 1);
+ parse_context.advance_to(it);
+ }
+ else
+ {
+ context.push("{fmt-err: unescaped}");
+ parse_context.advance_to(it);
+ }
+ }
+ }
+ }
+
+ auto string_writer::push(std::string_view text) -> void
+ {
+ m_result.append(text);
+ }
+
+ auto string_writer::push(char character) -> void
+ {
+ m_result.push_back(character);
+ }
+
+ auto string_writer::release() -> string &&
+ {
+ return std::move(m_result);
+ }
+
+ string_iterator_writer::string_iterator_writer(string::iterator it)
+ : m_iter{it}
+ {}
+
+ auto string_iterator_writer::push(std::string_view text) -> void
+ {
+ std::ranges::for_each(text, [this](auto c) { push(c); });
+ }
+
+ auto string_iterator_writer::push(char character) -> void
+ {
+ *m_iter++ = character;
+ }
+
+} // namespace kstd::bits::format \ No newline at end of file