2 Commits 07a18afa8b ... 502a6ff1ea

Author SHA1 Message Date
  Kajetan Johannes Hammerle 502a6ff1ea Remove leftover snprintf 1 month ago
  Kajetan Johannes Hammerle 6011df96c7 Compile time string joiner 1 month ago
8 changed files with 144 additions and 49 deletions
  1. 1 0
      CMakeLists.txt
  2. 12 13
      modules/Logger.cppm
  3. 5 0
      modules/Std.cppm
  4. 51 0
      modules/StringJoin.cppm
  5. 1 1
      modules/ToString.cppm
  6. 68 32
      src/ToString.cpp
  7. 2 0
      test/Main.cpp
  8. 4 3
      test/modules/UtilityTests.cpp

+ 1 - 0
CMakeLists.txt

@@ -35,6 +35,7 @@ set(PUBLIC_MODULES
     "modules/ReadLine.cppm"
     "modules/Std.cppm"
     "modules/StringFormat.cppm"
+    "modules/StringJoin.cppm"
     "modules/Terminal.cppm"
     "modules/TerminalConstants.cppm"
     "modules/Test.cppm"

+ 12 - 13
modules/Logger.cppm

@@ -4,6 +4,7 @@ import Core.TerminalConstants;
 import Core.Meta;
 import Core.ToString;
 import Core.Std;
+import Core.StringJoin;
 
 #define SOURCE const std::source_location& sl = std::source_location::current()
 
@@ -56,37 +57,35 @@ export namespace Core {
     template<typename... Args>
     void logError(const FormatLocation& format, Args&&... args) noexcept {
         if constexpr(LOG_LEVEL >= 1) {
-            String<32> s;
-            s.addFormat("{}[ERROR] ", Terminal::FG_RED);
-            log(LogLevel::ERROR, s, format, forward<Args>(args)...);
+            log(LogLevel::ERROR, mergeStrings(Terminal::FG_RED, "[ERROR] "),
+                format, forward<Args>(args)...);
         }
     }
 
     template<typename... Args>
     void logWarning(const FormatLocation& format, Args&&... args) noexcept {
         if constexpr(LOG_LEVEL >= 2) {
-            String<32> s;
-            s.addFormat("{}[WARNING] ", Terminal::FG_BRIGHT_YELLOW);
-            log(LogLevel::WARNING, s, format, forward<Args>(args)...);
+            log(LogLevel::WARNING,
+                mergeStrings(Terminal::FG_BRIGHT_YELLOW, "[WARNING] "), format,
+                forward<Args>(args)...);
         }
     }
 
     template<typename... Args>
     void logInfo(const FormatLocation& format, Args&&... args) noexcept {
         if constexpr(LOG_LEVEL >= 3) {
-            String<32> s;
-            s.addFormat("{}[INFO] ", Terminal::BOLD);
-            log(LogLevel::INFO, s, format, forward<Args>(args)...);
+            log(LogLevel::INFO, mergeStrings(Terminal::BOLD, "[INFO] "), format,
+                forward<Args>(args)...);
         }
     }
 
     template<typename... Args>
     void logDebug(const FormatLocation& format, Args&&... args) noexcept {
         if constexpr(LOG_LEVEL >= 4) {
-            String<32> s;
-            s.addFormat(
-                "{}{}[DEBUG] ", Terminal::BOLD, Terminal::FG_BRIGHT_BLACK);
-            log(LogLevel::DEBUG, s, format, forward<Args>(args)...);
+            log(LogLevel::DEBUG,
+                mergeStrings(
+                    Terminal::FG_BRIGHT_BLACK, Terminal::BOLD, "[DEBUG] "),
+                format, forward<Args>(args)...);
         }
     }
 }

+ 5 - 0
modules/Std.cppm

@@ -1,6 +1,7 @@
 module;
 
 #include <cctype>
+#include <charconv>
 #include <clocale>
 #include <cmath>
 #include <cstdio>
@@ -12,7 +13,11 @@ export module Core.Std;
 
 // NOLINTBEGIN(misc-unused-using-decls)
 export namespace std {
+    using std::chars_format;
+    using std::errc;
     using std::source_location;
+    using std::to_chars;
+    using std::to_chars_result;
 }
 
 export using ::exit;

+ 51 - 0
modules/StringJoin.cppm

@@ -0,0 +1,51 @@
+export module Core.StringJoin;
+
+import Core.Meta;
+
+namespace Core {
+    template<int N>
+    struct MergedString {
+        char s[N];
+
+        operator const char*() const noexcept {
+            return s;
+        }
+    };
+
+    template<int N1, int N2>
+    consteval auto mergeStringsBase(const char (&a)[N1], const char (&b)[N2]) {
+        static_assert(N1 > 0);
+        MergedString<N1 + N2 - 1> s;
+        for(int i = 0; i < N1; i++) {
+            s.s[i] = a[i];
+        }
+        for(int i = 0; i < N2; i++) {
+            s.s[i + N1 - 1] = b[i];
+        }
+        return s;
+    }
+
+    template<int N1, int N2>
+    consteval auto mergeStringsBase(
+        const MergedString<N1>& a, const char (&b)[N2]) {
+        return mergeStringsBase<N1, N2>(a.s, b);
+    }
+
+    template<int N1, int N2>
+    consteval auto mergeStringsBase(
+        const char (&a)[N1], const MergedString<N2>& b) {
+        return mergeStringsBase<N1, N2>(a, b.s);
+    }
+
+    export template<typename A, typename B>
+    consteval auto mergeStrings(const A& a, const B& b) {
+        return mergeStringsBase(a, b);
+    }
+
+    export template<typename A, typename B, typename... Args>
+    consteval auto mergeStrings(const A& a, const B& b, Args&&... args) {
+        auto c = mergeStringsBase(a, b);
+        return mergeStrings<decltype(c), Args...>(
+            c, Core::forward<Args>(args)...);
+    }
+}

+ 1 - 1
modules/ToString.cppm

@@ -106,7 +106,6 @@ export namespace Core {
         TO_STRING(double);
         TO_STRING(const char*);
         TO_STRING(const unsigned char*);
-        TO_STRING(unsigned char*);
         TO_STRING(bool);
 
         template<typename T>
@@ -134,6 +133,7 @@ export namespace Core {
             applyPostFormat(oldIndex, index - oldIndex, format);
         }
 
+        void addChar(char c);
         void applyPostFormat(
             size_t startIndex, size_t length,
             const StringFormat& format) noexcept;

+ 68 - 32
src/ToString.cpp

@@ -1,49 +1,77 @@
-module;
-
-#include <cstdio>
-
 module Core.ToString;
 
 import Core.Std;
 
-#define TO_STRING(type, format)                                               \
-    void Core::StringBase::toString(type v, const StringFormat& f) noexcept { \
-        (void)f;                                                              \
-        int e = snprintf(getCurrent(), getCapacity(), format, v);             \
-        index += e < 0 ? 0 : static_cast<size_t>(e);                          \
-    }
 #define TO_STRING_LINK(from, to)                                              \
     void Core::StringBase::toString(from v, const StringFormat& f) noexcept { \
         toString(static_cast<to>(v), f);                                      \
     }
 
-TO_STRING(char, "%c")
-TO_STRING_LINK(signed char, char)
-TO_STRING(short, "%hd")
-TO_STRING(int, "%d")
-TO_STRING(long, "%ld")
-TO_STRING(long long, "%lld")
-TO_STRING(unsigned char, "%c")
-TO_STRING(unsigned short, "%hu")
-TO_STRING(unsigned int, "%u")
-TO_STRING(unsigned long, "%lu")
-TO_STRING(unsigned long long, "%llu")
+TO_STRING_LINK(short, long long)
+TO_STRING_LINK(int, long long)
+TO_STRING_LINK(long, long long)
+TO_STRING_LINK(unsigned short, unsigned long long)
+TO_STRING_LINK(unsigned int, unsigned long long)
+TO_STRING_LINK(unsigned long, unsigned long long)
 TO_STRING_LINK(float, double)
-TO_STRING(const char*, "%s")
-TO_STRING(const unsigned char*, "%s")
-TO_STRING_LINK(unsigned char*, const unsigned char*)
+
+void Core::StringBase::toString(char c, const StringFormat&) noexcept {
+    addChar(c);
+}
+
+void Core::StringBase::toString(signed char c, const StringFormat&) noexcept {
+    addChar(static_cast<char>(c));
+}
+
+void Core::StringBase::toString(unsigned char c, const StringFormat&) noexcept {
+    addChar(static_cast<char>(c));
+}
+
+void Core::StringBase::toString(const char* s, const StringFormat&) noexcept {
+    while(*s != '\0') {
+        addChar(*(s++));
+    }
+}
+
+void Core::StringBase::toString(
+    const unsigned char* s, const StringFormat& f) noexcept {
+    return toString(reinterpret_cast<const char*>(s), f);
+}
+
+template<typename T, typename... Args>
+static void toBuffer(char* s, size_t n, T t, Args&&... args) {
+    std::to_chars_result r = std::to_chars(s, s + n, t, args...);
+    if(r.ec == std::errc()) {
+        *r.ptr = '\0';
+    } else {
+        *(s++) = '?';
+        *s = '\0';
+    }
+}
+
+void Core::StringBase::toString(long long v, const StringFormat& f) noexcept {
+    char s[32];
+    toBuffer(s, sizeof(s), v, 10);
+    toString(s, f);
+}
+
+void Core::StringBase::toString(
+    unsigned long long v, const StringFormat& f) noexcept {
+    char s[32];
+    toBuffer(s, sizeof(s), v, 10);
+    toString(s, f);
+}
 
 void Core::StringBase::toString(double v, const StringFormat& f) noexcept {
-    int e = snprintf(
-        getCurrent(), getCapacity(), "%.*f", f.precision < 0 ? 2 : f.precision,
-        v);
-    index += e < 0 ? 0 : static_cast<size_t>(e);
+    char s[64];
+    toBuffer(
+        s, sizeof(s), v, std::chars_format::fixed,
+        f.precision < 0 ? 2 : f.precision);
+    toString(s, f);
 }
 
 void Core::StringBase::toString(bool v, const StringFormat& f) noexcept {
-    (void)f;
-    int e = snprintf(getCurrent(), getCapacity(), "%s", v ? "true" : "false");
-    index += e < 0 ? 0 : static_cast<size_t>(e);
+    toString(v ? "true" : "false", f);
 }
 
 static int parseFormatNumber(const char*& from, const char* to) noexcept {
@@ -110,6 +138,14 @@ void Core::StringBase::print() const noexcept {
     }
 }
 
+void Core::StringBase::addChar(char c) {
+    if(index + 1 < capacity) {
+        buffer[index] = c;
+        buffer[index + 1] = '\0';
+    }
+    index++;
+}
+
 void Core::StringBase::applyPostFormat(
     size_t startIndex, size_t length, const StringFormat& format) noexcept {
     if(format.width <= 0) {
@@ -118,7 +154,7 @@ void Core::StringBase::applyPostFormat(
     size_t w = static_cast<size_t>(format.width);
     if(format.alignment == StringAlignment::LEFT) {
         while(length < w) {
-            add(" ");
+            addChar(' ');
             length++;
         }
     } else if(format.alignment == StringAlignment::RIGHT) {

+ 2 - 0
test/Main.cpp

@@ -96,6 +96,8 @@ int main(int argAmount, const char** args) {
     Core::logLevel = Core::LogLevel::WARNING;
     Core::logDebug("You won't see this!");
     Core::logLevel = Core::LogLevel::DEBUG;
+    Core::logDebug("Some debug message");
+    Core::logInfo("Great information");
 
     unsigned int data = 123'456'789;
     Core::setExitHandler(onExit, &data);

+ 4 - 3
test/modules/UtilityTests.cpp

@@ -108,13 +108,14 @@ static void testToString() {
     Core::test(10, b.format("{} {} {}", 456ll, 567l, 78ull));
 
     char c = 'a';
-    short s = 4;
+    short s = -454;
     unsigned char cu = 'h';
     unsigned short su = 67;
     signed char cs = 'x';
     b = Core::StringBase(buffer, sizeof(buffer));
-    Core::test(10, b.format("{} {} {} {} {}", c, s, cu, su, cs));
-    Core::testString("a 4 h 67 x", b);
+    Core::test(
+        24, b.format("{} {} {} {} {} {} {}", c, s, cu, su, cs, true, false));
+    Core::testString("a -454 h 67 x true false", b);
 
     unsigned char text[] = "fgsdf";
     b.clear();