소스 검색

Get rid of printf/snprintf

Kajetan Johannes Hammerle 1 주 전
부모
커밋
a46204ec97
58개의 변경된 파일302개의 추가작업 그리고 284개의 파일을 삭제
  1. 1 0
      CMakeLists.txt
  2. 0 2
      modules/AlignedData.cppm
  3. 0 2
      modules/Array.cppm
  4. 0 2
      modules/ArrayList.cppm
  5. 1 3
      modules/Assert.cppm
  6. 0 2
      modules/BitArray.cppm
  7. 0 2
      modules/Box.cppm
  8. 0 2
      modules/Buffer.cppm
  9. 0 2
      modules/Clock.cppm
  10. 0 2
      modules/Color.cppm
  11. 1 4
      modules/Components.cppm
  12. 0 2
      modules/File.cppm
  13. 0 2
      modules/Frustum.cppm
  14. 1 4
      modules/HashMap.cppm
  15. 2 5
      modules/HashedString.cppm
  16. 0 4
      modules/List.cppm
  17. 8 11
      modules/Logger.cppm
  18. 0 2
      modules/Math.cppm
  19. 0 2
      modules/Matrix.cppm
  20. 0 2
      modules/Meta.cppm
  21. 2 2
      modules/New.cppm
  22. 0 2
      modules/Plane.cppm
  23. 0 2
      modules/Quaternion.cppm
  24. 0 2
      modules/Queue.cppm
  25. 0 2
      modules/Random.cppm
  26. 0 2
      modules/ReadLine.cppm
  27. 12 5
      modules/Std.cppm
  28. 11 0
      modules/StringFormat.cppm
  29. 0 2
      modules/Terminal.cppm
  30. 0 2
      modules/TerminalConstants.cppm
  31. 1 3
      modules/Test.cppm
  32. 118 52
      modules/ToString.cppm
  33. 0 2
      modules/Unicode.cppm
  34. 0 2
      modules/UniquePointer.cppm
  35. 0 2
      modules/Utility.cppm
  36. 0 2
      modules/Vector.cppm
  37. 0 2
      modules/View.cppm
  38. 6 6
      performance/Main.cpp
  39. 0 2
      src/BitArray.cpp
  40. 4 10
      src/Box.cpp
  41. 7 6
      src/File.cpp
  42. 3 9
      src/Plane.cpp
  43. 3 9
      src/Quaternion.cpp
  44. 2 5
      src/ReadLine.cpp
  45. 6 7
      src/Terminal.cpp
  46. 8 11
      src/Test.cpp
  47. 5 4
      src/Thread.cpp
  48. 61 16
      src/ToString.cpp
  49. 0 2
      src/Unicode.cpp
  50. 9 13
      src/Utility.cpp
  51. 4 2
      test/Main.cpp
  52. 0 2
      test/Tests.cppm
  53. 1 3
      test/modules/FileTests.cpp
  54. 2 6
      test/modules/QueueTests.cpp
  55. 5 8
      test/modules/ReadLineTests.cpp
  56. 7 10
      test/modules/TerminalTests.cpp
  57. 10 7
      test/modules/UtilityTests.cpp
  58. 1 3
      test/modules/VectorTests.cpp

+ 1 - 0
CMakeLists.txt

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

+ 0 - 2
modules/AlignedData.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.AlignedData;
 
 export import Core.Types;

+ 0 - 2
modules/Array.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Array;
 
 export import Core.Types;

+ 0 - 2
modules/ArrayList.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.ArrayList;
 
 export import Core.New;

+ 1 - 3
modules/Assert.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Assert;
 
 import Core.Std;
