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 /libs/kstd/src/vformat.cpp | |
| parent | 98fc294deb6f7c27eda3f9ed3b616572a1ab2009 (diff) | |
| download | teachos-45091789eb9e49856ea6c2f3606639d43f4584e7.tar.xz teachos-45091789eb9e49856ea6c2f3606639d43f4584e7.zip | |
kstd: move formatting implementation to kstd
Diffstat (limited to 'libs/kstd/src/vformat.cpp')
| -rw-r--r-- | libs/kstd/src/vformat.cpp | 224 |
1 files changed, 224 insertions, 0 deletions
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 |
