From 8dfd173285df515fe9b41d970321da9d049460f8 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Wed, 9 Oct 2024 23:08:48 +0200 Subject: More work on format --- asl/format.cpp | 61 ++++++++++++++++++++++++++++++++++++-- asl/format.hpp | 16 ++++++++-- asl/format_tests.cpp | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 155 insertions(+), 4 deletions(-) (limited to 'asl') diff --git a/asl/format.cpp b/asl/format.cpp index 890e532..4866562 100644 --- a/asl/format.cpp +++ b/asl/format.cpp @@ -7,6 +7,63 @@ void asl::format_internals::format( int64_t arg_count) { formatter f(writer); - - f.write("Hello", 5); + + + int64_t arg = 0; + + const char* begin = fmt; + while (*fmt != '\0') + { + if (fmt[0] == '{') + { + if (fmt[1] == '}') + { + if (arg < arg_count) + { + f.write(begin, fmt - begin); + fmt += 2; + begin = fmt; + + args[arg].fn(f, args[arg].data); + arg += 1; + } + else + { + f.write(begin, fmt - begin); + fmt += 2; + begin = fmt; + + f.write("", 7); + } + } + else if (fmt[1] == '{') + { + fmt += 1; + f.write(begin, fmt - begin); + fmt += 1; + begin = fmt; + } + else + { + f.write(begin, fmt - begin); + fmt += 1; + begin = fmt; + + f.write("", 7); + } + } + else if (fmt[0] == '}' && fmt[1] == '}') + { + fmt += 1; + f.write(begin, fmt - begin); + fmt += 1; + begin = fmt; + } + else + { + fmt += 1; + } + } + + f.write(begin, fmt - begin); } diff --git a/asl/format.hpp b/asl/format.hpp index 6cffd3a..1b4088e 100644 --- a/asl/format.hpp +++ b/asl/format.hpp @@ -51,7 +51,7 @@ struct type_erased_arg // @Todo Use span void format(writer*, const char* fmt, const type_erased_arg* args, int64_t arg_count); -} // internals +} // namespace internals class formatter { @@ -73,7 +73,7 @@ public: template void format(writer* w, const char* fmt, const Args&... args) { - auto type_erased_args[] = { + format_internals::type_erased_arg type_erased_args[] = { format_internals::type_erased_arg(args)... }; @@ -81,4 +81,16 @@ void format(writer* w, const char* fmt, const Args&... args) format_internals::format(w, fmt, type_erased_args, types_count); } +// @Todo Use string_view +inline void format(writer* w, const char* fmt) +{ + format_internals::format(w, fmt, nullptr, 0); +} + +template +void AslFormat(formatter& f, const char (&str)[N]) +{ + f.write(str, N - 1); +} + } // namespace asl diff --git a/asl/format_tests.cpp b/asl/format_tests.cpp index e69de29..2288a77 100644 --- a/asl/format_tests.cpp +++ b/asl/format_tests.cpp @@ -0,0 +1,82 @@ +#include "asl/format.hpp" + +#include +#include +#include +#include + +// @Todo Improve this to use our utilities, not the C stdlib + +static_assert(asl::formattable); + +class StringSink : public asl::writer +{ + int64_t m_current_len{}; + char* m_data{}; + +public: + void write(const char* str, int64_t len) override + { + m_data = (char*)realloc(m_data, (size_t)(m_current_len + len + 1)); + memcpy(m_data + m_current_len, str, (size_t)len); + m_current_len += len; + m_data[m_current_len] = '\0'; + } + + constexpr const char* cstr() const { return m_data; } + + void reset() + { + m_current_len = 0; + free(m_data); + m_data = nullptr; + } +}; + +int main() +{ + StringSink sink; + + // @Todo Use the testing framework + + asl::format(&sink, "Hello, world!"); + assert(strcmp(sink.cstr(), "Hello, world!") == 0); + + sink.reset(); + asl::format(&sink, ""); + assert(strcmp(sink.cstr(), "") == 0); + + sink.reset(); + asl::format(&sink, "Hello, {}!", "world"); + assert(strcmp(sink.cstr(), "Hello, world!") == 0); + + sink.reset(); + asl::format(&sink, "Hello, {}! {}", "world"); + assert(strcmp(sink.cstr(), "Hello, world! ") == 0); + + sink.reset(); + asl::format(&sink, "Hello, pup!", "world"); + assert(strcmp(sink.cstr(), "Hello, pup!") == 0); + + sink.reset(); + asl::format(&sink, "{}", "CHEESE"); + assert(strcmp(sink.cstr(), "CHEESE") == 0); + + sink.reset(); + asl::format(&sink, "{ ", "CHEESE"); + assert(strcmp(sink.cstr(), " ") == 0); + + sink.reset(); + asl::format(&sink, "{", "CHEESE"); + assert(strcmp(sink.cstr(), "") == 0); + + sink.reset(); + asl::format(&sink, "a{{b"); + assert(strcmp(sink.cstr(), "a{b") == 0); + + sink.reset(); + asl::format(&sink, "{{{}}} }", "CHEESE"); + assert(strcmp(sink.cstr(), "{CHEESE} }") == 0); + + return 0; +} -- cgit