@@ -16,7 +14,7 @@ export namespace Core {
         const std::source_location& l = std::source_location::current()) {
         if(!b) {
             Core::logError(
-                FormatLocation("Assert in function #", l),
+                FormatLocation("Assert in function {}", l),
                 getShortFileName(l.file_name()), l.line(), l.function_name());
             exitWithHandler(1, l);
         }

+ 0 - 2
modules/BitArray.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.BitArray;
 
 import Core.Types;

+ 0 - 2
modules/Box.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Box;
 
 export import Core.Vector;

+ 0 - 2
modules/Buffer.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Buffer;
 
 import Core.Types;

+ 0 - 2
modules/Clock.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Clock;
 
 import Core.Array;

+ 0 - 2
modules/Color.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Color;
 
 export import Core.Types;

+ 1 - 4
modules/Components.cppm

@@ -1,15 +1,12 @@
-module;
-
 export module Core.Components;
 
 export import Core.Utility;
+export import Core.New;
 
 import Core.HashMap;
 import Core.List;
 import Core.Meta;
 
-export using ::operator new;
-
 export namespace Core {
     using Entity = size_t;
 

+ 0 - 2
modules/File.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.File;
 
 export import Core.List;

+ 0 - 2
modules/Frustum.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Frustum;
 
 export import Core.Matrix;

+ 1 - 4
modules/HashMap.cppm

@@ -1,9 +1,8 @@
-module;
-
 export module Core.HashMap;
 
 export import Core.Types;
 export import Core.Utility;
+export import Core.New;
 
 import Core.List;
 import Core.ToString;
@@ -11,8 +10,6 @@ import Core.AlignedData;
 import Core.Math;
 import Core.Meta;
 
-export using ::operator new;
-
 export template<typename T>
 concept Hashable = requires(const T& t) { t.hashCode(); };
 export template<typename T>

+ 2 - 5
modules/HashedString.cppm

@@ -1,12 +1,9 @@
-module;
-
-#include <cstdio>
-
 export module Core.HashedString;
 
 export import Core.Types;
 
 import Core.Std;
+import Core.ToString;
 
 export namespace Core {
     struct StringHash {
@@ -33,7 +30,7 @@ export namespace Core {
         }
 
         HashedString(const char* s) : hash(hashString(s)) {
-            snprintf(data, N, "%s", s);
+            toString(s, data, N);
         }
 
         bool operator==(const HashedString& other) const {

+ 0 - 4
modules/List.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.List;
 
 export import Core.Utility;
@@ -11,8 +9,6 @@ import Core.Meta;
 import Core.ToString;
 import Core.Assert;
 
-export using ::operator new;
-
 export namespace Core {
     template<typename T>
     class List final {

+ 8 - 11
modules/Logger.cppm

@@ -1,7 +1,3 @@
-module;
-
-#include <cstdio>
-
 export module Core.Logger;
 
 import Core.TerminalConstants;
@@ -53,7 +49,7 @@ export namespace Core {
         }
         const char* file = getShortFileName(format.location.file_name());
         fputs(prefix, stdout);
-        printf("%s:%u | ", file, format.location.line());
+        print("{}:{} | ", file, format.location.line());
         char buffer[512];
         formatBuffer(
             buffer, sizeof(buffer), format.format,
@@ -66,7 +62,8 @@ export namespace Core {
     void logError(const FormatLocation& format, Args&&... args) {
         if constexpr(LOG_LEVEL >= 1) {
             char buffer[32];
-            snprintf(buffer, sizeof(buffer), "%s[ERROR] ", Terminal::FG_RED);
+            formatBuffer(
+                buffer, sizeof(buffer), "{}[ERROR] ", Terminal::FG_RED);
             log(LogLevel::ERROR, buffer, format, forward<Args>(args)...);
         }
     }
@@ -75,8 +72,8 @@ export namespace Core {
     void logWarning(const FormatLocation& format, Args&&... args) {
         if constexpr(LOG_LEVEL >= 2) {
             char buffer[32];
-            snprintf(
-                buffer, sizeof(buffer), "%s[WARNING] ",
+            formatBuffer(
+                buffer, sizeof(buffer), "{}[WARNING] ",
                 Terminal::FG_BRIGHT_YELLOW);
             log(LogLevel::WARNING, buffer, format, forward<Args>(args)...);
         }
@@ -86,7 +83,7 @@ export namespace Core {
     void logInfo(const FormatLocation& format, Args&&... args) {
         if constexpr(LOG_LEVEL >= 3) {
             char buffer[32];
-            snprintf(buffer, sizeof(buffer), "%s[INFO] ", Terminal::BOLD);
+            formatBuffer(buffer, sizeof(buffer), "{}[INFO] ", Terminal::BOLD);
             log(LogLevel::INFO, buffer, format, forward<Args>(args)...);
         }
     }
@@ -95,8 +92,8 @@ export namespace Core {
     void logDebug(const FormatLocation& format, Args&&... args) {
         if constexpr(LOG_LEVEL >= 4) {
             char buffer[32];
-            snprintf(
-                buffer, sizeof(buffer), "%s%s[DEBUG] ", Terminal::BOLD,
+            formatBuffer(
+                buffer, sizeof(buffer), "{}{}[DEBUG] ", Terminal::BOLD,
                 Terminal::FG_BRIGHT_BLACK);
             log(LogLevel::DEBUG, buffer, format, forward<Args>(args)...);
         }

+ 0 - 2
modules/Math.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Math;
 
 import Core.Meta;

+ 0 - 2
modules/Matrix.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Matrix;
 
 export import Core.Quaternion;

+ 0 - 2
modules/Meta.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Meta;
 
 namespace Core {

+ 2 - 2
modules/New.cppm

@@ -5,7 +5,7 @@ module;
 export module Core.New;
 
 export namespace std {
-    using std::set_new_handler;
+    using std::set_new_handler; // NOLINT
 }
 
-export using ::operator new;
+export using ::operator new; // NOLINT

+ 0 - 2
modules/Plane.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Plane;
 
 export import Core.Vector;

+ 0 - 2
modules/Quaternion.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Quaternion;
 
 export import Core.Vector;

+ 0 - 2
modules/Queue.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Queue;
 
 export import Core.New;

+ 0 - 2
modules/Random.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Random;
 
 import Core.Array;

+ 0 - 2
modules/ReadLine.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.ReadLine;
 
 export import Core.Types;

+ 12 - 5
modules/Std.cppm

@@ -10,19 +10,23 @@ module;
 
 export module Core.Std;
 
+// NOLINTBEGIN(misc-unused-using-decls)
 export namespace std {
     using std::source_location;
 }
 
+export using ::exit;
 export using ::fflush;
 export using ::fputs;
 export using ::free;
 export using ::iscntrl;
+export using ::malloc;
 export using ::memcmp;
 export using ::memcpy;
 export using ::memset;
+export using ::putchar;
 export using ::puts;
-export using ::setlocale;
+export using ::realloc;
 export using ::sincosf;
 export using ::sqrtf;
 export using ::stdout;
@@ -30,7 +34,10 @@ export using ::strcmp;
 export using ::strdup;
 export using ::strstr;
 export using ::tanf;
-export using ::malloc;
-export using ::realloc;
-export using ::exit;
-export inline auto CORE_LC_ALL = LC_ALL;
+// NOLINTEND(misc-unused-using-decls)
+
+export void setDefaultLocal();
+
+void setDefaultLocal() {
+    setlocale(LC_ALL, "en_US.utf8");
+}

+ 11 - 0
modules/StringFormat.cppm

@@ -0,0 +1,11 @@
+export module Core.StringFormat;
+
+export namespace Core {
+    enum class StringAlignment { LEFT, RIGHT };
+
+    struct StringFormat {
+        StringAlignment alignment = StringAlignment::RIGHT;
+        int width = -1;
+        int precision = -1;
+    };
+}

+ 0 - 2
modules/Terminal.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Terminal;
 
 export import Core.Vector;

+ 0 - 2
modules/TerminalConstants.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.TerminalConstants;
 
 export import Core.Vector;

+ 1 - 3
modules/Test.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Test;
 
 import Core.Logger;
@@ -21,7 +19,7 @@ export namespace Core {
         }
         char buffer[512];
         formatBuffer(
-            buffer, sizeof(buffer), "#@#:# - expected '#' got '#'#",
+            buffer, sizeof(buffer), "{}{}:{} - expected '{}' got '{}'{}",
             Terminal::FG_RED, file, l.line(), wanted, actual, Terminal::RESET);
         puts(buffer);
         return false;

+ 118 - 52
modules/ToString.cppm

@@ -1,74 +1,91 @@
-module;
-
 export module Core.ToString;
 
 import Core.Math;
 import Core.Meta;
 import Core.Types;
 
+export import Core.StringFormat;
+
+#define TO_STRING(type) \
+    size_t toString(type t, char* s, size_t n, const StringFormat& format = {})
+
 export namespace Core {
-    size_t toString(signed char v, char* s, size_t n);
-    size_t toString(char v, char* s, size_t n);
-    size_t toString(short v, char* s, size_t n);
-    size_t toString(int v, char* s, size_t n);
-    size_t toString(long v, char* s, size_t n);
-    size_t toString(long long v, char* s, size_t n);
-    size_t toString(unsigned char v, char* s, size_t n);
-    size_t toString(unsigned short v, char* s, size_t n);
-    size_t toString(unsigned int v, char* s, size_t n);
-    size_t toString(unsigned long v, char* s, size_t n);
-    size_t toString(unsigned long long v, char* s, size_t n);
-    size_t toString(float v, char* s, size_t n);
-    size_t toString(double v, char* s, size_t n);
-    size_t toString(const char* v, char* s, size_t n);
-    size_t toString(char* v, char* s, size_t n);
-    size_t toString(const unsigned char* v, char* s, size_t n);
-    size_t toString(unsigned char* v, char* s, size_t n);
-    size_t toString(bool v, char* s, size_t n);
+    TO_STRING(signed char);
+    TO_STRING(char);
+    TO_STRING(short);
+    TO_STRING(int);
+    TO_STRING(long);
+    TO_STRING(long long);
+    TO_STRING(unsigned char);
+    TO_STRING(unsigned short);
+    TO_STRING(unsigned int);
+    TO_STRING(unsigned long);
+    TO_STRING(unsigned long long);
+    TO_STRING(float);
+    TO_STRING(double);
+    TO_STRING(const char*);
+    TO_STRING(const unsigned char*);
+    TO_STRING(unsigned char*);
+    TO_STRING(bool);
 
     template<typename T>
-    size_t toString(const T& t, char* s, size_t n);
+    void addString(
+        const T& t, char*& s, size_t& n, size_t& total,
+        const StringFormat& format = {});
+
+    template<Core::Iterable T>
+    size_t toString(
+        const T& t, char* s, size_t n, const StringFormat& format = {}) {
+        (void)format;
+        size_t total = 0;
+        addString("[", s, n, total);
+        auto current = t.begin();
+        auto end = t.end();
+        if(current != end) {
+            addString(*current, s, n, total);
+            ++current;
+        }
+        while(current != end) {
+            addString(", ", s, n, total);
+            addString(*current, s, n, total);
+            ++current;
+        }
+        addString("]", s, n, total);
+        return total;
+    }
 
     template<typename T>
-    void addString(const T& t, char*& s, size_t& n, size_t& total) {
-        size_t w = toString(t, s, n);
+    concept ToString =
+        requires(const T& t, char* s, size_t n) { t.toString(s, n); };
+
+    template<ToString T>
+    size_t toString(
+        const T& t, char* s, size_t n, const StringFormat& format = {}) {
+        (void)format;
+        return t.toString(s, n);
+    }
+
+    template<typename T>
+    void addString(
+        const T& t, char*& s, size_t& n, size_t& total,
+        const StringFormat& format) {
+        size_t w = toString(t, s, n, format);
         total += w;
         w = Core::min(n, w);
         s += w;
         n -= w;
     }
 
-    template<typename T>
-    size_t toString(const T& t, char* s, size_t n) {
-        if constexpr(Core::Iterable<T>) {
-            size_t total = 0;
-            addString("[", s, n, total);
-            auto current = t.begin();
-            auto end = t.end();
-            if(current != end) {
-                addString(*current, s, n, total);
-                ++current;
-            }
-            while(current != end) {
-                addString(", ", s, n, total);
-                addString(*current, s, n, total);
-                ++current;
-            }
-            addString("]", s, n, total);
-            return total;
-        } else {
-            return t.toString(s, n);
-        }
-    }
-
-    size_t copyFormatUntil(const char*& format, char*& s, size_t& n);
+    size_t copyFormatUntil(
+        const char*& format, char*& s, size_t& n, StringFormat& f);
 
     template<typename T, typename... Args>
     void formatR(
         const char*& format, char*& s, size_t& n, size_t& total, const T& t,
         Args&&... args) {
-        total += copyFormatUntil(format, s, n);
-        addString(t, s, n, total);
+        StringFormat f;
+        total += copyFormatUntil(format, s, n, f);
+        addString(t, s, n, total, f);
         if constexpr(sizeof...(args) > 0) {
             formatR(format, s, n, total, Core::forward<Args>(args)...);
         }
@@ -76,11 +93,60 @@ export namespace Core {
 
     template<typename... Args>
     size_t formatBuffer(char* s, size_t n, const char* format, Args&&... args) {
+        StringFormat f;
+        size_t total = 0;
         if constexpr(sizeof...(args) > 0) {
-            size_t total = 0;
             formatR(format, s, n, total, Core::forward<Args>(args)...);
-            return total + toString(format, s, n);
         }
-        return copyFormatUntil(format, s, n);
+        return total + copyFormatUntil(format, s, n, f);
+    }
+
+    struct StringBase {
+        size_t index = 0;
+        size_t capacity = 0;
+        char* buffer = nullptr;
+
+        StringBase() {
+        }
+
+        StringBase(StringBase&& other) = default;
+        StringBase(const StringBase& other) = delete;
+        StringBase& operator=(StringBase&& other) = default;
+        StringBase& operator=(const StringBase& other) = delete;
+
+        template<typename... Args>
+        size_t format(const char* format, Args&&... args) {
+            size_t total = formatBuffer(
+                buffer + index, capacity - index, format,
+                Core::forward<Args>(args)...);
+            index = Core::min(index + total, capacity);
+            return total;
+        }
+
+        template<typename T>
+        size_t add(const T& t) {
+            size_t total = toString(t, buffer + index, capacity - index);
+            index = Core::min(index + total, capacity);
+            return total;
+        }
+
+        void print();
+    };
+
+    template<size_t N>
+    struct String : public StringBase {
+        char data[N]{};
+
+        String() {
+            buffer = data;
+            capacity = N;
+        }
+    };
+
+    template<typename... Args>
+    void print(const char* format, Args&&... args) {
+        String<256> s;
+        s.format(format, Core::forward<Args>(args)...);
+        s.print();
     }
 }

+ 0 - 2
modules/Unicode.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Unicode;
 
 export import Core.Types;

+ 0 - 2
modules/UniquePointer.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.UniquePointer;
 
 export namespace Core {

+ 0 - 2
modules/Utility.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Utility;
 
 export import Core.Types;

+ 0 - 2
modules/Vector.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.Vector;
 
 export import Core.Types;

+ 0 - 2
modules/View.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Core.View;
 
 export import Core.Matrix;

+ 6 - 6
performance/Main.cpp

@@ -38,7 +38,7 @@ static void fillOrder(HashMapInt& m) {
     for(int i = 0; i < 10'000; i++) {
         m.put(i, i * i);
     }
-    Core::logInfo("Fill Order: #ns", Clock::getNanos() - nanos);
+    Core::logInfo("Fill Order: {}ns", Clock::getNanos() - nanos);
 }
 
 static void fillChaos(HashMapInt& m) {
@@ -48,7 +48,7 @@ static void fillChaos(HashMapInt& m) {
         int r = random.nextI32(0, 10'000);
         m.put(r, r * r);
     }
-    Core::logInfo("Fill Chaos: #ns", Clock::getNanos() - nanos);
+    Core::logInfo("Fill Chaos: {}ns", Clock::getNanos() - nanos);
 }
 
 static i64 average(HashMapInt& m, i64 (*f)(const HashMapInt& m), int n) {
@@ -63,16 +63,16 @@ static void order(int n) {
     HashMapInt m;
     fillOrder(m);
     Core::logInfo("Order Probing");
-    Core::logInfo("Search | #ms", average(m, testSearch, n));
-    Core::logInfo("EmptySearch | #ms", average(m, testEmptySearch, n));
+    Core::logInfo("Search | {}ms", average(m, testSearch, n));
+    Core::logInfo("EmptySearch | {}ms", average(m, testEmptySearch, n));
 }
 
 static void chaos(int n) {
     HashMapInt m;
     fillChaos(m);
     Core::logInfo("Chaos Probing");
-    Core::logInfo("Search | #ms", average(m, testSearch, n));
-    Core::logInfo("EmptySearch | #ms", average(m, testEmptySearch, n));
+    Core::logInfo("Search | {}ms", average(m, testSearch, n));
+    Core::logInfo("EmptySearch | {}ms", average(m, testEmptySearch, n));
 }
 
 int main() {

+ 0 - 2
src/BitArray.cpp

@@ -1,5 +1,3 @@
-module;
-
 module Core.BitArray;
 
 import Core.ToString;

+ 4 - 10
src/Box.cpp

@@ -1,10 +1,7 @@
-module;
-
-#include <cstdio>
-
 module Core.Box;
 
 import Core.Std;
+import Core.ToString;
 
 using Core::Box;
 
@@ -65,10 +62,7 @@ const Core::Vector3& Box::getMax() const {
 }
 
 size_t Box::toString(char* s, size_t n) const {
-    int w = snprintf(
-        s, n, "Box([%.2f, %.2f, %.2f], [%.2f, %.2f, %.2f])",
-        static_cast<double>(min[0]), static_cast<double>(min[1]),
-        static_cast<double>(min[2]), static_cast<double>(max[0]),
-        static_cast<double>(max[1]), static_cast<double>(max[2]));
-    return w >= 0 ? static_cast<size_t>(w) : 0;
+    return formatBuffer(
+        s, n, "Box([{.2}, {.2}, {.2}], [{.2}, {.2}, {.2}])", min[0], min[1],
+        min[2], max[0], max[1], max[2]);
 }

+ 7 - 6
src/File.cpp

@@ -11,25 +11,26 @@ using Core::LogLevel;
 
 static bool readOpenFile(FILE* file, Core::List<char>& f, const char* path) {
     if(doFailStep() || fseek(file, 0, SEEK_END)) {
-        Core::report(LogLevel::ERROR, "cannot seek file end of '#'", path);
+        Core::report(LogLevel::ERROR, "cannot seek file end of '{}'", path);
         return true;
     }
     long l = ftell(file);
     if(doFailStep() || l < 0) {
-        Core::report(LogLevel::ERROR, "cannot tell file position of '#'", path);
+        Core::report(
+            LogLevel::ERROR, "cannot tell file position of '{}'", path);
         return true;
     }
     size_t size = static_cast<size_t>(l);
     f.resize(size + 1);
     if(doFailStep() || fseek(file, 0, SEEK_SET)) {
-        Core::report(LogLevel::ERROR, "cannot seek file start of '#'", path);
+        Core::report(LogLevel::ERROR, "cannot seek file start of '{}'", path);
         return true;
     }
     size_t read = fread(&f[0], 1, size, file);
     f.getLast() = 0;
     if(doFailStep() || read != size) {
         Core::report(
-            LogLevel::ERROR, "expected to read # bytes from '#' but read #",
+            LogLevel::ERROR, "expected to read {} bytes from '{}' but read {}",
             size, path, read);
         return true;
     }
@@ -39,12 +40,12 @@ static bool readOpenFile(FILE* file, Core::List<char>& f, const char* path) {
 bool Core::readFile(List<char>& f, const char* path) {
     FILE* file = fopen(path, "rb");
     if(file == nullptr) {
-        report(LogLevel::ERROR, "cannot read file '#'", path);
+        report(LogLevel::ERROR, "cannot read file '{}'", path);
         return true;
     }
     bool r = readOpenFile(file, f, path);
     if(doFailStep() || fclose(file)) {
-        report(LogLevel::ERROR, "cannot close file '#'", path);
+        report(LogLevel::ERROR, "cannot close file '{}'", path);
         r = true;
     }
     return r;

+ 3 - 9
src/Plane.cpp

@@ -1,10 +1,7 @@
-module;
-
-#include <cstdio>
-
 module Core.Plane;
 
 import Core.Std;
+import Core.ToString;
 
 using Core::Plane;
 
@@ -20,9 +17,6 @@ float Plane::signedDistance(const Vector3& v) const {
 }
 
 size_t Plane::toString(char* s, size_t n) const {
-    int w = snprintf(
-        s, n, "(%.3f x + %.3f y + %.3f z + %.3f)", static_cast<double>(abc[0]),
-        static_cast<double>(abc[1]), static_cast<double>(abc[2]),
-        static_cast<double>(d));
-    return w >= 0 ? static_cast<size_t>(w) : 0;
+    return formatBuffer(
+        s, n, "({.3} x + {.3} y + {.3} z + {.3})", abc[0], abc[1], abc[2], d);
 }

+ 3 - 9
src/Quaternion.cpp

@@ -1,11 +1,8 @@
-module;
-
-#include <cstdio>
-
 module Core.Quaternion;
 
 import Core.Math;
 import Core.Std;
+import Core.ToString;
 
 Core::Quaternion::Quaternion() : v(0.0f, 0.0f, 0.0f, 1.0f) {
 }
@@ -46,9 +43,6 @@ Core::Vector3 Core::Quaternion::operator*(const Vector3& v3) const {
 }
 
 size_t Core::Quaternion::toString(char* s, size_t n) const {
-    int w = snprintf(
-        s, n, "(%.3f i + %.3f j + %.3f k + %.3f)", static_cast<double>(v[0]),
-        static_cast<double>(v[1]), static_cast<double>(v[2]),
-        static_cast<double>(v[3]));
-    return w >= 0 ? static_cast<size_t>(w) : 0;
+    return formatBuffer(
+        s, n, "({.3} i + {.3} j + {.3} k + {.3})", v[0], v[1], v[2], v[3]);
 }

+ 2 - 5
src/ReadLine.cpp

@@ -1,7 +1,3 @@
-module;
-
-#include <cstdio>
-
 module Core.ReadLine;
 
 import Core.Array;
@@ -14,6 +10,7 @@ import Core.TerminalConstants;
 import Core.Types;
 import Core.Unicode;
 import Core.Std;
+import Core.ToString;
 
 static constexpr size_t HISTORY_LENGTH = 10;
 static constexpr size_t CONSOLE_BUFFER_SIZE = 256;
@@ -224,7 +221,7 @@ bool Core::readLine(char* buffer_, size_t n) {
         return false;
     }
     Core::MutexGuard mg(bufferMutex);
-    snprintf(buffer_, n, "%s", buffer[0].data.begin());
+    toString(buffer[0].data.begin(), buffer_, n);
     buffer.remove();
     return true;
 }

+ 6 - 7
src/Terminal.cpp

@@ -1,7 +1,5 @@
 module;
 
-#include <cstdio>
-
 #include <sys/ioctl.h>
 #include <termios.h>
 #include <unistd.h>
@@ -13,6 +11,7 @@ import Core.Array;
 import Core.Logger;
 import Core.Unicode;
 import Core.Std;
+import Core.ToString;
 
 #define ESC "\33["
 #define esc(s) fputs(ESC s, stdout)
@@ -129,19 +128,19 @@ void Core::resetCursor() {
 }
 
 void Core::moveCursorLeft(int i) {
-    printf(ESC "%dD", i);
+    print(ESC "{}D", i);
 }
 
 void Core::moveCursorRight(int i) {
-    printf(ESC "%dC", i);
+    print(ESC "{}C", i);
 }
 
 void Core::moveCursorUp(int i) {
-    printf(ESC "%dA", i);
+    print(ESC "{}A", i);
 }
 
 void Core::moveCursorDown(int i) {
-    printf(ESC "%dB", i);
+    print(ESC "{}B", i);
 }
 
 bool Core::enterRawTerminal() {
@@ -201,7 +200,7 @@ static u64 readEscapeSequence() {
         s[l++] = readChar();
     }
     Core::report(
-        LogLevel::WARNING, "Unknown escape sequence starting with '#'", s);
+        LogLevel::WARNING, "Unknown escape sequence starting with '{}'", s);
     return Core::Terminal::KEY_UNKNOWN;
 }
 

+ 8 - 11
src/Test.cpp

@@ -1,12 +1,9 @@
-module;
-
-#include <cstdio>
-
 module Core.Test;
 
 import Core.Logger;
 import Core.Utility;
 import Core.Std;
+import Core.ToString;
 
 typedef struct {
     char* file;
@@ -43,8 +40,8 @@ void Core::finalizeTests(void) {
         Result* r = results + i;
         bool c = r->successTests == r->tests;
         fputs(c ? Terminal::FG_GREEN : Terminal::FG_RED, stdout);
-        printf(
-            "%s - %d / %d tests succeeded", r->file, r->successTests, r->tests);
+        print(
+            "{} - {} / {} tests succeeded", r->file, r->successTests, r->tests);
         puts(Terminal::RESET);
         free(r->file);
     }
@@ -74,7 +71,7 @@ bool Core::testString(
     const char* wanted, const char* actual, const std::source_location& l) {
     TEST_SUCCESS(strcmp(wanted, actual) == 0)
     fputs(Terminal::FG_RED, stdout);
-    printf("%s:%u - expected '%s' got '%s'", file, l.line(), wanted, actual);
+    print("{}:{} - expected '{}' got '{}'", file, l.line(), wanted, actual);
     puts(Terminal::RESET);
     return false;
 }
@@ -85,8 +82,8 @@ bool Core::testFloat(
     diff = diff < 0.0f ? -diff : diff;
     TEST_SUCCESS(diff <= error)
     fputs(Terminal::FG_RED, stdout);
-    printf(
-        "%s:%u - expected '%.3f' got '%.3f'", file, l.line(),
+    print(
+        "{}:{} - expected '{.3}' got '{.3}'", file, l.line(),
         static_cast<double>(wanted), static_cast<double>(actual));
     puts(Terminal::RESET);
     return false;
@@ -95,7 +92,7 @@ bool Core::testFloat(
 bool Core::testNull(const void* actual, const std::source_location& l) {
     TEST_SUCCESS(actual == nullptr)
     fputs(Terminal::FG_RED, stdout);
-    printf("%s:%u - expected null", file, l.line());
+    print("{}:{} - expected null", file, l.line());
     puts(Terminal::RESET);
     return false;
 }
@@ -103,7 +100,7 @@ bool Core::testNull(const void* actual, const std::source_location& l) {
 bool Core::testNotNull(const void* actual, const std::source_location& l) {
     TEST_SUCCESS(actual != nullptr)
     fputs(Terminal::FG_RED, stdout);
-    printf("%s:%u - expected valid pointer", file, l.line());
+    print("{}:{} - expected valid pointer", file, l.line());
     puts(Terminal::RESET);
     return false;
 }

+ 5 - 4
src/Thread.cpp

@@ -17,7 +17,7 @@ void Mutex::lock() noexcept {
         debugThrow();
         mutex.lock();
     } catch(std::exception& e) {
-        Core::report(LogLevel::ERROR, "Could not lock mutex: #", e.what());
+        Core::report(LogLevel::ERROR, "Could not lock mutex: {}", e.what());
     }
 }
 
@@ -26,7 +26,7 @@ void Mutex::unlock() noexcept {
         debugThrow();
         mutex.unlock();
     } catch(std::exception& e) {
-        Core::report(LogLevel::ERROR, "Could not unlock mutex: #", e.what());
+        Core::report(LogLevel::ERROR, "Could not unlock mutex: {}", e.what());
     }
 }
 
@@ -69,7 +69,7 @@ bool Thread::start(Function f, void* p) {
         debugThrow();
         thread = std::thread([f, p]() { f(p); });
     } catch(std::exception& e) {
-        Core::report(LogLevel::ERROR, "Could not start thread: #", e.what());
+        Core::report(LogLevel::ERROR, "Could not start thread: {}", e.what());
         return true;
     }
     return false;
@@ -81,7 +81,8 @@ bool Thread::join() {
             debugThrow();
             thread.join();
         } catch(std::exception& e) {
-            Core::report(LogLevel::ERROR, "Could not join thread: #", e.what());
+            Core::report(
+                LogLevel::ERROR, "Could not join thread: {}", e.what());
             return true;
         }
     }

+ 61 - 16
src/ToString.cpp

@@ -6,14 +6,15 @@ module Core.ToString;
 
 import Core.Std;
 
-#define TO_STRING(type, format)                        \
-    size_t Core::toString(type v, char* s, size_t n) { \
-        int e = snprintf(s, n, format, v);             \
-        return e < 0 ? 0 : static_cast<size_t>(e);     \
+#define TO_STRING(type, format)                                               \
+    size_t Core::toString(type v, char* s, size_t n, const StringFormat& f) { \
+        (void)f;                                                              \
+        int e = snprintf(s, n, format, v);                                    \
+        return e < 0 ? 0 : static_cast<size_t>(e);                            \
     }
-#define TO_STRING_LINK(from, to)                       \
-    size_t Core::toString(from v, char* s, size_t n) { \
-        return toString(static_cast<to>(v), s, n);     \
+#define TO_STRING_LINK(from, to)                                              \
+    size_t Core::toString(from v, char* s, size_t n, const StringFormat& f) { \
+        return toString(static_cast<to>(v), s, n, f);                         \
     }
 
 TO_STRING(char, "%c")
@@ -27,29 +28,67 @@ TO_STRING(unsigned short, "%hu")
 TO_STRING(unsigned int, "%u")
 TO_STRING(unsigned long, "%lu")
 TO_STRING(unsigned long long, "%llu")
-TO_STRING(double, "%.2f")
+TO_STRING_LINK(float, double)
 TO_STRING(const char*, "%s")
-TO_STRING_LINK(char*, const char*)
 TO_STRING(const unsigned char*, "%s")
 TO_STRING_LINK(unsigned char*, const unsigned char*)
 
-size_t Core::toString(float v, char* s, size_t n) {
-    int e = snprintf(s, n, "%.2f", static_cast<double>(v));
+size_t Core::toString(double v, char* s, size_t n, const StringFormat& f) {
+    int e = snprintf(s, n, "%.*f", f.precision < 0 ? 2 : f.precision, v);
     return e < 0 ? 0 : static_cast<size_t>(e);
 }
 
-size_t Core::toString(bool v, char* s, size_t n) {
+size_t Core::toString(bool v, char* s, size_t n, const StringFormat& f) {
+    (void)f;
     int e = snprintf(s, n, "%s", v ? "true" : "false");
     return e < 0 ? 0 : static_cast<size_t>(e);
 }
 
-size_t Core::copyFormatUntil(const char*& format, char*& s, size_t& n) {
+static int parseFormatNumber(const char*& from, const char* to) {
+    int n = 0;
+    while(from != to && *from >= '0' && *from <= '9') {
+        n = n * 10 + (*(from++) - '0');
+    }
+    return n;
+}
+
+static void parseFormat(
+    const char* from, const char* to, Core::StringFormat& f) {
+    while(from != to) {
+        char c = *from;
+        if(c == 'l') {
+            f.alignment = Core::StringAlignment::LEFT;
+        } else if(c == 'r') {
+            f.alignment = Core::StringAlignment::RIGHT;
+        } else if((c >= '0' && c <= '9') || c == '.') {
+            break;
+        }
+        from++;
+    }
+    if(*from >= '0' && *from <= '9') {
+        f.width = parseFormatNumber(from, to);
+    }
+    if(*from == '.') {
+        from++;
+        if(*from >= '0' && *from <= '9') {
+            f.precision = parseFormatNumber(from, to);
+        }
+    }
+}
+
+size_t Core::copyFormatUntil(
+    const char*& format, char*& s, size_t& n, StringFormat& f) {
     size_t w = 0;
     while(*format != '\0') {
         char u = *(format++);
-        if(u == '#') {
-            if(*format != '#') {
-                format += *format == '@';
+        if(u == '{') {
+            if(*format != '{') {
+                const char* formatStart = format;
+                while(*format != '\0' && *format != '}') {
+                    format++;
+                }
+                parseFormat(formatStart, format, f);
+                format += *format == '}';
                 break;
             }
             format++;
@@ -65,3 +104,9 @@ size_t Core::copyFormatUntil(const char*& format, char*& s, size_t& n) {
     }
     return w;
 }
+
+void Core::StringBase::print() {
+    if(buffer != nullptr) {
+        fputs(buffer, stdout);
+    }
+}

+ 0 - 2
src/Unicode.cpp

@@ -1,5 +1,3 @@
-module;
-
 module Core.Unicode;
 
 Core::UTF8 Core::convertUnicodeToUTF8(u32 c) {

+ 9 - 13
src/Utility.cpp

@@ -1,7 +1,3 @@
-module;
-
-#include <cstdio>
-
 module Core.Utility;
 
 import Core.Logger;
@@ -9,6 +5,7 @@ import Core.Thread;
 import Core.Types;
 import Core.Std;
 import Core.New;
+import Core.ToString;
 
 static Core::ExitHandler exitHandler = nullptr;
 static void* exitData = nullptr;
@@ -19,7 +16,7 @@ static void* outOfMemoryData = nullptr;
     int value, const std::source_location& l) {
     if(value != 0) {
         const char* file = getShortFileName(l.file_name());
-        logError("Exit from #:# with value #", file, l.line(), value);
+        logError("Exit from {}:{} with value {}", file, l.line(), value);
     }
     if(exitHandler != nullptr) {
         exitHandler(value, exitData);
@@ -47,7 +44,7 @@ void Core::setOutOfMemoryHandler(OutOfMemoryHandler h, void* data) {
 
 static void* exitOnNull(void* p, size_t n) {
     if(p == nullptr) {
-        Core::logError("Out of memory, requested '#' bytes", n);
+        Core::logError("Out of memory, requested '{}' bytes", n);
         Core::exitWithHandler(1);
     }
     return p;
@@ -104,9 +101,8 @@ static void addMemoryInfo(
     i->previous = nullptr;
     i->size = n;
     i->line = l.line();
-    snprintf(
-        i->buffer, sizeof(i->buffer), "%s",
-        Core::getShortFileName(l.file_name()));
+    Core::toString(
+        Core::getShortFileName(l.file_name()), i->buffer, sizeof(i->buffer));
     memcpy(i->canary, CANARY, sizeof(CANARY));
     memcpy(reinterpret_cast<char*>(i) + n, CANARY, sizeof(CANARY));
     Core::MutexGuard mg(memoryInfoMutex);
@@ -181,12 +177,12 @@ void Core::deallocateRaw(void* p, const std::source_location& l) {
     rp->buffer[sizeof(rp->buffer) - 1] = '\0'; // end might be broken
     if(checkCanary(rp->canary)) {
         logError(
-            "Free at #:# from #:# violated pre canary",
+            "Free at {}:{} from {}:{} violated pre canary",
             getShortFileName(l.file_name()), l.line(), rp->buffer, rp->line);
         exitWithHandler(1, l);
     } else if(checkCanary(reinterpret_cast<char*>(rp) + rp->size)) {
         logError(
-            "Free at #:# from #:# violated post canary",
+            "Free at {}:{} from {}:{} violated post canary",
             getShortFileName(l.file_name()), l.line(), rp->buffer, rp->line);
         exitWithHandler(1, l);
     }
@@ -232,11 +228,11 @@ void Core::printMemoryReport() {
         if(i->line == 0) {
             counter++;
         } else {
-            logError("#:# was not freed", i->buffer, i->line);
+            logError("{}:{} was not freed", i->buffer, i->line);
         }
     }
     if(counter > 0) {
-        logError("# unknown entries were not freed", counter);
+        logError("{} unknown entries were not freed", counter);
     }
 #endif
 }

+ 4 - 2
test/Main.cpp

@@ -3,6 +3,8 @@ import Core.Logger;
 import Core.Test;
 import Core.Utility;
 import Core.Std;
+import Core.ToString;
+import Core.List;
 
 static void finalize() {
     Core::finalizeTests();
@@ -11,7 +13,7 @@ static void finalize() {
 
 static void onExit(int code, void* data) {
     unsigned int i = *static_cast<unsigned int*>(data);
-    Core::logWarning("Hello from exit #: #", code, i);
+    Core::logWarning("Hello from exit {}: {}", code, i);
     finalize();
 }
 
@@ -29,7 +31,7 @@ int main(int argAmount, const char** args) {
         puts("light;testData/readLineTest");
         return 0;
     }
-    setlocale(CORE_LC_ALL, "en_US.utf8");
+    setDefaultLocal();
     bool light = false;
     for(int i = 0; i < argAmount; i++) {
         if(strcmp(args[i], "light") == 0) {

+ 0 - 2
test/Tests.cppm

@@ -1,5 +1,3 @@
-module;
-
 export module Tests;
 
 export [[noreturn]] void testInvalidAllocate();

+ 1 - 3
test/modules/FileTests.cpp

@@ -1,5 +1,3 @@
-module;
-
 module Tests;
 
 import Core.File;
@@ -21,7 +19,7 @@ static void printReport(
     Core::LogLevel l, const std::source_location&, void*, const char* message) {
     Core::test(static_cast<int>(Core::LogLevel::ERROR), static_cast<int>(l));
     if(!Core::testTrue(strstr(message, fails[failIndex]) != nullptr)) {
-        Core::logError("'#' does not contain '#'", message, fails[failIndex]);
+        Core::logError("'{}' does not contain '{}'", message, fails[failIndex]);
     }
 }
 

+ 2 - 6
test/modules/QueueTests.cpp

@@ -1,7 +1,3 @@
-module;
-
-#include <cstdio>
-
 module Tests;
 
 import Core.Std;
@@ -9,6 +5,7 @@ import Core.Queue;
 import Core.Test;
 import Core.Types;
 import Core.Meta;
+import Core.ToString;
 
 template class Core::Queue<int, 5>;
 
@@ -42,8 +39,7 @@ struct Tester final {
     }
 
     size_t toString(char* s, size_t n) const {
-        int w = snprintf(s, n, "%d", id);
-        return w >= 0 ? static_cast<size_t>(w) : 0;
+        return Core::formatBuffer(s, n, "{}", id);
     }
 };
 

+ 5 - 8
test/modules/ReadLineTests.cpp

@@ -1,13 +1,10 @@
-module;
-
-#include <cstdio>
-
 module Tests;
 
 import Core.Clock;
 import Core.ReadLine;
 import Core.Test;
 import Core.Std;
+import Core.ToString;
 import ErrorSimulator;
 
 static void testStringError(
@@ -22,16 +19,16 @@ static void testStringError(
     }
     if(!Core::testString(s, buffer, l)) {
         const char* p = buffer;
-        printf("Invalid sequence: ");
+        Core::print("Invalid sequence: ");
         while(*p != 0) {
-            printf("%u ", static_cast<unsigned int>(*p & 0xFF));
+            Core::print("{} ", static_cast<unsigned int>(*p & 0xFF));
             p++;
         }
         putchar('\n');
         p = s;
-        printf("Correct sequence: ");
+        Core::print("Correct sequence: ");
         while(*p != 0) {
-            printf("%u ", static_cast<unsigned int>(*p & 0xFF));
+            Core::print("{} ", static_cast<unsigned int>(*p & 0xFF));
             p++;
         }
         putchar('\n');

+ 7 - 10
test/modules/TerminalTests.cpp

@@ -1,7 +1,3 @@
-module;
-
-#include <cstdio>
-
 module Tests;
 
 import Core.Std;
@@ -12,6 +8,7 @@ import Core.TerminalConstants;
 import Core.Test;
 import Core.Vector;
 import Core.Types;
+import Core.ToString;
 
 #define KEY_CASE(key)           \
     case key: puts(#key); break
@@ -61,7 +58,7 @@ void testInteractiveTerminal(void) {
     puts("Hi there");
     Core::logWarning("This is a test");
     Core::IntVector2 v = Core::getTerminalSize();
-    printf("%d %d\n", v[0], v[1]);
+    Core::print("{} {}\n", v[0], v[1]);
     Core::clearTerminal();
     Core::resetCursor();
     Core::showCursor();
@@ -79,13 +76,13 @@ void testInteractiveTerminal(void) {
         } else if(Core::isSpecialChar(c)) {
             Core::SpecialChar sc = Core::convertToSpecialChar(c);
             if(sc.shift) {
-                printf("SHIFT + ");
+                Core::print("SHIFT + ");
             }
             if(sc.control) {
-                printf("CTRL + ");
+                Core::print("CTRL + ");
             }
             if(sc.alt) {
-                printf("ALT + ");
+                Core::print("ALT + ");
             }
             switch(sc.key) {
                 KEY_CASE(Core::Terminal::KEY_ARROW_LEFT);
@@ -109,10 +106,10 @@ void testInteractiveTerminal(void) {
                 KEY_CASE(Core::Terminal::KEY_PAGE_DOWN);
                 KEY_CASE(Core::Terminal::KEY_HOME);
                 KEY_CASE(Core::Terminal::KEY_END);
-                default: printf("%lu\n", sc.key); break;
+                default: Core::print("{}\n", sc.key); break;
             }
         } else {
-            printf("%lu\n", c);
+            Core::print("{}\n", c);
         }
     }
 

+ 10 - 7
test/modules/UtilityTests.cpp

@@ -81,19 +81,22 @@ static void testSort() {
 static void testToString() {
     char buffer[512];
     Core::test(
-        10, Core::formatBuffer(buffer, sizeof(buffer), "a#a##a", 1.0, 2, 3));
+        10, Core::formatBuffer(buffer, sizeof(buffer), "a{}a#a", 1.0, 2, 3));
     Core::testString("a1.00a#a23", buffer);
-    Core::test(5, Core::formatBuffer(buffer, sizeof(buffer), "aa##ab"));
+    Core::test(5, Core::formatBuffer(buffer, sizeof(buffer), "aa#ab"));
     Core::testString("aa#ab", buffer);
+    Core::test(7, Core::formatBuffer(buffer, sizeof(buffer), "{{a}{}{{b}", 1));
+    Core::testString("{a}1{b}", buffer);
     Core::test(6, Core::formatBuffer(buffer, 3, "aaaaaa"));
     Core::testString("aa", buffer);
-    Core::test(4, Core::formatBuffer(buffer, 4, "a#", 456));
+    Core::test(4, Core::formatBuffer(buffer, 4, "a{}", 456));
     Core::testString("a45", buffer);
-    Core::test(10, Core::formatBuffer(buffer, 4, "# # #", 456, 567, 78));
+    Core::test(10, Core::formatBuffer(buffer, 4, "{} {} {}", 456, 567, 78));
     Core::testString("456", buffer);
-    Core::test(10, Core::formatBuffer(buffer, 1, "# # #", 456, 567, 78));
+    Core::test(10, Core::formatBuffer(buffer, 1, "{} {} {}", 456, 567, 78));
     Core::testString("", buffer);
-    Core::test(10, Core::formatBuffer(nullptr, 0, "# # #", 456ll, 567l, 78ull));
+    Core::test(
+        10, Core::formatBuffer(nullptr, 0, "{} {} {}", 456ll, 567l, 78ull));
 
     char c = 'a';
     short s = 4;
@@ -102,7 +105,7 @@ static void testToString() {
     signed char cs = 'x';
     Core::test(
         10, Core::formatBuffer(
-                buffer, sizeof(buffer), "# # # # #", c, s, cu, su, cs));
+                buffer, sizeof(buffer), "{} {} {} {} {}", c, s, cu, su, cs));
     Core::testString("a 4 h 67 x", buffer);
 
     unsigned char text[] = "fgsdf";

+ 1 - 3
test/modules/VectorTests.cpp

@@ -1,5 +1,3 @@
-module;
-
 module Tests;
 
 import Core.Test;
@@ -211,7 +209,7 @@ static void testCast() {
 static void testToString() {
     char buffer[200];
     formatBuffer(
-        buffer, sizeof(buffer), "# # #", Core::Vector<1, float>(),
+        buffer, sizeof(buffer), "{} {} {}", Core::Vector<1, float>(),
         Core::Vector2(2.0f, 3.0f), V3(4.0f, 5.0f, 6.0f));
     Core::testString("[0.00] [2.00, 3.00] [4.00, 5.00, 6.00]", buffer);
 }