Преглед изворни кода

string char type is template argument, char and char32_t strings

Kajetan Johannes Hammerle пре 1 година
родитељ
комит
953f95d3f2

+ 2 - 2
data/Array.h

@@ -50,8 +50,8 @@ namespace Core {
             return N;
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             return Core::toString(s, *this);
         }
     };

+ 2 - 2
data/ArrayList.h

@@ -115,8 +115,8 @@ namespace Core {
             return removeBySwap(length - 1);
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             return Core::toString(s, *this);
         }
 

+ 2 - 2
data/BitArray.h

@@ -32,8 +32,8 @@ namespace Core {
 
         void fill(int value);
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("["));
             for(int i = 0; i < length - 1; i++) {
                 CORE_RETURN_ERROR(s.append(get(i)));

+ 4 - 4
data/HashMap.h

@@ -22,8 +22,8 @@ namespace Core {
                 return key;
             }
 
-            template<int L>
-            check_return Error toString(ArrayString<L>& s) const {
+            template<typename String>
+            check_return Error toString(String& s) const {
                 CORE_RETURN_ERROR(s.append(key));
                 CORE_RETURN_ERROR(s.append(" = "));
                 return s.append(value);
@@ -261,8 +261,8 @@ namespace Core {
             return ConstEntryIterator(nodes.end());
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             return Core::toString(s, *this);
         }
 

+ 2 - 2
data/LinkedList.h

@@ -135,8 +135,8 @@ namespace Core {
             last = nullptr;
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             return Core::toString(s, *this);
         }
 

+ 2 - 2
data/List.h

@@ -181,8 +181,8 @@ namespace Core {
             return removeBySwap(length - 1);
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             return Core::toString(s, *this);
         }
 

+ 2 - 2
data/RingBuffer.h

@@ -103,8 +103,8 @@ namespace Core {
             return Error::NONE;
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("["));
             for(int i = 0; i < getLength() - 1; i++) {
                 CORE_RETURN_ERROR(s.append((*this)[i]));

+ 2 - 2
data/Stack.h

@@ -36,8 +36,8 @@ namespace Core {
                 return data[data.getLength() - 1];
             }
 
-            template<int L>
-            check_return Error toString(ArrayString<L>& s) const {
+            template<typename String>
+            check_return Error toString(String& s) const {
                 return s.append(data);
             }
         };

+ 8 - 0
io/File.cpp

@@ -0,0 +1,8 @@
+#include "io/File.h"
+
+#include <stdio.h>
+
+Core::File::File() {
+    // file = fopen("fsdf", "r");
+    // int i = fgetc(file);
+}

+ 16 - 0
io/File.h

@@ -0,0 +1,16 @@
+#ifndef CORE_FILE_H
+#define CORE_FILE_H
+
+#include "math/Vector.h"
+#include "utils/ArrayString.h"
+
+namespace Core {
+    class File final {
+        void* file;
+
+    public:
+        File();
+    };
+}
+
+#endif

+ 2 - 2
math/Box.h

@@ -22,8 +22,8 @@ namespace Core {
         const Vector3& getMin() const;
         const Vector3& getMax() const;
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("Box("));
             CORE_RETURN_ERROR(s.append(min));
             CORE_RETURN_ERROR(s.append(", "));

+ 2 - 2
math/Frustum.h

@@ -24,8 +24,8 @@ namespace Core {
         bool isInside(const Vector3& pos) const;
         bool isInside(const Vector3& pos, float radius) const;
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("(tan = "));
             CORE_RETURN_ERROR(s.append(tan));
             CORE_RETURN_ERROR(s.append(", nearClip = "));

+ 2 - 2
math/Matrix.h

@@ -37,8 +37,8 @@ namespace Core {
         Matrix& rotateZ(float degrees);
         Matrix& rotate(const Quaternion& q);
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append('['));
             CORE_RETURN_ERROR(s.append(data[0]));
             CORE_RETURN_ERROR(s.append(", "));

+ 2 - 2
math/MatrixStack.h

@@ -38,8 +38,8 @@ namespace Core {
             (void)stack.add(Matrix());
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             return s.append(stack);
         }
     };

+ 2 - 2
math/Plane.h

@@ -14,8 +14,8 @@ namespace Core {
         Plane(const Vector3& a, const Vector3& b, const Vector3& c);
         float getSignedDistance(const Vector3& v) const;
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("("));
             CORE_RETURN_ERROR(s.append(abc[0]));
             CORE_RETURN_ERROR(s.append(" x + "));

+ 2 - 2
math/Quaternion.h

@@ -18,8 +18,8 @@ namespace Core {
         Quaternion operator*(const Quaternion& other) const;
         Vector3 operator*(const Vector3& v) const;
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("("));
             CORE_RETURN_ERROR(s.append(xyz[0]));
             CORE_RETURN_ERROR(s.append(" i + "));

+ 2 - 2
math/Vector.h

@@ -169,8 +169,8 @@ namespace Core {
             return cast;
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<typename String>
+        check_return Error toString(String& s) const {
             CORE_RETURN_ERROR(s.append("["));
             for(int i = 0; i < N - 1; i++) {
                 CORE_RETURN_ERROR(s.append(values[i]));

+ 2 - 0
meson.build

@@ -17,6 +17,7 @@ src = [
     'math/Frustum.cpp',
     'math/View.cpp',
     'thread/Thread.cpp',
+    'io/File.cpp',
 ]
 
 src_tests = [
@@ -49,6 +50,7 @@ src_tests = [
     'tests/ClockTests.cpp',
     'tests/RandomTests.cpp',
     'tests/ThreadTests.cpp',
+    'tests/FileTests.cpp',
 ]
 
 compiler = meson.get_compiler('cpp')

+ 1 - 1
test/Main.cpp

@@ -31,7 +31,7 @@
 
 static void onExit(int code, void* data) {
     unsigned int i = *static_cast<unsigned int*>(data);
-    Core::ArrayString<1024> s;
+    Core::String32<1024> s;
     CORE_TEST_ERROR(s.append("Hello from exit #: #"));
     CORE_TEST_ERROR(s.format(code, i));
     CORE_TEST_ERROR(s.printLine());

+ 5 - 5
test/Test.h

@@ -11,7 +11,7 @@ namespace Core::Test {
             int tests = 0;
             int successTests = 0;
         };
-        using FileName = ArrayString<256>;
+        using FileName = String32<256>;
         extern HashMap<FileName, Result> results;
 
         template<typename T>
@@ -45,14 +45,14 @@ namespace Core::Test {
         bool checkString(const char* file, int line, const A& wanted,
                          const B& actual) {
             Error e = Error::NONE;
-            ArrayString<2048> a;
+            String32<2048> a;
             if(checkError(e, a.append(wanted))) {
-                CORE_LOG_WARNING("#", e);
+                CORE_LOG_WARNING("error at #:# | ", file, line, e);
                 return false;
             }
-            ArrayString<2048> b;
+            String32<2048> b;
             if(checkError(e, b.append(actual))) {
-                CORE_LOG_WARNING("#", e);
+                CORE_LOG_WARNING("error at #:# | ", file, line, e);
                 return false;
             }
             return checkEqual(file, line, a, b);

+ 214 - 136
tests/ArrayStringTests.cpp

@@ -4,194 +4,216 @@
 #include "test/Test.h"
 #include "utils/ArrayString.h"
 
-using String = Core::ArrayString<128>;
-
+template<typename String>
 static String build(const char* cs) {
     String s;
     CORE_TEST_ERROR(s.append(cs));
     return s;
 }
 
+template<typename String>
 static void testEquality() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_TRUE(s == "test");
-    CORE_TEST_TRUE(s == build("test"));
+    CORE_TEST_TRUE(s == build<String>("test"));
     CORE_TEST_TRUE("test" == s);
-    CORE_TEST_TRUE(build("test") == s);
+    CORE_TEST_TRUE(build<String>("test") == s);
     CORE_TEST_TRUE(s == s);
 }
 
+template<typename String>
 static void testUnicodeEquality() {
     const char* cs = "\u0040\u0400\u8000\U00100000";
-    String s = build(cs);
+    String s = build<String>(cs);
     CORE_TEST_TRUE(s == cs);
-    CORE_TEST_TRUE(s == build(cs));
+    CORE_TEST_TRUE(s == build<String>(cs));
     CORE_TEST_TRUE(cs == s);
-    CORE_TEST_TRUE(build(cs) == s);
+    CORE_TEST_TRUE(build<String>(cs) == s);
     CORE_TEST_TRUE(s == s);
 }
 
+template<typename String>
 static void testInequality() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_FALSE(s != "test");
-    CORE_TEST_FALSE(s != build("test"));
+    CORE_TEST_FALSE(s != build<String>("test"));
     CORE_TEST_FALSE("test" != s);
-    CORE_TEST_FALSE(build("test") != s);
+    CORE_TEST_FALSE(build<String>("test") != s);
     CORE_TEST_FALSE(s != s);
 }
 
+template<typename String>
 static void testStringAppend() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_ERROR(s.append("22"));
     CORE_TEST_ERROR(s.append("333"));
     CORE_TEST_ERROR(s.append("4444"));
-    CORE_TEST_EQUAL(build("test223334444"), s);
+    CORE_TEST_EQUAL(build<String>("test223334444"), s);
 }
 
+template<typename String, typename CharType>
 static void testStringAppendOverflow() {
-    Core::ArrayString<6> s;
+    Core::ArrayString<6, CharType> s;
     CORE_TEST_ERROR(s.append("te"));
     CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append("23334444"));
-    CORE_TEST_TRUE(build("te23334444") != s);
+    CORE_TEST_TRUE(build<String>("te23334444") != s);
 }
 
+template<typename String>
 static void testCharacters() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_EQUAL('t', s[0]);
     CORE_TEST_EQUAL('e', s[1]);
     CORE_TEST_EQUAL('s', s[2]);
     CORE_TEST_EQUAL('t', s[3]);
 }
 
+template<typename String>
 static void testLength() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_EQUAL(4, s.getLength());
     CORE_TEST_ERROR(s.append("aaa"));
     CORE_TEST_EQUAL(7, s.getLength());
 }
 
+template<typename String>
 static void testChar() {
-    String s = build("test");
+    String s = build<String>("test");
     for(char i = 'a'; i < 'd'; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("testabc"), s);
+    CORE_TEST_EQUAL(build<String>("testabc"), s);
 }
 
+template<typename String>
 static void testSignedChar() {
-    String s = build("test");
+    String s = build<String>("test");
     for(signed char i = 'b'; i < 'e'; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("testbcd"), s);
+    CORE_TEST_EQUAL(build<String>("testbcd"), s);
 }
 
+template<typename String>
 static void testUnsignedChar() {
-    String s = build("test");
+    String s = build<String>("test");
     for(unsigned char i = 'c'; i < 'f'; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("testcde"), s);
+    CORE_TEST_EQUAL(build<String>("testcde"), s);
 }
 
+template<typename String>
 static void testSignedShort() {
-    String s = build("test");
+    String s = build<String>("test");
     for(signed short i = 100; i < 103; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test100101102"), s);
+    CORE_TEST_EQUAL(build<String>("test100101102"), s);
 }
 
+template<typename String>
 static void testUnsignedShort() {
-    String s = build("test");
+    String s = build<String>("test");
     for(unsigned short i = 101; i < 104; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test101102103"), s);
+    CORE_TEST_EQUAL(build<String>("test101102103"), s);
 }
 
+template<typename String>
 static void testSignedInt() {
-    String s = build("test");
+    String s = build<String>("test");
     for(signed int i = 102; i < 105; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test102103104"), s);
+    CORE_TEST_EQUAL(build<String>("test102103104"), s);
 }
 
+template<typename String>
 static void testUnsignedInt() {
-    String s = build("test");
+    String s = build<String>("test");
     for(unsigned int i = 103; i < 106; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test103104105"), s);
+    CORE_TEST_EQUAL(build<String>("test103104105"), s);
 }
 
+template<typename String>
 static void testSignedLong() {
-    String s = build("test");
+    String s = build<String>("test");
     for(signed long i = 104; i < 107; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test104105106"), s);
+    CORE_TEST_EQUAL(build<String>("test104105106"), s);
 }
 
+template<typename String>
 static void testUnsignedLong() {
-    String s = build("test");
+    String s = build<String>("test");
     for(unsigned long i = 105; i < 108; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test105106107"), s);
+    CORE_TEST_EQUAL(build<String>("test105106107"), s);
 }
 
+template<typename String>
 static void testSignedLongLong() {
-    String s = build("test");
+    String s = build<String>("test");
     for(signed long long i = 106; i < 109; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test106107108"), s);
+    CORE_TEST_EQUAL(build<String>("test106107108"), s);
 }
 
+template<typename String>
 static void testUnsignedLongLong() {
-    String s = build("test");
+    String s = build<String>("test");
     for(unsigned long long i = 107; i < 110; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test107108109"), s);
+    CORE_TEST_EQUAL(build<String>("test107108109"), s);
 }
 
+template<typename String>
 static void testFloat() {
-    String s = build("test");
+    String s = build<String>("test");
     for(float i = 108; i < 111; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test108.00109.00110.00"), s);
+    CORE_TEST_EQUAL(build<String>("test108.00109.00110.00"), s);
 }
 
+template<typename String>
 static void testDouble() {
-    String s = build("test");
+    String s = build<String>("test");
     for(double i = 109; i < 112; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test109.00110.00111.00"), s);
+    CORE_TEST_EQUAL(build<String>("test109.00110.00111.00"), s);
 }
 
+template<typename String>
 static void testLongDouble() {
-    String s = build("test");
+    String s = build<String>("test");
     for(long double i = 110; i < 113; i++) {
         CORE_TEST_ERROR(s.append(i));
     }
-    CORE_TEST_EQUAL(build("test110.00111.00112.00"), s);
+    CORE_TEST_EQUAL(build<String>("test110.00111.00112.00"), s);
 }
 
+template<typename String>
 static void testBool() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_ERROR(s.append(true));
     CORE_TEST_ERROR(s.append(false));
     CORE_TEST_ERROR(s.append(true));
-    CORE_TEST_EQUAL(build("testtruefalsetrue"), s);
+    CORE_TEST_EQUAL(build<String>("testtruefalsetrue"), s);
 }
 
+template<typename String, typename CharType>
 static void testIntOverflow() {
-    Core::ArrayString<4> s;
+    Core::ArrayString<4, CharType> s;
     CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append(123456));
 
     String o;
@@ -202,24 +224,27 @@ static void testIntOverflow() {
     CORE_TEST_TRUE(o == s);
 }
 
+template<typename String>
 static void testUnicode() {
     String s;
-    CORE_TEST_ERROR(s.appendUnicode('\u0040'));
-    CORE_TEST_ERROR(s.appendUnicode(L'\u0400'));
-    CORE_TEST_ERROR(s.appendUnicode(L'\u8000'));
-    CORE_TEST_ERROR(s.appendUnicode(U'\U00100000'));
-    CORE_TEST_EQUAL(build("\u0040\u0400\u8000\U00100000"), s);
+    CORE_TEST_ERROR(s.append('\u0040'));
+    CORE_TEST_ERROR(s.append(L'\u0400'));
+    CORE_TEST_ERROR(s.append(L'\u8000'));
+    CORE_TEST_ERROR(s.append(U'\U00100000'));
+    CORE_TEST_EQUAL(build<String>("\u0040\u0400\u8000\U00100000"), s);
 }
 
+template<typename String>
 static void testClear() {
-    String s = build("test");
+    String s = build<String>("test");
     CORE_TEST_ERROR(s.append(1234));
     s.clear();
     CORE_TEST_ERROR(s.append("wusi"));
     CORE_TEST_ERROR(s.append("1234"));
-    CORE_TEST_EQUAL(build("wusi1234"), s);
+    CORE_TEST_EQUAL(build<String>("wusi1234"), s);
 }
 
+template<typename String>
 static void testHashCode() {
     String s;
     CORE_TEST_ERROR(s.append("a"));
@@ -227,29 +252,31 @@ static void testHashCode() {
     CORE_TEST_ERROR(s.append(20));
     CORE_TEST_ERROR(s.append(25.5f));
     CORE_TEST_ERROR(s.append(true));
-    CORE_TEST_EQUAL(build("abc2025.50true").hashCode(), s.hashCode());
+    CORE_TEST_EQUAL(build<String>("abc2025.50true").hashCode(), s.hashCode());
     s.clear();
     CORE_TEST_EQUAL(String().hashCode(), s.hashCode());
 }
 
+template<typename String>
 static void testAddSelf() {
     String s;
     CORE_TEST_ERROR(s.append("test1"));
     CORE_TEST_ERROR(s.append(s));
     CORE_TEST_ERROR(s.append(s));
-    CORE_TEST_EQUAL(build("test1test1test1test1"), s);
+    CORE_TEST_EQUAL(build<String>("test1test1test1test1"), s);
 }
 
+template<typename String>
 static void testAsHashMapKey() {
     Core::HashMap<String, int> map;
-    CORE_TEST_ERROR(map.add(build("wusi"), 3));
-    CORE_TEST_ERROR(map.add(build("hiThere"), 7));
-    CORE_TEST_ERROR(map.add(build("baum123"), 5));
+    CORE_TEST_ERROR(map.add(build<String>("wusi"), 3));
+    CORE_TEST_ERROR(map.add(build<String>("hiThere"), 7));
+    CORE_TEST_ERROR(map.add(build<String>("baum123"), 5));
 
-    int* a = map.search(build("wusi"));
-    int* b = map.search(build("hiThere"));
-    int* c = map.search(build("baum123"));
-    int* d = map.search(build("423hifd"));
+    int* a = map.search(build<String>("wusi"));
+    int* b = map.search(build<String>("hiThere"));
+    int* c = map.search(build<String>("baum123"));
+    int* d = map.search(build<String>("423hifd"));
 
     CORE_TEST_NOT_NULL(a);
     CORE_TEST_NOT_NULL(b);
@@ -263,6 +290,7 @@ static void testAsHashMapKey() {
     }
 }
 
+template<typename String>
 static void testStartsWith() {
     String s;
     CORE_TEST_ERROR(s.append("0123456789"));
@@ -298,6 +326,7 @@ static void testStartsWith() {
     CORE_TEST_FALSE(s.startsWidth(s7, 7));
 }
 
+template<typename String>
 static void testSearch() {
     String s;
     CORE_TEST_ERROR(s.append("0123456789"));
@@ -329,6 +358,7 @@ static void testSearch() {
     CORE_TEST_EQUAL(-1, s.search(s7, 3));
 }
 
+template<typename String>
 static void testContains() {
     String s;
     CORE_TEST_ERROR(s.append("0123456789"));
@@ -353,48 +383,75 @@ static void testContains() {
     CORE_TEST_FALSE(s.contains(s7));
 }
 
+template<typename String, typename CharType>
 static void testSearchChar() {
     String s;
     CORE_TEST_ERROR(s.append("01üää3ä"));
 
-    CORE_TEST_EQUAL(0, s.search(U'0'));
-    CORE_TEST_EQUAL(1, s.search(U'1'));
-    CORE_TEST_EQUAL(2, s.search(U'ü'));
-    CORE_TEST_EQUAL(3, s.search(U'ä'));
-    CORE_TEST_EQUAL(4, s.search(U'ä', 4));
-    CORE_TEST_EQUAL(5, s.search(U'3'));
-    CORE_TEST_EQUAL(6, s.search(U'ä', 5));
+    CORE_TEST_EQUAL(0, s.search('0'));
+    CORE_TEST_EQUAL(1, s.search('1'));
+    CORE_TEST_EQUAL((Core::IsSame<CharType, c32> ? 5 : 8), s.search('3'));
+
+    if constexpr(Core::IsSame<CharType, c32>) {
+        CORE_TEST_EQUAL(2, s.search(U'ü'));
+        CORE_TEST_EQUAL(3, s.search(U'ä'));
+        CORE_TEST_EQUAL(4, s.search(U'ä', 4));
+        CORE_TEST_EQUAL(6, s.search(U'ä', 5));
+    }
 }
 
+template<typename String, typename CharType>
 static void testContainsChar() {
     String s;
     CORE_TEST_ERROR(s.append("01üää3ä"));
 
-    CORE_TEST_TRUE(s.contains(U'0'));
-    CORE_TEST_TRUE(s.contains(U'1'));
-    CORE_TEST_TRUE(s.contains(U'ü'));
-    CORE_TEST_TRUE(s.contains(U'ä'));
-    CORE_TEST_FALSE(s.contains(U'ö'));
+    if constexpr(Core::IsSame<CharType, c32>) {
+        CORE_TEST_TRUE(s.contains(U'0'));
+        CORE_TEST_TRUE(s.contains(U'1'));
+        CORE_TEST_TRUE(s.contains(U'ü'));
+        CORE_TEST_TRUE(s.contains(U'ä'));
+        CORE_TEST_FALSE(s.contains(U'ö'));
+    } else {
+        CORE_TEST_TRUE(s.contains('0'));
+        CORE_TEST_TRUE(s.contains('1'));
+    }
 }
 
+template<typename String, typename CharType>
 static void testSubString() {
     String s;
     CORE_TEST_ERROR(s.append("01üää3ä"));
 
-    CORE_TEST_STRING("01üää3ä", s.substring(-2));
-    CORE_TEST_STRING("1üää3ä", s.substring(1));
-    CORE_TEST_STRING("üää3ä", s.substring(2));
-    CORE_TEST_STRING("ää3ä", s.substring(3));
-    CORE_TEST_STRING("ä3ä", s.substring(4));
-
-    CORE_TEST_STRING("01üää3ä", s.substring(0, 6));
-    CORE_TEST_STRING("1üää3", s.substring(1, 5));
-    CORE_TEST_STRING("üää", s.substring(2, 4));
-    CORE_TEST_STRING("ä", s.substring(3, 3));
-    CORE_TEST_STRING("", s.substring(4, 2));
-    CORE_TEST_STRING("ä3ä", s.substring(4, 23));
+    if constexpr(Core::IsSame<CharType, c32>) {
+        CORE_TEST_STRING("01üää3ä", s.substring(-2));
+        CORE_TEST_STRING("1üää3ä", s.substring(1));
+        CORE_TEST_STRING("üää3ä", s.substring(2));
+        CORE_TEST_STRING("ää3ä", s.substring(3));
+        CORE_TEST_STRING("ä3ä", s.substring(4));
+
+        CORE_TEST_STRING("01üää3ä", s.substring(0, 6));
+        CORE_TEST_STRING("1üää3", s.substring(1, 5));
+        CORE_TEST_STRING("üää", s.substring(2, 4));
+        CORE_TEST_STRING("ä", s.substring(3, 3));
+        CORE_TEST_STRING("", s.substring(4, 2));
+        CORE_TEST_STRING("ä3ä", s.substring(4, 23));
+    } else {
+        CORE_TEST_STRING("01üää3ä", s.substring(-2));
+        CORE_TEST_STRING("1üää3ä", s.substring(1));
+        CORE_TEST_STRING("üää3ä", s.substring(2));
+        CORE_TEST_STRING("ää3ä", s.substring(4));
+        CORE_TEST_STRING("ä3ä", s.substring(6));
+
+        CORE_TEST_STRING("01üää3ä", s.substring(0, 10));
+        CORE_TEST_STRING("1üää3", s.substring(1, 8));
+        CORE_TEST_STRING("üää", s.substring(2, 7));
+        CORE_TEST_STRING("ä", s.substring(4, 5));
+        CORE_TEST_STRING("", s.substring(4, 2));
+        CORE_TEST_STRING("ä3ä", s.substring(6, 23));
+    }
 }
 
+template<typename String>
 static void testReplace() {
     String s;
     CORE_TEST_ERROR(s.append("0äääää1üää3ä"));
@@ -414,60 +471,81 @@ static void testReplace() {
     CORE_TEST_EQUAL(s2.hashCode(), s.hashCode());
 }
 
+template<typename String, typename CharType>
 static void testReplaceChar() {
     String s;
-    CORE_TEST_ERROR(s.append("01üää3ä"));
-    s.replace(U'0', U'A');
-    CORE_TEST_STRING("A1üää3ä", s);
-    s.replace(U'1', U'B');
-    CORE_TEST_STRING("ABüää3ä", s);
-    s.replace(U'ü', U'C');
-    CORE_TEST_STRING("ABCää3ä", s);
-    s.replace(U'ä', U'D');
-    CORE_TEST_STRING("ABCDD3D", s);
-    s.replace(U'3', U'E');
-    CORE_TEST_STRING("ABCDDED", s);
-
+    if constexpr(Core::IsSame<CharType, c32>) {
+        CORE_TEST_ERROR(s.append("01üää3ä"));
+        s.replace(U'0', U'A');
+        CORE_TEST_STRING("A1üää3ä", s);
+        s.replace(U'1', U'B');
+        CORE_TEST_STRING("ABüää3ä", s);
+        s.replace(U'ü', U'C');
+        CORE_TEST_STRING("ABCää3ä", s);
+        s.replace(U'ä', U'D');
+        CORE_TEST_STRING("ABCDD3D", s);
+        s.replace(U'3', U'E');
+        CORE_TEST_STRING("ABCDDED", s);
+    } else {
+        CORE_TEST_ERROR(s.append("01YXX3X"));
+        s.replace('0', 'A');
+        CORE_TEST_STRING("A1YXX3X", s);
+        s.replace('1', 'B');
+        CORE_TEST_STRING("ABYXX3X", s);
+        s.replace('Y', 'C');
+        CORE_TEST_STRING("ABCXX3X", s);
+        s.replace('X', 'D');
+        CORE_TEST_STRING("ABCDD3D", s);
+        s.replace('3', 'E');
+        CORE_TEST_STRING("ABCDDED", s);
+    }
     String s2;
     CORE_TEST_ERROR(s2.append("ABCDDED"));
     CORE_TEST_EQUAL(s2.hashCode(), s.hashCode());
 }
 
+template<int N, typename CharType>
+static void typedTest() {
+    using String = Core::ArrayString<N, CharType>;
+    testEquality<String>();
+    testUnicodeEquality<String>();
+    testInequality<String>();
+    testStringAppend<String>();
+    testStringAppendOverflow<String, CharType>();
+    testCharacters<String>();
+    testLength<String>();
+    testChar<String>();
+    testSignedChar<String>();
+    testUnsignedChar<String>();
+    testSignedShort<String>();
+    testUnsignedShort<String>();
+    testSignedInt<String>();
+    testUnsignedInt<String>();
+    testSignedLong<String>();
+    testUnsignedLong<String>();
+    testSignedLongLong<String>();
+    testUnsignedLongLong<String>();
+    testFloat<String>();
+    testDouble<String>();
+    testLongDouble<String>();
+    testBool<String>();
+    testIntOverflow<String, CharType>();
+    testUnicode<String>();
+    testClear<String>();
+    testHashCode<String>();
+    testAddSelf<String>();
+    testAsHashMapKey<String>();
+    testStartsWith<String>();
+    testSearch<String>();
+    testContains<String>();
+    testSearchChar<String, CharType>();
+    testContainsChar<String, CharType>();
+    testSubString<String, CharType>();
+    testReplace<String>();
+    testReplaceChar<String, CharType>();
+}
+
 void Core::ArrayStringTests::test() {
-    testEquality();
-    testUnicodeEquality();
-    testInequality();
-    testStringAppend();
-    testStringAppendOverflow();
-    testCharacters();
-    testLength();
-    testChar();
-    testSignedChar();
-    testUnsignedChar();
-    testSignedShort();
-    testUnsignedShort();
-    testSignedInt();
-    testUnsignedInt();
-    testSignedLong();
-    testUnsignedLong();
-    testSignedLongLong();
-    testUnsignedLongLong();
-    testFloat();
-    testDouble();
-    testLongDouble();
-    testBool();
-    testIntOverflow();
-    testUnicode();
-    testClear();
-    testHashCode();
-    testAddSelf();
-    testAsHashMapKey();
-    testStartsWith();
-    testSearch();
-    testContains();
-    testSearchChar();
-    testContainsChar();
-    testSubString();
-    testReplace();
-    testReplaceChar();
+    typedTest<128, c32>();
+    typedTest<128, char>();
 }

+ 11 - 0
tests/FileTests.cpp

@@ -0,0 +1,11 @@
+#include "tests/FileTests.h"
+
+#include "io/File.h"
+#include "test/Test.h"
+
+static void testAdd() {
+}
+
+void Core::FileTests::test() {
+    testAdd();
+}

+ 8 - 0
tests/FileTests.h

@@ -0,0 +1,8 @@
+#ifndef CORE_FILE_TESTS_H
+#define CORE_FILE_TESTS_H
+
+namespace Core::FileTests {
+    void test();
+}
+
+#endif

+ 2 - 2
tests/HashMapTests.cpp

@@ -89,8 +89,8 @@ struct A final {
         return a == other.a && b == other.b;
     }
 
-    template<int N>
-    check_return Core::Error toString(Core::ArrayString<N>& s) const {
+    template<typename String>
+    check_return Core::Error toString(String& s) const {
         CORE_RETURN_ERROR(s.append("A("));
         CORE_RETURN_ERROR(s.append(a));
         CORE_RETURN_ERROR(s.append(", "));

+ 1 - 1
tests/MatrixTests.cpp

@@ -126,7 +126,7 @@ static void testRotateZ() {
 }
 
 static void testToString() {
-    Core::ArrayString<1024> s;
+    Core::String32<1024> s;
     Core::Matrix m;
     m.set(0, Core::Vector4(1.0f, 2.0f, 3.0f, 4.0f));
     m.set(1, Core::Vector4(5.0f, 6.0f, 7.0f, 8.0f));

+ 2 - 2
tests/RingBufferTests.cpp

@@ -32,8 +32,8 @@ struct Tester final {
         sum -= id;
     }
 
-    template<int L>
-    check_return Core::Error toString(Core::ArrayString<L>& s) const {
+    template<typename String>
+    check_return Core::Error toString(String& s) const {
         return s.append(id);
     }
 };

+ 2 - 2
tests/VectorTests.cpp

@@ -183,11 +183,11 @@ static void testCast() {
 }
 
 static void testToString() {
-    Core::ArrayString<200> s;
+    Core::String32<200> s;
     CORE_TEST_ERROR(s.append(Core::Vector<1, float>()));
     CORE_TEST_ERROR(s.append(Core::Vector2(2.0f, 3.0f)));
     CORE_TEST_ERROR(s.append(V3(4.0f, 5.0f, 6.0f)));
-    Core::ArrayString<200> s2;
+    Core::String32<200> s2;
     CORE_TEST_ERROR(s2.append("[0.00][2.00, 3.00][4.00, 5.00, 6.00]"));
     CORE_TEST_EQUAL(s2, s);
 }

+ 167 - 91
utils/ArrayString.h

@@ -1,17 +1,17 @@
-#ifndef CORE_STRING_H
-#define CORE_STRING_H
+#ifndef CORE_ARRAY_STRING_H
+#define CORE_ARRAY_STRING_H
 
 #include "math/Math.h"
 #include "utils/Check.h"
 #include "utils/Utility.h"
 
 namespace Core {
-    template<int N>
+    template<int N, typename CharType>
     class ArrayString final {
         int length;
         u32 hash;
         static_assert(N > 0, "size of array string must be positive");
-        u32 data[static_cast<unsigned int>(N)];
+        CharType data[static_cast<unsigned int>(N)];
 
     public:
         ArrayString() : length(0), hash(0) {
@@ -19,17 +19,26 @@ namespace Core {
         }
 
         bool operator==(const char* s) const {
-            for(int i = 0; i < length; i++) {
-                u32 u = 0;
-                if(readUnicode(u, s) != Error::NONE || data[i] != u) {
-                    return false;
+            if constexpr(IsSame<CharType, char>) {
+                for(int i = 0; i < length; i++, s++) {
+                    if(*s == '\0' && *s != data[i]) {
+                        return false;
+                    }
+                }
+                return *s == '\0';
+            } else {
+                for(int i = 0; i < length; i++) {
+                    c32 u = 0;
+                    if(readUnicode(u, s) != Error::NONE || data[i] != u) {
+                        return false;
+                    }
                 }
+                return read(s) == 0;
             }
-            return read(s) == 0;
         }
 
         template<int L>
-        bool operator==(const ArrayString<L>& other) const {
+        bool operator==(const ArrayString<L, CharType>& other) const {
             if(length != other.getLength()) {
                 return false;
             }
@@ -46,11 +55,11 @@ namespace Core {
         }
 
         template<int L>
-        bool operator!=(const ArrayString<L>& other) const {
+        bool operator!=(const ArrayString<L, CharType>& other) const {
             return !((*this) == other);
         }
 
-        u32 operator[](int index) const {
+        CharType operator[](int index) const {
             return data[index];
         }
 
@@ -59,35 +68,50 @@ namespace Core {
         }
 
         constexpr int getCapacity() const {
-            return N;
+            return N - 1;
         }
 
         check_return Error append(char c) {
-            if(c < 0) {
-                return Error::NEGATIVE_ARGUMENT;
-            }
-            return appendUnicode(static_cast<u32>(c));
+            return add(static_cast<CharType>(c));
         }
 
         check_return Error append(signed char c) {
-            if(c < 0) {
-                return Error::NEGATIVE_ARGUMENT;
-            }
-            return appendUnicode(static_cast<u32>(c));
+            return append(static_cast<char>(c));
         }
 
         check_return Error append(unsigned char c) {
-            return appendUnicode(c);
+            return append(static_cast<char>(c));
+        }
+
+        check_return Error append(wchar_t c) {
+            return append(static_cast<c32>(c));
+        }
+
+        check_return Error append(c32 c) {
+            if constexpr(IsSame<CharType, char>) {
+                char buffer[5];
+                unicodeToChar(c, buffer);
+                return append(static_cast<const char*>(buffer));
+            } else {
+                return add(c);
+            }
         }
 
         check_return Error append(const char* s) {
-            while(true) {
-                u32 u = 0;
-                CORE_RETURN_ERROR(readUnicode(u, s));
-                if(u == 0) {
-                    return Error::NONE;
+            if constexpr(IsSame<CharType, char>) {
+                while(*s != '\0') {
+                    CORE_RETURN_ERROR(append(*(s++)));
+                }
+                return Error::NONE;
+            } else {
+                while(true) {
+                    c32 u = 0;
+                    CORE_RETURN_ERROR(readUnicode(u, s));
+                    if(u == 0) {
+                        return Error::NONE;
+                    }
+                    CORE_RETURN_ERROR(append(u));
                 }
-                CORE_RETURN_ERROR(appendUnicode(u));
             }
         }
 
@@ -147,15 +171,6 @@ namespace Core {
             return b ? append("true") : append("false");
         }
 
-        check_return Error appendUnicode(u32 c) {
-            if(length >= N) {
-                return Error::CAPACITY_REACHED;
-            }
-            data[length++] = c;
-            addToHash(c);
-            return Error::NONE;
-        }
-
         check_return Error append(Error e) {
             return append(getErrorName(e));
         }
@@ -165,11 +180,15 @@ namespace Core {
             return t.toString(*this);
         }
 
-        template<int L>
-        check_return Error toString(ArrayString<L>& s) const {
+        template<int L, typename C>
+        check_return Error toString(ArrayString<L, C>& s) const {
             int l = length; // length changes if &s == this
-            for(int i = 0; i < l; i++) {
-                CORE_RETURN_ERROR(s.appendUnicode(data[i]));
+            if constexpr(IsSame<CharType, char> && !IsSame<C, char>) {
+                return s.append(data);
+            } else {
+                for(int i = 0; i < l; i++) {
+                    CORE_RETURN_ERROR(s.append(data[i]));
+                }
             }
             return Error::NONE;
         }
@@ -185,25 +204,32 @@ namespace Core {
         }
 
         check_return Error print() const {
-            for(int i = 0; i < length; i++) {
-                u32 c = data[i];
-                if(c < (1 << 7)) {
-                    CORE_RETURN_ERROR(printChar(c, 0, 0x7F, 0x0));
-                } else if(c < (1 << 11)) {
-                    CORE_RETURN_ERROR(printChar(c, 6, 0x1F, 0xC0));
-                    CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
-                } else if(c < (1 << 16)) {
-                    CORE_RETURN_ERROR(printChar(c, 12, 0x0F, 0xE0));
-                    CORE_RETURN_ERROR(printChar(c, 6, 0x3F, 0x80));
-                    CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
-                } else if(c < (1 << 21)) {
-                    CORE_RETURN_ERROR(printChar(c, 18, 0x07, 0xF0));
-                    CORE_RETURN_ERROR(printChar(c, 12, 0x3F, 0x80));
-                    CORE_RETURN_ERROR(printChar(c, 6, 0x3F, 0x80));
-                    CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
+            if constexpr(IsSame<CharType, char>) {
+                for(int i = 0; i < length; i++) {
+                    CORE_RETURN_ERROR(Core::putChar(data[i]));
+                }
+                return Error::NONE;
+            } else {
+                for(int i = 0; i < length; i++) {
+                    c32 c = data[i];
+                    if(c < (1 << 7)) {
+                        CORE_RETURN_ERROR(printChar(c, 0, 0x7F, 0x0));
+                    } else if(c < (1 << 11)) {
+                        CORE_RETURN_ERROR(printChar(c, 6, 0x1F, 0xC0));
+                        CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
+                    } else if(c < (1 << 16)) {
+                        CORE_RETURN_ERROR(printChar(c, 12, 0x0F, 0xE0));
+                        CORE_RETURN_ERROR(printChar(c, 6, 0x3F, 0x80));
+                        CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
+                    } else if(c < (1 << 21)) {
+                        CORE_RETURN_ERROR(printChar(c, 18, 0x07, 0xF0));
+                        CORE_RETURN_ERROR(printChar(c, 12, 0x3F, 0x80));
+                        CORE_RETURN_ERROR(printChar(c, 6, 0x3F, 0x80));
+                        CORE_RETURN_ERROR(printChar(c, 0, 0x3F, 0x80));
+                    }
                 }
+                return Error::NONE;
             }
-            return Error::NONE;
         }
 
         check_return Error printLine() const {
@@ -221,7 +247,8 @@ namespace Core {
         }
 
         template<int L>
-        bool startsWidth(const ArrayString<L>& other, int from = 0) const {
+        bool startsWidth(const ArrayString<L, CharType>& other,
+                         int from = 0) const {
             if(from + other.getLength() > length) {
                 return false;
             }
@@ -234,7 +261,7 @@ namespace Core {
         }
 
         template<int L>
-        int search(const ArrayString<L>& other, int from = 0) const {
+        int search(const ArrayString<L, CharType>& other, int from = 0) const {
             for(int i = from; i < length; i++) {
                 if(startsWidth(other, i)) {
                     return i;
@@ -244,11 +271,12 @@ namespace Core {
         }
 
         template<int L>
-        bool contains(const ArrayString<L>& other, int from = 0) const {
+        bool contains(const ArrayString<L, CharType>& other,
+                      int from = 0) const {
             return search(other, from) >= 0;
         }
 
-        int search(u32 u, int from = 0) const {
+        int search(CharType u, int from = 0) const {
             for(int i = from; i < length; i++) {
                 if(data[i] == u) {
                     return i;
@@ -257,16 +285,16 @@ namespace Core {
             return -1;
         }
 
-        bool contains(u32 u, int from = 0) const {
+        bool contains(CharType u, int from = 0) const {
             return search(u, from) >= 0;
         }
 
         ArrayString substring(int from, int to) const {
             from = Math::max(from, 0);
             to = Math::min(to, length - 1);
-            ArrayString<N> s;
+            ArrayString s;
             for(int i = from; i <= to; i++) {
-                (void)s.appendUnicode(data[i]);
+                (void)s.append(data[i]);
             }
             return s;
         }
@@ -276,16 +304,16 @@ namespace Core {
         }
 
         template<int L1, int L2>
-        check_return Error replace(const ArrayString<L1>& search,
-                                   const ArrayString<L2>& replace) {
-            ArrayString<N> s;
+        check_return Error replace(const ArrayString<L1, CharType>& search,
+                                   const ArrayString<L2, CharType>& replace) {
+            ArrayString<N, CharType> s;
             int i = 0;
             while(i < length) {
                 if(startsWidth(search, i)) {
                     CORE_RETURN_ERROR(s.append(replace));
                     i += search.getLength();
                 } else {
-                    CORE_RETURN_ERROR(s.appendUnicode(data[i]));
+                    CORE_RETURN_ERROR(s.append(data[i]));
                     i++;
                 }
             }
@@ -293,52 +321,94 @@ namespace Core {
             return Error::NONE;
         }
 
-        void replace(u32 search, u32 replace) {
+        void replace(CharType search, CharType replace) {
             hash = 0;
             for(int i = 0; i < length; i++) {
                 if(data[i] == search) {
                     data[i] = replace;
                 }
-                addToHash(data[i]);
+                addToHash(static_cast<c32>(data[i]));
             }
         }
 
+        operator const char*() const {
+            static_assert(IsSame<CharType, char>,
+                          "this only works for char strings");
+            return data;
+        }
+
     private:
-        check_return static Error printChar(u32 u, u32 shift, u32 a, u32 o) {
+        Error add(CharType c) {
+            if(length >= N - 1) {
+                return Error::CAPACITY_REACHED;
+            }
+            data[length++] = c;
+            data[length] = '\0';
+            addToHash(static_cast<c32>(c));
+            return Error::NONE;
+        }
+
+        template<unsigned int L>
+        void unicodeToChar(c32 c, char (&buffer)[L]) {
+            static_assert(L >= 5, "to small char buffer");
+            if(c < (1 << 7)) {
+                buffer[0] = static_cast<char>(((c >> 0) & 0x7F) | 0x0);
+                buffer[1] = '\0';
+            } else if(c < (1 << 11)) {
+                buffer[0] = static_cast<char>(((c >> 6) & 0x1F) | 0xC0);
+                buffer[1] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
+                buffer[2] = '\0';
+            } else if(c < (1 << 16)) {
+                buffer[0] = static_cast<char>(((c >> 12) & 0x0F) | 0xE0);
+                buffer[1] = static_cast<char>(((c >> 6) & 0x3F) | 0x80);
+                buffer[2] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
+                buffer[3] = '\0';
+            } else if(c < (1 << 21)) {
+                buffer[0] = static_cast<char>(((c >> 18) & 0x07) | 0xF0);
+                buffer[1] = static_cast<char>(((c >> 12) & 0x3F) | 0x80);
+                buffer[2] = static_cast<char>(((c >> 6) & 0x3F) | 0x80);
+                buffer[3] = static_cast<char>(((c >> 0) & 0x3F) | 0x80);
+                buffer[4] = '\0';
+            } else {
+                buffer[0] = '\0';
+            }
+        }
+
+        check_return static Error printChar(c32 u, u32 shift, u32 a, u32 o) {
             return Core::putChar(static_cast<int>(((u >> shift) & a) | o));
         }
 
-        static u32 read(const char*& s) {
+        static c32 read(const char*& s) {
             if(*s == '\0') {
                 return 0;
             }
-            return static_cast<u32>(*(s++));
+            return static_cast<c32>(*(s++));
         }
 
-        static Error readUnicode(u32& u, const char*& s) {
+        static Error readUnicode(c32& u, const char*& s) {
             u = read(s);
             if((u & 0x80) == 0) {
                 return Error::NONE;
             }
             if((u & 0xE0) == 0xC0) {
-                u32 u2 = read(s);
+                c32 u2 = read(s);
                 if(u2 == 0) {
                     return Error::INVALID_CHAR;
                 }
                 u = ((u & 0x1F) << 6) | (u2 & 0x3F);
                 return Error::NONE;
             } else if((u & 0xF0) == 0xE0) {
-                u32 u2 = read(s);
-                u32 u3 = read(s);
+                c32 u2 = read(s);
+                c32 u3 = read(s);
                 if(u2 == 0 || u3 == 0) {
                     return Error::INVALID_CHAR;
                 }
                 u = ((u & 0xF) << 12) | ((u2 & 0x3F) << 6) | (u3 & 0x3F);
                 return Error::NONE;
             } else if((u & 0xF8) == 0xF0) {
-                u32 u2 = read(s);
-                u32 u3 = read(s);
-                u32 u4 = read(s);
+                c32 u2 = read(s);
+                c32 u3 = read(s);
+                c32 u4 = read(s);
                 if(u2 == 0 || u3 == 0 || u4 == 0) {
                     return Error::INVALID_CHAR;
                 }
@@ -349,7 +419,7 @@ namespace Core {
             return Error::INVALID_CHAR;
         }
 
-        void addToHash(u32 u) {
+        void addToHash(c32 u) {
             hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
         }
 
@@ -357,7 +427,7 @@ namespace Core {
         check_return Error formatBuffer(ArrayString& s, int index, const T& t,
                                         Args&&... args) {
             while(index < length) {
-                u32 u = data[index++];
+                CharType u = data[index++];
                 if(u == '#') {
                     if(index >= length ||
                        (index < length && data[index] != '#')) {
@@ -365,7 +435,7 @@ namespace Core {
                     }
                     index++;
                 }
-                CORE_RETURN_ERROR(s.appendUnicode(u));
+                CORE_RETURN_ERROR(s.append(u));
             }
             CORE_RETURN_ERROR(s.append(t));
             return formatBuffer(s, index, Core::forward<Args>(args)...);
@@ -373,7 +443,7 @@ namespace Core {
 
         check_return Error formatBuffer(ArrayString& s, int index) {
             while(index < length) {
-                CORE_RETURN_ERROR(s.appendUnicode(data[index++]));
+                CORE_RETURN_ERROR(s.append(data[index++]));
             }
             return Error::NONE;
         }
@@ -386,8 +456,8 @@ namespace Core {
         }
     };
 
-    template<int L, typename Iterable>
-    check_return Error toString(ArrayString<L>& s, const Iterable& i) {
+    template<typename String, typename Iterable>
+    check_return Error toString(String& s, const Iterable& i) {
         CORE_RETURN_ERROR(s.append("["));
         auto current = i.begin();
         auto end = i.end();
@@ -400,15 +470,21 @@ namespace Core {
         }
         return s.append("]");
     }
+
+    template<int N>
+    using String8 = ArrayString<N, char>;
+
+    template<int N>
+    using String32 = ArrayString<N, char32_t>;
 }
 
-template<int N>
-bool operator==(const char* cs, const Core::ArrayString<N>& s) {
+template<int N, typename CharType>
+bool operator==(const char* cs, const Core::ArrayString<N, CharType>& s) {
     return s == cs;
 }
 
-template<int N>
-bool operator!=(const char* cs, const Core::ArrayString<N>& s) {
+template<int N, typename CharType>
+bool operator!=(const char* cs, const Core::ArrayString<N, CharType>& s) {
     return s != cs;
 }
 

+ 1 - 1
utils/Logger.h

@@ -15,7 +15,7 @@ namespace Core::Logger {
             return;
         }
         file = Core::getFileName(file);
-        Core::ArrayString<2048> s;
+        Core::String32<2048> s;
         Error e = Error::NONE;
         if(checkError(e, s.append(start)) ||
            checkError(e, s.append("#:# | ")) ||

+ 1 - 0
utils/Utility.h

@@ -184,6 +184,7 @@ using u64 = Core::Internal::SelectUnsigned<8>;
 using u32 = Core::Internal::SelectUnsigned<4>;
 using u16 = Core::Internal::SelectUnsigned<2>;
 using u8 = Core::Internal::SelectUnsigned<1>;
+using c32 = char32_t;
 
 static_assert(sizeof(i64) == 8, "invalid size");
 static_assert(sizeof(i32) == 4, "invalid size");