From 75e956eac30050bb10d131b8f14ecbc396abcf17 Mon Sep 17 00:00:00 2001 From: Steven Le Rouzic Date: Wed, 13 Nov 2024 23:58:18 +0100 Subject: Use string_view for formatting --- asl/format.cpp | 88 +++++++++++++++++++++-------------------- asl/format.hpp | 11 +++--- asl/print.cpp | 8 ++-- asl/print.hpp | 6 +-- asl/string_view.hpp | 32 +++++++++++++++ asl/tests/format_tests.cpp | 35 ++++++++-------- asl/tests/string_view_tests.cpp | 35 ++++++++++++++++ 7 files changed, 142 insertions(+), 73 deletions(-) (limited to 'asl') diff --git a/asl/format.cpp b/asl/format.cpp index a86ce69..5c22026 100644 --- a/asl/format.cpp +++ b/asl/format.cpp @@ -4,7 +4,7 @@ void asl::format_internals::format( writer* writer, - const char* fmt, + string_view fmt, span args) { formatter f(writer); @@ -12,87 +12,91 @@ void asl::format_internals::format( const auto* arg_it = args.begin(); const auto* arg_end = args.end(); - const char* begin = fmt; - while (*fmt != '\0') + isize_t i = 0; + while (i < fmt.size()) { - if (fmt[0] == '{') + if (fmt[i] == '{') { - if (fmt[1] == '}') + if (i + 1 < fmt.size()) { - if (arg_it < arg_end) + if (fmt[i + 1] == '}') { - f.write(begin, fmt - begin); - fmt += 2; - begin = fmt; + if (arg_it >= arg_end) + { + f.write(fmt.substr(0, i)); + fmt = fmt.substr(i + 2); + i = 0; + + f.write(""); + + continue; + } + + f.write(fmt.substr(0, i)); + fmt = fmt.substr(i + 2); + i = 0; arg_it->fn(f, arg_it->data); arg_it++; // NOLINT(*-pointer-arithmetic) + + continue; } - else + + if (fmt[i + 1] == '{') { - f.write(begin, fmt - begin); - fmt += 2; - begin = fmt; + f.write(fmt.substr(0, i + 1)); + fmt = fmt.substr(i + 2); + i = 0; - f.write("", 7); + continue; } } - 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(fmt.substr(0, i)); + fmt = fmt.substr(i + 1); + i = 0; - f.write("", 7); - } + f.write(""); } - else if (fmt[0] == '}' && fmt[1] == '}') + else if (i + 1 < fmt.size() && fmt[i] == '}' && fmt[i + 1] == '}') { - fmt += 1; - f.write(begin, fmt - begin); - fmt += 1; - begin = fmt; + f.write(fmt.substr(0, i + 1)); + fmt = fmt.substr(i + 2); + i = 0; } else { - fmt += 1; + i += 1; } } - f.write(begin, fmt - begin); + f.write(fmt); } void asl::AslFormat(formatter& f, const char* str) { - f.write(str, static_cast(__builtin_strlen(str))); + f.write({str, static_cast(__builtin_strlen(str))}); } void asl::AslFormat(formatter& f, float) { - f.write("", 7); // @Todo Float formatting + f.write(""); // @Todo Float formatting } void asl::AslFormat(formatter& f, double) { - f.write("", 8); // @Todo Float formatting + f.write(""); // @Todo Float formatting } void asl::AslFormat(formatter& f, bool v) { if (v) { - f.write("true", 4); + f.write("true"); } else { - f.write("false", 5); + f.write("false"); } } @@ -170,7 +174,7 @@ void asl::AslFormat(formatter& f, uint64_t v) write_one('0' + static_cast(v)); } - f.write(buffer + cursor, kMaxDigits - cursor); + f.write({buffer + cursor, kMaxDigits - cursor}); } void asl::AslFormat(formatter& f, int8_t v) @@ -192,7 +196,7 @@ void asl::AslFormat(formatter& f, int64_t v) { if (v < 0) { - f.write("-", 1); + f.write("-"); uint64_t absolute_value = ~(bit_cast(v) - 1); AslFormat(f, absolute_value); } diff --git a/asl/format.hpp b/asl/format.hpp index 666e325..57be45d 100644 --- a/asl/format.hpp +++ b/asl/format.hpp @@ -4,6 +4,7 @@ #include "asl/meta.hpp" #include "asl/io.hpp" #include "asl/span.hpp" +#include "asl/string_view.hpp" namespace asl { @@ -37,7 +38,7 @@ struct type_erased_arg {} }; -void format(writer*, const char* fmt, span args); +void format(writer*, string_view fmt, span args); } // namespace internals @@ -50,16 +51,14 @@ public: : m_writer{writer} {} - // @Todo Use string_view - constexpr void write(const char* s, isize_t len) + constexpr void write(string_view s) { - m_writer->write(as_bytes(span(s, len))); + m_writer->write(as_bytes(s.as_span())); } }; -// @Todo Use string_view template -void format(writer* w, const char* fmt, const Args&... args) +void format(writer* w, string_view fmt, const Args&... args) { if constexpr (types_count > 0) { diff --git a/asl/print.cpp b/asl/print.cpp index 8180c04..6f81f19 100644 --- a/asl/print.cpp +++ b/asl/print.cpp @@ -20,12 +20,12 @@ public: asl::writer* asl::print_internals::get_stdout_writer() { - static ConsoleWriter writer{stdout}; - return &writer; + static ConsoleWriter s_writer{stdout}; + return &s_writer; } asl::writer* asl::print_internals::get_stderr_writer() { - static ConsoleWriter writer{stderr}; - return &writer; + static ConsoleWriter s_writer{stderr}; + return &s_writer; } diff --git a/asl/print.hpp b/asl/print.hpp index d82d52b..4e7d07a 100644 --- a/asl/print.hpp +++ b/asl/print.hpp @@ -14,16 +14,14 @@ writer* get_stderr_writer(); } // namespace print_internals -// @Todo Use string_view template -void print(const char* fmt, const Args&... args) +void print(string_view fmt, const Args&... args) { format(print_internals::get_stdout_writer(), fmt, args...); } -// @Todo Use string_view template -void eprint(const char* fmt, const Args&... args) +void eprint(string_view fmt, const Args&... args) { format(print_internals::get_stderr_writer(), fmt, args...); } diff --git a/asl/string_view.hpp b/asl/string_view.hpp index 9045eda..2e8efff 100644 --- a/asl/string_view.hpp +++ b/asl/string_view.hpp @@ -2,6 +2,7 @@ #include "asl/integers.hpp" #include "asl/meta.hpp" +#include "asl/span.hpp" namespace asl { @@ -23,6 +24,15 @@ public: , m_size{size} {} + template + constexpr string_view(const char (&str)[kSize]) // NOLINT(*-explicit-conversions) + requires (kSize >= 1) + : m_data{str} + , m_size{kSize - 1} + { + ASL_ASSERT(m_data[kSize - 1] == '\0'); // NOLINT(*-pointer-arithmetic) + } + constexpr string_view(const string_view&) = default; constexpr string_view(string_view&&) = default; @@ -40,6 +50,26 @@ public: constexpr const char* begin() const { return m_data; } constexpr const char* end() const { return m_data + m_size; } // NOLINT(*-pointer-arithmetic) + + constexpr span as_span() const { return span(m_data, m_size); } + + constexpr char operator[](isize_t i) const + { + ASL_ASSERT(i >= 0 && i < m_size); + return m_data[i]; // NOLINT(*-pointer-arithmetic) + } + + constexpr string_view substr(isize_t offset, isize_t size) const + { + ASL_ASSERT(offset >= 0 && size >= 0 && offset + size <= m_size); + return string_view{m_data + offset, size}; // NOLINT(*-pointer-arithmetic) + } + + constexpr string_view substr(isize_t offset) const + { + ASL_ASSERT(offset >= 0 && offset <= m_size); + return string_view{m_data + offset, m_size - offset}; // NOLINT(*-pointer-arithmetic) + } }; } // namespace asl @@ -48,3 +78,5 @@ constexpr asl::string_view operator ""_sv(const char* s, size_t len) { return asl::string_view(s, static_cast(len)); } + +// @Todo Make comparison operator, replace in format and string_view tests diff --git a/asl/tests/format_tests.cpp b/asl/tests/format_tests.cpp index f051034..dd31efc 100644 --- a/asl/tests/format_tests.cpp +++ b/asl/tests/format_tests.cpp @@ -1,5 +1,6 @@ #include "asl/format.hpp" #include "asl/testing/testing.hpp" +#include "asl/print.hpp" #include #include @@ -38,47 +39,47 @@ ASL_TEST(format_args) { StringSink sink; - // @Todo Introduce ASL_TEST_ASSERT_EQ, or ASL_TEST_ASSERT_STREQ + // @Todo Introduce ASL_TEST_EXPECT_EQ, or ASL_TEST_EXPECT_STREQ // @Todo Don't use strcmp for string comparison asl::format(&sink, "Hello, world!"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "Hello, world!") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "Hello, world!") == 0); sink.reset(); asl::format(&sink, ""); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "") == 0); sink.reset(); asl::format(&sink, "Hello, {}!", "world"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "Hello, world!") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "Hello, world!") == 0); sink.reset(); asl::format(&sink, "Hello, {}! {}", "world"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "Hello, world! ") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "Hello, world! ") == 0); sink.reset(); asl::format(&sink, "Hello, pup!", "world"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "Hello, pup!") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "Hello, pup!") == 0); sink.reset(); asl::format(&sink, "{}", "CHEESE"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "CHEESE") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "CHEESE") == 0); sink.reset(); asl::format(&sink, "{ ", "CHEESE"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), " ") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), " ") == 0); sink.reset(); asl::format(&sink, "{", "CHEESE"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "") == 0); sink.reset(); asl::format(&sink, "a{{b"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "a{b") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "a{b") == 0); sink.reset(); asl::format(&sink, "{{{}}} }", "CHEESE"); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "{CHEESE} }") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "{CHEESE} }") == 0); } ASL_TEST(format_integers) @@ -87,23 +88,23 @@ ASL_TEST(format_integers) sink.reset(); asl::format(&sink, "{} {} {}", 0, 1, 2); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "0 1 2") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "0 1 2") == 0); sink.reset(); asl::format(&sink, "{} {} {}", 10, 11, 12); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "10 11 12") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "10 11 12") == 0); sink.reset(); asl::format(&sink, "{} {} {}", 100, 101, 102); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "100 101 102") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "100 101 102") == 0); sink.reset(); asl::format(&sink, "{} {} {}", 1000, 1001, 1002); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "1000 1001 1002") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "1000 1001 1002") == 0); sink.reset(); asl::format(&sink, "{} {} {} {}", -1, -23, -456, -7890); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "-1 -23 -456 -7890") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "-1 -23 -456 -7890") == 0); } ASL_TEST(format_boolean) @@ -112,5 +113,5 @@ ASL_TEST(format_boolean) sink.reset(); asl::format(&sink, "{} {}", true, false); - ASL_TEST_ASSERT(strcmp(sink.cstr(), "true false") == 0); + ASL_TEST_EXPECT(strcmp(sink.cstr(), "true false") == 0); } diff --git a/asl/tests/string_view_tests.cpp b/asl/tests/string_view_tests.cpp index dafb91c..1c12603 100644 --- a/asl/tests/string_view_tests.cpp +++ b/asl/tests/string_view_tests.cpp @@ -25,3 +25,38 @@ ASL_TEST(from_literal) asl::string_view s2 = ""_sv; ASL_TEST_EXPECT(s2.is_empty()); } + +ASL_TEST(substr1) +{ + asl::string_view s1 = "abcd"; + + asl::string_view s2 = s1.substr(0); + ASL_TEST_ASSERT(s2.size() == 4); + ASL_TEST_EXPECT(memcmp(s2.data(), "abcd", 4) == 0); + + s2 = s1.substr(2); + ASL_TEST_ASSERT(s2.size() == 2); + ASL_TEST_EXPECT(memcmp(s2.data(), "cd", 2) == 0); + + s2 = s1.substr(4); + ASL_TEST_ASSERT(s2.size() == 0); +} + +ASL_TEST(substr2) +{ + asl::string_view s1 = "abcd"; + + asl::string_view s2 = s1.substr(0, 4); + ASL_TEST_ASSERT(s2.size() == 4); + ASL_TEST_EXPECT(memcmp(s2.data(), "abcd", 4) == 0); + + s2 = s1.substr(1, 2); + ASL_TEST_ASSERT(s2.size() == 2); + ASL_TEST_EXPECT(memcmp(s2.data(), "bc", 2) == 0); + + s2 = s1.substr(4, 0); + ASL_TEST_ASSERT(s2.size() == 0); + + s2 = s1.substr(1, 0); + ASL_TEST_ASSERT(s2.size() == 0); +} -- cgit