aboutsummaryrefslogtreecommitdiff
path: root/libs/kstd/src
diff options
context:
space:
mode:
Diffstat (limited to 'libs/kstd/src')
-rw-r--r--libs/kstd/src/vformat.cpp209
1 files changed, 209 insertions, 0 deletions
diff --git a/libs/kstd/src/vformat.cpp b/libs/kstd/src/vformat.cpp
new file mode 100644
index 0000000..b7c5121
--- /dev/null
+++ b/libs/kstd/src/vformat.cpp
@@ -0,0 +1,209 @@
+#include <kstd/format>
+#include <kstd/string>
+
+#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);
+ }
+
+} // namespace kstd::bits::format \ No newline at end of file