More work on format
This commit is contained in:
2
.bazelrc
2
.bazelrc
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Reference in New Issue
Block a user