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-documentation-unknown-command
|
||||||
build --cxxopt=-Wno-extra-semi-stmt
|
build --cxxopt=-Wno-extra-semi-stmt
|
||||||
build --cxxopt=-Wno-extra-semi
|
build --cxxopt=-Wno-extra-semi
|
||||||
|
|
||||||
|
test --test_output=errors
|
||||||
|
@ -7,6 +7,63 @@ void asl::format_internals::format(
|
|||||||
int64_t arg_count)
|
int64_t arg_count)
|
||||||
{
|
{
|
||||||
formatter f(writer);
|
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
|
// @Todo Use span
|
||||||
void format(writer*, const char* fmt, const type_erased_arg* args, int64_t arg_count);
|
void format(writer*, const char* fmt, const type_erased_arg* args, int64_t arg_count);
|
||||||
|
|
||||||
} // internals
|
} // namespace internals
|
||||||
|
|
||||||
class formatter
|
class formatter
|
||||||
{
|
{
|
||||||
@ -73,7 +73,7 @@ public:
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
void format(writer* w, const char* fmt, const Args&... 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)...
|
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...>);
|
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
|
} // 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