More work on format

This commit is contained in:
2024-10-09 23:08:48 +02:00
parent 0e7999f2d1
commit 8dfd173285
4 changed files with 157 additions and 4 deletions

View File

@ -15,3 +15,5 @@ build --cxxopt=-Wno-unused-macros
build --cxxopt=-Wno-documentation-unknown-command
build --cxxopt=-Wno-extra-semi-stmt
build --cxxopt=-Wno-extra-semi
test --test_output=errors

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}