summaryrefslogtreecommitdiff
path: root/asl
diff options
context:
space:
mode:
authorSteven Le Rouzic <steven.lerouzic@gmail.com>2024-10-09 23:08:48 +0200
committerSteven Le Rouzic <steven.lerouzic@gmail.com>2024-12-20 15:35:58 +0100
commit8dfd173285df515fe9b41d970321da9d049460f8 (patch)
tree570b3ffbbe53ffee6a2d7d08646bfa448b95a509 /asl
parent0e7999f2d147b026aaee6693bdd2be2cb4a2519e (diff)
More work on format
Diffstat (limited to 'asl')
-rw-r--r--asl/format.cpp61
-rw-r--r--asl/format.hpp16
-rw-r--r--asl/format_tests.cpp82
3 files changed, 155 insertions, 4 deletions
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("<ERROR>", 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("<ERROR>", 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<typename... Args>
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<Args...>);
}
+// @Todo Use string_view
+inline void format(writer* w, const char* fmt)
+{
+ format_internals::format(w, fmt, nullptr, 0);
+}
+
+template<int64_t N>
+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 <cstdlib>
+#include <cstring>
+#include <cassert>
+#include <cstdio>
+
+// @Todo Improve this to use our utilities, not the C stdlib
+
+static_assert(asl::formattable<decltype("Hello")>);
+
+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! <ERROR>") == 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(), "<ERROR> ") == 0);
+
+ sink.reset();
+ asl::format(&sink, "{", "CHEESE");
+ assert(strcmp(sink.cstr(), "<ERROR>") == 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;
+}