diff options
| author | Felix Morgner <felix.morgner@ost.ch> | 2026-04-13 14:56:39 +0200 |
|---|---|---|
| committer | Felix Morgner <felix.morgner@ost.ch> | 2026-04-13 14:56:39 +0200 |
| commit | 45091789eb9e49856ea6c2f3606639d43f4584e7 (patch) | |
| tree | f7e920f27be2616eca77d8337dbabddd52e852e9 | |
| parent | 98fc294deb6f7c27eda3f9ed3b616572a1ab2009 (diff) | |
| download | teachos-45091789eb9e49856ea6c2f3606639d43f4584e7.tar.xz teachos-45091789eb9e49856ea6c2f3606639d43f4584e7.zip | |
kstd: move formatting implementation to kstd
| -rw-r--r-- | kernel/kstd/print.cpp | 198 | ||||
| -rw-r--r-- | libs/kstd/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/context.hpp | 5 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/formatter/bool.hpp | 4 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/formatter/integral.hpp | 4 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/specifiers.hpp | 6 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/bits/format/vformat.hpp | 2 | ||||
| -rw-r--r-- | libs/kstd/include/kstd/vector | 2 | ||||
| -rw-r--r-- | libs/kstd/src/vformat.cpp | 224 |
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 |
