aboutsummaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-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
8 files changed, 240 insertions, 8 deletions
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