5 Commits 817f8eb1bf ... a8989829d7

Author SHA1 Message Date
  Kajetan Johannes Hammerle a8989829d7 Error can store multiple errors 2 weeks ago
  Kajetan Johannes Hammerle 14960267fc Reuse format functions 2 weeks ago
  Kajetan Johannes Hammerle a8f560e645 Use generic append 2 weeks ago
  Kajetan Johannes Hammerle ba27558413 Move c32 string to cpp as well 2 weeks ago
  Kajetan Johannes Hammerle 5b6904e505 Make array string more generic 2 weeks ago
72 changed files with 790 additions and 825 deletions
  1. 1 2
      CMakeLists.txt
  2. 5 5
      include/core/data/ArrayList.hpp
  3. 1 1
      include/core/data/BitArray.hpp
  4. 3 3
      include/core/data/Components.hpp
  5. 11 11
      include/core/data/HashMap.hpp
  6. 4 4
      include/core/data/LinkedList.hpp
  7. 14 14
      include/core/data/List.hpp
  8. 11 11
      include/core/data/ProbingHashMap.hpp
  9. 5 5
      include/core/data/RingBuffer.hpp
  10. 2 2
      include/core/data/Stack.hpp
  11. 2 2
      include/core/math/Box.hpp
  12. 1 1
      include/core/math/BufferedValue.hpp
  13. 2 2
      include/core/math/Frustum.hpp
  14. 1 1
      include/core/math/Math.hpp
  15. 2 2
      include/core/math/Matrix.hpp
  16. 2 2
      include/core/math/MatrixStack.hpp
  17. 2 2
      include/core/math/Plane.hpp
  18. 2 2
      include/core/math/Quaternion.hpp
  19. 1 1
      include/core/math/View.hpp
  20. 1 1
      include/core/thread/Mutex.hpp
  21. 1 1
      include/core/thread/Thread.hpp
  22. 145 489
      include/core/utils/ArrayString.hpp
  23. 3 1
      include/core/utils/Check.hpp
  24. 60 22
      include/core/utils/Error.hpp
  25. 2 1
      include/core/utils/HashCode.hpp
  26. 2 2
      include/core/utils/Logger.hpp
  27. 1 1
      include/core/utils/Meta.hpp
  28. 279 26
      src/ArrayString.cpp
  29. 4 4
      src/BitArray.cpp
  30. 2 2
      src/Buffer.cpp
  31. 7 7
      src/Clock.cpp
  32. 17 24
      src/Error.cpp
  33. 1 1
      src/ErrorSimulator.cpp
  34. 1 1
      src/ErrorSimulator.hpp
  35. 9 9
      src/FileReader.cpp
  36. 1 1
      src/Logger.cpp
  37. 1 1
      src/Math.cpp
  38. 8 7
      src/Mutex.cpp
  39. 1 1
      src/Plane.cpp
  40. 1 1
      src/Quaternion.cpp
  41. 4 4
      src/Thread.cpp
  42. 8 8
      src/Utility.cpp
  43. 1 1
      src/Vector.cpp
  44. 1 2
      test/Test.cpp
  45. 4 4
      test/Test.hpp
  46. 5 5
      test/modules/ArrayListTests.cpp
  47. 44 31
      test/modules/ArrayStringTests.cpp
  48. 1 1
      test/modules/ArrayTests.cpp
  49. 8 8
      test/modules/BitArrayTests.cpp
  50. 1 1
      test/modules/BoxTests.cpp
  51. 1 1
      test/modules/BufferTests.cpp
  52. 1 1
      test/modules/BufferedValueTests.cpp
  53. 3 2
      test/modules/ClockTests.cpp
  54. 1 1
      test/modules/ColorTests.cpp
  55. 4 4
      test/modules/ComponentsTests.cpp
  56. 29 23
      test/modules/ErrorTests.cpp
  57. 10 10
      test/modules/FileReaderTests.cpp
  58. 1 1
      test/modules/FrustumTests.cpp
  59. 6 5
      test/modules/HashMapTests.cpp
  60. 1 1
      test/modules/LinkedListTests.cpp
  61. 8 8
      test/modules/ListTests.cpp
  62. 1 1
      test/modules/MathTests.cpp
  63. 3 3
      test/modules/MatrixStackTests.cpp
  64. 1 1
      test/modules/PlaneTests.cpp
  65. 7 6
      test/modules/ProbingHashMapTests.cpp
  66. 1 1
      test/modules/RandomTests.cpp
  67. 5 5
      test/modules/RingBufferTests.cpp
  68. 2 2
      test/modules/StackTests.cpp
  69. 4 4
      test/modules/ThreadTests.cpp
  70. 3 2
      test/modules/UtilityTests.cpp
  71. 1 1
      test/modules/VectorTests.cpp
  72. 1 1
      test/modules/ViewTests.cpp

+ 1 - 2
CMakeLists.txt

@@ -175,13 +175,12 @@ target_compile_options(core PUBLIC
     -Wsign-conversion
     -Wsign-promo
     -Wstack-protector
-    -Wstrict-overflow=5
+    -Wstrict-overflow=2
     -Wsuggest-override
     -Wswitch-enum
     -Wsynth
     -Wundef
     -Wunreachable-code
-    -Wunused-macros
     -Wvla
     -Wwrite-strings
     -Wzero-as-null-pointer-constant

+ 5 - 5
include/core/data/ArrayList.hpp

@@ -65,10 +65,10 @@ namespace Core {
         template<typename... Args>
         check_return Error put(T*& t, Args&&... args) {
             if(length >= N) {
-                return Error::CAPACITY_REACHED;
+                return ErrorCode::CAPACITY_REACHED;
             }
             t = new(begin() + length++) T(Core::forward<Args>(args)...);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
@@ -98,14 +98,14 @@ namespace Core {
 
         check_return Error removeBySwap(i64 index) {
             if(index < 0 || index >= length) {
-                return Error::INVALID_INDEX;
+                return ErrorCode::INVALID_INDEX;
             }
             length--;
             if(index != length) {
                 begin()[index] = Core::move(begin()[length]);
             }
             begin()[length].~T();
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         check_return Error removeLast() {
@@ -132,4 +132,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 1 - 1
include/core/data/BitArray.hpp

@@ -50,4 +50,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 3 - 3
include/core/data/Components.hpp

@@ -63,7 +63,7 @@ namespace Core {
             i64 index = components.getLength();
             i64* indexP = nullptr;
             CORE_RETURN_ERROR(entityToIndex.tryEmplace(indexP, ent, index));
-            Error e = Error::NONE;
+            Error e = ErrorCode::NONE;
             if(checkError(e, indexToEntity.add(ent))) {
                 (void)entityToIndex.remove(ent);
                 return e;
@@ -84,7 +84,7 @@ namespace Core {
         check_return Error remove(Entity ent) {
             i64* indexP = entityToIndex.search(ent);
             if(indexP == nullptr) {
-                return Error::NOT_FOUND;
+                return ErrorCode::NOT_FOUND;
             }
             i64 lastIndex = components.getLength() - 1;
             i64 index = *indexP;
@@ -140,4 +140,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 11 - 11
include/core/data/HashMap.hpp

@@ -124,12 +124,12 @@ namespace Core {
             }
             swap(copy.nodes, nodes);
             swap(copy.nodePointers, nodePointers);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         check_return Error rehash(i64 minCapacity) {
             if(minCapacity <= nodePointers.getLength()) {
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             HashMap<K, V> map;
             i64 l = 1l << Math::roundUpLog2(Core::Math::max(minCapacity, 8l));
@@ -141,7 +141,7 @@ namespace Core {
                 }
             }
             Core::swap(map.nodePointers, nodePointers);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
@@ -150,17 +150,17 @@ namespace Core {
             i64 h = hashIndex(key);
             v = searchList(key, h);
             if(v != nullptr) {
-                return Error::EXISTING_KEY;
+                return ErrorCode::EXISTING_KEY;
             }
             NodePointer np = nullptr;
             CORE_RETURN_ERROR(nodes.put(np, key, Core::forward<Args>(args)...));
-            Error e = Error::NONE;
+            Error e = ErrorCode::NONE;
             if(checkError(e, nodePointers[h].add(np))) {
                 nodes.remove(np);
                 return e;
             }
             v = &(np->data.value);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename VA>
@@ -170,17 +170,17 @@ namespace Core {
             v = searchList(key, h);
             if(v != nullptr) {
                 *v = Core::forward<VA>(value);
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             NodePointer np = nullptr;
             CORE_RETURN_ERROR(nodes.put(np, key, Core::forward<VA>(value)));
-            Error e = Error::NONE;
+            Error e = ErrorCode::NONE;
             if(checkError(e, nodePointers[h].add(np))) {
                 nodes.remove(np);
                 return e;
             }
             v = &(np->data.value);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename VA>
@@ -197,7 +197,7 @@ namespace Core {
                     return list.removeBySwap(i);
                 }
             }
-            return Error::NOT_FOUND;
+            return ErrorCode::NOT_FOUND;
         }
 
         const V* search(const K& key) const {
@@ -280,4 +280,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 4 - 4
include/core/data/LinkedList.hpp

@@ -77,25 +77,25 @@ namespace Core {
                 CORE_RETURN_ERROR(copy.add(t));
             }
             swap(copy);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
         check_return Error put(Node*& n, Args&&... args) {
             n = new(noThrow) Node(Core::forward<Args>(args)...);
             if(n == nullptr) {
-                return Error::OUT_OF_MEMORY;
+                return ErrorCode::OUT_OF_MEMORY;
             }
             length++;
             if(first == nullptr) {
                 first = n;
                 last = n;
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             last->next = n;
             n->previous = last;
             last = n;
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>

+ 14 - 14
include/core/data/List.hpp

@@ -41,7 +41,7 @@ namespace Core {
                 copy.unsafeAdd(other[i]);
             }
             swap(copy);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         T* begin() {
@@ -62,14 +62,14 @@ namespace Core {
 
         check_return Error reserve(i64 n) {
             if(n <= capacity) {
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             return setSize(n);
         }
 
         check_return Error shrink() {
             if(length == capacity) {
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             return setSize(length);
         }
@@ -86,7 +86,7 @@ namespace Core {
                 }
                 length = n;
             }
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         check_return Error resize(i64 n) {
@@ -101,14 +101,14 @@ namespace Core {
                 }
                 length = n;
             }
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
         check_return Error put(T*& t, Args&&... args) {
             CORE_RETURN_ERROR(ensureCapacity());
             t = unsafeAdd(Core::forward<Args>(args)...);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
@@ -142,19 +142,19 @@ namespace Core {
 
         check_return Error removeBySwap(i64 index) {
             if(index < 0 || index >= length) {
-                return Error::INVALID_INDEX;
+                return ErrorCode::INVALID_INDEX;
             }
             length--;
             if(index != length) {
                 data[index] = Core::move(data[length]);
             }
             data[length].~T();
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         check_return Error remove(i64 index) {
             if(index < 0 || index >= length) {
-                return Error::INVALID_INDEX;
+                return ErrorCode::INVALID_INDEX;
             }
             length--;
             T* currentT = begin() + index;
@@ -165,7 +165,7 @@ namespace Core {
                 currentT = nextT;
             }
             endT->~T();
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         check_return Error removeLast() {
@@ -186,16 +186,16 @@ namespace Core {
     private:
         static Error allocate(T*& t, i64 n) {
             if(n <= 0) {
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             t = reinterpret_cast<T*>(new(noThrow)
                                          AlignedType<T>[static_cast<u64>(n)]);
-            return t == nullptr ? Error::OUT_OF_MEMORY : Error::NONE;
+            return t == nullptr ? ErrorCode::OUT_OF_MEMORY : ErrorCode::NONE;
         }
 
         check_return Error ensureCapacity() {
             return length < capacity
-                       ? Error::NONE
+                       ? ErrorCode::NONE
                        : reserve(capacity + Core::Math::max(4l, capacity / 4));
         }
 
@@ -213,7 +213,7 @@ namespace Core {
                 copy.unsafeAdd(Core::move(data[i]));
             }
             swap(copy);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
     };
 }

+ 11 - 11
include/core/data/ProbingHashMap.hpp

@@ -157,24 +157,24 @@ namespace Core {
                 CORE_RETURN_ERROR(copy.add(e.getKey(), e.value));
             }
             swap(copy);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         check_return Error rehash(i64 minCapacity) {
             if(minCapacity <= keys.getLength()) {
-                return Error::NONE;
+                return ErrorCode::NONE;
             }
             ProbingHashMap<K, V> map;
             i64 shifts = Math::roundUpLog2(Core::Math::max(minCapacity, 8l));
             if(shifts >= 48) {
-                return Error::CAPACITY_REACHED;
+                return ErrorCode::CAPACITY_REACHED;
             }
             i64 l = 1l << shifts;
             CORE_RETURN_ERROR(map.keys.resize(l, emptyValue<K>()));
             map.values = reinterpret_cast<V*>(
                 new(noThrow) AlignedType<V>[static_cast<u64>(l)]);
             if(map.values == nullptr) {
-                return Error::OUT_OF_MEMORY;
+                return ErrorCode::OUT_OF_MEMORY;
             }
             for(i64 i = 0; i < keys.getLength(); i++) {
                 if(keys[i] != emptyValue<K>()) {
@@ -182,29 +182,29 @@ namespace Core {
                 }
             }
             swap(map);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
         check_return Error tryEmplace(V*& v, const K& key, Args&&... args) {
             if(key == emptyValue<K>()) {
-                return Error::INVALID_ARGUMENT;
+                return ErrorCode::INVALID_ARGUMENT;
             }
             i64 index = 0;
             CORE_RETURN_ERROR(searchSlot(index, key));
             if(keys[index] == key) {
-                return Error::EXISTING_KEY;
+                return ErrorCode::EXISTING_KEY;
             }
             keys[index] = key;
             v = new(values + index) V(Core::forward<Args>(args)...);
             entries++;
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename VA>
         check_return Error put(V*& v, const K& key, VA&& value) {
             if(key == emptyValue<K>()) {
-                return Error::INVALID_ARGUMENT;
+                return ErrorCode::INVALID_ARGUMENT;
             }
             i64 index = 0;
             CORE_RETURN_ERROR(searchSlot(index, key));
@@ -216,7 +216,7 @@ namespace Core {
             }
             keys[index] = key;
             v = reinterpret_cast<V*>(values + index);
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename VA>
@@ -294,7 +294,7 @@ namespace Core {
                     i64 hash = static_cast<i64>((baseHash + i) & end);
                     if(keys[hash] == emptyValue<K>() || keys[hash] == key) {
                         slot = hash;
-                        return Core::Error::NONE;
+                        return Core::ErrorCode::NONE;
                     }
                 }
                 rehashFactor *= 2;

+ 5 - 5
include/core/data/RingBuffer.hpp

@@ -51,12 +51,12 @@ namespace Core {
         template<typename... Args>
         check_return Error put(T*& t, Args&&... args) {
             if(getLength() >= N) {
-                return Error::CAPACITY_REACHED;
+                return ErrorCode::CAPACITY_REACHED;
             }
             t = new(data + writeIndex) T(Core::forward<Args>(args)...);
             writeIndex = (writeIndex + 1) % N;
             values++;
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename... Args>
@@ -92,12 +92,12 @@ namespace Core {
 
         check_return Error remove() {
             if(!canRemove()) {
-                return Error::INVALID_STATE;
+                return ErrorCode::INVALID_STATE;
             }
             values--;
             (*this)[0].~T();
             readIndex = (readIndex + 1) % N;
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
         template<typename String>
@@ -130,4 +130,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 2 - 2
include/core/data/Stack.hpp

@@ -23,7 +23,7 @@ namespace Core {
             check_return Error pop() {
                 i64 index = data.getLength();
                 if(index <= 0) {
-                    return Error::INVALID_STATE;
+                    return ErrorCode::INVALID_STATE;
                 }
                 return data.removeBySwap(index - 1);
             }
@@ -54,4 +54,4 @@ namespace Core {
     using ArrayStack = Internal::BaseStack<T, ArrayList<T, N>>;
 }
 
-#endif
+#endif

+ 2 - 2
include/core/math/Box.hpp

@@ -29,9 +29,9 @@ namespace Core {
             CORE_RETURN_ERROR(s.append(", "));
             CORE_RETURN_ERROR(s.append(max));
             CORE_RETURN_ERROR(s.append(")"));
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
     };
 }
 
-#endif
+#endif

+ 1 - 1
include/core/math/BufferedValue.hpp

@@ -93,4 +93,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 2 - 2
include/core/math/Frustum.hpp

@@ -33,9 +33,9 @@ namespace Core {
             CORE_RETURN_ERROR(s.append(", farClip = "));
             CORE_RETURN_ERROR(s.append(farClip));
             CORE_RETURN_ERROR(s.append(')'));
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
     };
 }
 
-#endif
+#endif

+ 1 - 1
include/core/math/Math.hpp

@@ -72,4 +72,4 @@ namespace Core::Math {
     float squareRoot(float f);
 }
 
-#endif
+#endif

+ 2 - 2
include/core/math/Matrix.hpp

@@ -48,7 +48,7 @@ namespace Core {
             CORE_RETURN_ERROR(s.append(", "));
             CORE_RETURN_ERROR(s.append(data[3]));
             CORE_RETURN_ERROR(s.append("]"));
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
 
     private:
@@ -56,4 +56,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 2 - 2
include/core/math/MatrixStack.hpp

@@ -16,7 +16,7 @@ namespace Core {
 
         check_return Error pop() {
             if(stack.getLength() <= 1) {
-                return Error::INVALID_STATE;
+                return ErrorCode::INVALID_STATE;
             }
             return stack.removeLast();
         }
@@ -45,4 +45,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 2 - 2
include/core/math/Plane.hpp

@@ -25,9 +25,9 @@ namespace Core {
             CORE_RETURN_ERROR(s.append(" z + "));
             CORE_RETURN_ERROR(s.append(d));
             CORE_RETURN_ERROR(s.append(')'));
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
     };
 }
 
-#endif
+#endif

+ 2 - 2
include/core/math/Quaternion.hpp

@@ -29,9 +29,9 @@ namespace Core {
             CORE_RETURN_ERROR(s.append(" k + "));
             CORE_RETURN_ERROR(s.append(w));
             CORE_RETURN_ERROR(s.append(')'));
-            return Error::NONE;
+            return ErrorCode::NONE;
         }
     };
 }
 
-#endif
+#endif

+ 1 - 1
include/core/math/View.hpp

@@ -24,4 +24,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 1 - 1
include/core/thread/Mutex.hpp

@@ -24,4 +24,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 1 - 1
include/core/thread/Thread.hpp

@@ -26,4 +26,4 @@ namespace Core {
     };
 }
 
-#endif
+#endif

+ 145 - 489
include/core/utils/ArrayString.hpp

@@ -9,16 +9,52 @@
 #include "core/utils/Utility.hpp"
 
 namespace Core {
-    template<typename T>
-    constexpr int stringLength(const T* c) {
-        const T* i = c + 1;
-        while(*(c++) != '\0') {}
-        return static_cast<int>(c - i);
+    namespace Internal {
+        template<typename String, typename T>
+        CError genericAppend(String& s, const T& t) {
+            if constexpr(requires { t.toString(s); }) {
+                return t.toString(s);
+            } else {
+                char buffer[64];
+                CORE_RETURN_ERROR(toString(t, buffer, CORE_SIZE(buffer)));
+                return s.append(static_cast<const char*>(buffer));
+            }
+        }
+
+        template<typename S, typename T, typename... Args>
+        CError formatR(const S& f, S& s, int index, const T& t,
+                       Args&&... args) {
+            i32 l = f.getLength();
+            while(index < l) {
+                auto u = f[index++];
+                if(u == '#') {
+                    if(index >= l || f[index] != '#') {
+                        break;
+                    }
+                    index++;
+                }
+                CORE_RETURN_ERROR(s.append(u));
+            }
+            CORE_RETURN_ERROR(s.append(t));
+            if constexpr(sizeof...(args) > 0) {
+                return formatR(f, s, index, forward<Args>(args)...);
+            }
+            while(index < f.getLength()) {
+                CORE_RETURN_ERROR(s.append(f[index++]));
+            }
+            return ErrorCode::NONE;
+        }
     }
 
-    Error readUnicode(c32& u, const char*& s);
+    template<typename String, typename... Args>
+    CError copyFormat(String& result, String& s, Args&&... args) {
+        if constexpr(sizeof...(args) > 0) {
+            Error e = Internal::formatR(result, s, 0, forward<Args>(args)...);
+            return e | result.copyFrom(s);
+        }
+        return ErrorCode::NONE;
+    }
 
-    template<int N>
     class Char32String;
 
     class CharString {
@@ -32,8 +68,7 @@ namespace Core {
         CharString(char* buffer, i32 bufferSize);
         CharString(const CharString&) = delete;
         CharString& operator=(const CharString&) = delete;
-
-        check_return Error copyFrom(const CharString& s);
+        CError copyFrom(const CharString& s);
         bool operator==(const char* s) const;
         bool operator==(const CharString& other) const;
         bool operator!=(const char* s) const;
@@ -41,50 +76,32 @@ namespace Core {
         char operator[](int index) const;
         int getLength() const;
         int getCapacity() const;
-        check_return Error append(char c);
-        check_return Error append(signed char c);
-        check_return Error append(unsigned char c);
-        check_return Error append(wchar_t c);
-        check_return Error append(c32 c);
-        check_return Error append(const char* s);
-        check_return Error append(const c32* s);
-        check_return Error append(const signed char* s);
-        check_return Error append(const unsigned char* s);
-        check_return Error append(bool b);
-        check_return Error append(Error e);
+        CError append(char c);
+        CError append(signed char c);
+        CError append(unsigned char c);
+        CError append(wchar_t c);
+        CError append(c32 c);
+        CError append(const char* s);
+        CError append(const c32* s);
+        CError append(const signed char* s);
+        CError append(const unsigned char* s);
+        CError append(bool b);
 
         template<typename T>
-        check_return Error append(const T& t) {
-            if constexpr(requires { t.toString(*this); }) {
-                return t.toString(*this);
-            } else {
-                char buffer[64];
-                CORE_RETURN_ERROR(Core::toString(t, buffer, CORE_SIZE(buffer)));
-                return append(static_cast<const char*>(buffer));
-            }
-        }
-
-        check_return Error toString(CharString& s) const;
-
-        template<int L>
-        check_return Error toString(Char32String<L>& s) const {
-            return s.append(static_cast<const char*>(data));
+        CError append(const T& t) {
+            return Internal::genericAppend(*this, t);
         }
 
+        CError toString(CharString& s) const;
+        CError toString(Char32String& s) const;
         void clear();
         u32 hashCode() const;
-        check_return Error print() const;
-        check_return Error printLine() const;
+        CError print() const;
+        CError printLine() const;
 
         template<typename... Args>
-        check_return Error format(CharString& s, Args&&... args) {
-            Error e = formatBuffer(s, 0, Core::forward<Args>(args)...);
-            if(e == Error::NONE) {
-                return copyFrom(s);
-            } else if(e == Error::CAPACITY_REACHED) {
-                (void)copyFrom(s);
-            }
-            return e;
+        CError format(CharString& s, Args&&... args) {
+            return copyFormat(*this, s, Core::forward<Args>(args)...);
         }
 
         bool startsWidth(const CharString& other, int from = 0) const;
@@ -92,479 +109,120 @@ namespace Core {
         bool contains(const CharString& other, int from = 0) const;
         int search(char u, int from = 0) const;
         bool contains(char u, int from = 0) const;
-        check_return Error substring(CharString& s, int from, int to) const;
-        check_return Error substring(CharString& s, int from = 0) const;
-        check_return Error replace(CharString& s, const CharString& search,
-                                   const CharString& replace);
+        CError substring(CharString& s, int from, int to) const;
+        CError substring(CharString& s, int from = 0) const;
+        CError replace(CharString& s, const CharString& search,
+                       const CharString& replace);
         void replace(char search, char replace);
         operator const char*() const;
 
     private:
         void addToHash(c32 u);
-
-        template<typename T, typename... Args>
-        check_return Error formatBuffer(CharString& s, int index, const T& t,
-                                        Args&&... args) {
-            while(index < length) {
-                char u = data[index++];
-                if(u == '#') {
-                    if(index >= length ||
-                       (index < length && data[index] != '#')) {
-                        break;
-                    }
-                    index++;
-                }
-                CORE_RETURN_ERROR(s.append(u));
-            }
-            CORE_RETURN_ERROR(s.append(t));
-            return formatBuffer(s, index, Core::forward<Args>(args)...);
-        }
-
-        check_return Error formatBuffer(CharString& s, int index);
     };
 
-    template<int N>
-    class ArrayCharString final : public CharString {
-        static_assert(N > 0, "size of array string must be positive");
-        char data[static_cast<unsigned int>(N)];
+    class Char32String {
+    protected:
+        i32 length;
+        i32 capacity;
+        u32 hash;
+        c32* data;
 
     public:
-        ArrayCharString() : CharString(data, N) {
-        }
+        Char32String(c32* buffer, i32 bufferSize);
+        Char32String(const Char32String&) = delete;
+        Char32String& operator=(const Char32String&) = delete;
+        Error copyFrom(const Char32String& s);
+        bool operator==(const c32* s) const;
+        bool operator==(const Char32String& other) const;
+        bool operator!=(const c32* s) const;
+        bool operator!=(const Char32String& other) const;
+        c32 operator[](int index) const;
+        int getLength() const;
+        int getCapacity() const;
+        CError append(char c);
+        CError append(signed char c);
+        CError append(unsigned char c);
+        CError append(wchar_t c);
+        CError append(c32 c);
+        CError append(const char* s);
+        CError append(const c32* s);
+        CError append(const signed char* s);
+        CError append(const unsigned char* s);
+        CError append(bool b);
 
-        ArrayCharString(const ArrayCharString& other) : CharString(data, N) {
-            Core::memoryCopy(data, other.data, N);
-            length = other.length;
-            hash = other.hash;
+        template<typename T>
+        CError append(const T& t) {
+            return Internal::genericAppend(*this, t);
         }
 
-        ArrayCharString& operator=(const ArrayCharString& other) {
-            if(this != &other) {
-                Core::memoryCopy(data, other.data, N);
-                length = other.length;
-                hash = other.hash;
-            }
-            return *this;
-        }
+        CError toString(CharString& s) const;
+        CError toString(Char32String& s) const;
+        void clear();
+        u32 hashCode() const;
+        CError print() const;
+        CError printLine() const;
 
         template<typename... Args>
-        check_return Error format(Args&&... args) {
-            ArrayCharString s;
-            return CharString::format(s, Core::forward<Args>(args)...);
-        }
+        CError format(Char32String& s, Args&&... args) {
+            return copyFormat(*this, s, Core::forward<Args>(args)...);
+        }
+
+        bool startsWidth(const Char32String& other, int from = 0) const;
+        int search(const Char32String& other, int from = 0) const;
+        bool contains(const Char32String& other, int from = 0) const;
+        int search(c32 u, int from = 0) const;
+        bool contains(c32 u, int from = 0) const;
+        CError substring(Char32String& s, int from, int to) const;
+        CError substring(Char32String& s, int from = 0) const;
+        CError replace(Char32String& s, const Char32String& search,
+                       const Char32String& replace);
+        void replace(c32 search, c32 replace);
+        operator const c32*() const;
 
-        check_return Error replace(const CharString& search,
-                                   const CharString& replace) {
-            ArrayCharString s;
-            return CharString::replace(s, search, replace);
-        }
-
-        using CharString::replace;
+    private:
+        void addToHash(c32 u);
     };
 
-    template<int N>
-    class Char32String final {
-        int length;
-        u32 hash;
+    template<int N, typename C, typename B>
+    class ArrayString final : public B {
         static_assert(N > 0, "size of array string must be positive");
-        c32 data[static_cast<unsigned int>(N)];
+        C data[static_cast<unsigned int>(N)];
 
     public:
-        Char32String() : length(0), hash(0) {
-            data[0] = '\0';
-        }
-
-        bool operator==(const c32* s) const {
-            const c32* p = data;
-            while(*s == *p && *s != '\0') {
-                s++;
-                p++;
-            }
-            return *s == *p;
-        }
-
-        template<int L>
-        bool operator==(const Char32String<L>& other) const {
-            if(length != other.getLength()) {
-                return false;
-            }
-            for(int i = 0; i < length; i++) {
-                if(data[i] != other[i]) {
-                    return false;
-                }
-            }
-            return true;
-        }
-
-        bool operator!=(const c32* s) const {
-            return !((*this) == s);
-        }
-
-        template<int L>
-        bool operator!=(const Char32String<L>& other) const {
-            return !((*this) == other);
-        }
-
-        c32 operator[](int index) const {
-            return data[index];
-        }
-
-        int getLength() const {
-            return length;
-        }
-
-        constexpr int getCapacity() const {
-            return N - 1;
-        }
-
-        check_return Error append(char c) {
-            return add(static_cast<c32>(c));
-        }
-
-        check_return Error append(signed char c) {
-            return append(static_cast<char>(c));
-        }
-
-        check_return Error append(unsigned char 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<c32, 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) {
-                c32 u = 0;
-                CORE_RETURN_ERROR(readUnicode(u, s));
-                if(u == 0) {
-                    return Error::NONE;
-                }
-                CORE_RETURN_ERROR(append(u));
-            }
-        }
-
-        check_return Error append(const c32* s) {
-            // stringLength as s could be some part of data
-            for(int i = stringLength(s); i > 0; i--) {
-                CORE_RETURN_ERROR(append(*(s++)));
-            }
-            return Error::NONE;
-        }
-
-        check_return Error append(const signed char* s) {
-            return append(reinterpret_cast<const char*>(s));
-        }
-
-        check_return Error append(const unsigned char* s) {
-            return append(reinterpret_cast<const char*>(s));
+        ArrayString() : B(data, N) {
         }
 
-        check_return Error append(signed short s) {
-            return convertAppend(s);
+        ArrayString(const ArrayString& other) : B(data, N) {
+            Core::memoryCopy(data, other.data, sizeof(data));
+            B::length = other.length;
+            B::hash = other.hash;
         }
 
-        check_return Error append(unsigned short s) {
-            return convertAppend(s);
-        }
-
-        check_return Error append(signed int i) {
-            return convertAppend(i);
-        }
-
-        check_return Error append(unsigned int i) {
-            return convertAppend(i);
-        }
-
-        check_return Error append(signed long l) {
-            return convertAppend(l);
-        }
-
-        check_return Error append(unsigned long l) {
-            return convertAppend(l);
-        }
-
-        check_return Error append(signed long long ll) {
-            return convertAppend(ll);
-        }
-
-        check_return Error append(unsigned long long ll) {
-            return convertAppend(ll);
-        }
-
-        check_return Error append(float f) {
-            return convertAppend(f);
-        }
-
-        check_return Error append(double d) {
-            return convertAppend(d);
-        }
-
-        check_return Error append(long double ld) {
-            return convertAppend(ld);
-        }
-
-        check_return Error append(bool b) {
-            return b ? append("true") : append("false");
-        }
-
-        check_return Error append(Error e) {
-            return append(getErrorName(e));
-        }
-
-        template<typename T>
-        check_return Error append(const T& t) {
-            return t.toString(*this);
-        }
-
-        check_return Error toString(CharString& s) const {
-            int l = length; // length changes if &s == this
-            for(int i = 0; i < l; i++) {
-                CORE_RETURN_ERROR(s.append(data[i]));
-            }
-            return Error::NONE;
-        }
-
-        template<int L>
-        check_return Error toString(Char32String<L>& s) const {
-            int l = length; // length changes if &s == this
-            for(int i = 0; i < l; i++) {
-                CORE_RETURN_ERROR(s.append(data[i]));
-            }
-            return Error::NONE;
-        }
-
-        void clear() {
-            length = 0;
-            hash = 0;
-            data[0] = '\0';
-        }
-
-        u32 hashCode() const {
-            return hash;
-        }
-
-        check_return Error print() const {
-            if constexpr(IsSame<c32, 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;
+        ArrayString& operator=(const ArrayString& other) {
+            if(this != &other) {
+                Core::memoryCopy(data, other.data, sizeof(data));
+                B::length = other.length;
+                B::hash = other.hash;
             }
-        }
-
-        check_return Error printLine() const {
-            CORE_RETURN_ERROR(print());
-            CORE_RETURN_ERROR(Core::putChar('\n'));
-            return Error::NONE;
+            return *this;
         }
 
         template<typename... Args>
-        check_return Error format(Args&&... args) {
-            Char32String s;
-            Error e = formatBuffer(s, 0, Core::forward<Args>(args)...);
-            if(e == Error::NONE || e == Error::CAPACITY_REACHED) {
-                *this = s;
-            }
-            return e;
-        }
-
-        template<int L>
-        bool startsWidth(const Char32String<L>& other, int from = 0) const {
-            if(from > length - other.getLength()) {
-                return false;
-            }
-            for(int i = 0; i < other.getLength(); i++) {
-                if(data[from + i] != other[i]) {
-                    return false;
-                }
-            }
-            return true;
+        CError format(Args&&... args) {
+            ArrayString s;
+            return B::format(s, Core::forward<Args>(args)...);
         }
 
-        template<int L>
-        int search(const Char32String<L>& other, int from = 0) const {
-            for(int i = from; i < length; i++) {
-                if(startsWidth(other, i)) {
-                    return i;
-                }
-            }
-            return -1;
-        }
-
-        template<int L>
-        bool contains(const Char32String<L>& other, int from = 0) const {
-            return search(other, from) >= 0;
-        }
-
-        int search(c32 u, int from = 0) const {
-            for(int i = from; i < length; i++) {
-                if(data[i] == u) {
-                    return i;
-                }
-            }
-            return -1;
-        }
-
-        bool contains(c32 u, int from = 0) const {
-            return search(u, from) >= 0;
-        }
-
-        Char32String substring(int from, int to) const {
-            from = Math::max(from, 0);
-            to = Math::min(to, length - 1);
-            Char32String s;
-            for(int i = from; i <= to; i++) {
-                (void)s.append(data[i]);
-            }
-            return s;
+        CError replace(const B& search, const B& replace) {
+            ArrayString s;
+            return B::replace(s, search, replace);
         }
 
-        Char32String substring(int from = 0) const {
-            return substring(from, length - 1);
-        }
-
-        template<int L1, int L2>
-        check_return Error replace(const Char32String<L1>& search,
-                                   const Char32String<L2>& replace) {
-            Char32String<N> 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.append(data[i]));
-                    i++;
-                }
-            }
-            *this = s;
-            return Error::NONE;
-        }
-
-        void replace(c32 search, c32 replace) {
-            hash = 0;
-            for(int i = 0; i < length; i++) {
-                if(data[i] == search) {
-                    data[i] = replace;
-                }
-                addToHash(static_cast<c32>(data[i]));
-            }
-        }
-
-        operator const c32*() const {
-            return data;
-        }
-
-    private:
-        Error add(c32 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");
-            buffer[0] = '\0';
-            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';
-            }
-        }
-
-        check_return static Error printChar(c32 u, u32 shift, u32 a, u32 o) {
-            return Core::putChar(static_cast<int>(((u >> shift) & a) | o));
-        }
-
-        void addToHash(c32 u) {
-            hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
-        }
-
-        template<typename T, typename... Args>
-        check_return Error formatBuffer(Char32String& s, int index, const T& t,
-                                        Args&&... args) {
-            while(index < length) {
-                c32 u = data[index++];
-                if(u == '#') {
-                    if(index >= length ||
-                       (index < length && data[index] != '#')) {
-                        break;
-                    }
-                    index++;
-                }
-                CORE_RETURN_ERROR(s.append(u));
-            }
-            CORE_RETURN_ERROR(s.append(t));
-            return formatBuffer(s, index, Core::forward<Args>(args)...);
-        }
-
-        check_return Error formatBuffer(Char32String& s, int index) {
-            while(index < length) {
-                CORE_RETURN_ERROR(s.append(data[index++]));
-            }
-            return Error::NONE;
-        }
-
-        template<typename T>
-        check_return Error convertAppend(T t) {
-            char buffer[64];
-            CORE_RETURN_ERROR(Core::toString(t, buffer, CORE_SIZE(buffer)));
-            return append(static_cast<const char*>(buffer));
-        }
+        using B::replace;
     };
 
     template<typename String, typename Iterable>
-    check_return Error toString(String& s, const Iterable& i) {
+    CError toString(String& s, const Iterable& i) {
         CORE_RETURN_ERROR(s.append("["));
         auto current = i.begin();
         auto end = i.end();
@@ -579,19 +237,17 @@ namespace Core {
     }
 
     template<int N>
-    using String8 = ArrayCharString<N>;
+    using String8 = ArrayString<N, char, CharString>;
 
     template<int N>
-    using String32 = Char32String<N>;
+    using String32 = ArrayString<N, c32, Char32String>;
 }
 
-template<int N>
-bool operator==(const c32* cs, const Core::Char32String<N>& s) {
+inline bool operator==(const c32* cs, const Core::Char32String& s) {
     return s == cs;
 }
 
-template<int N>
-bool operator!=(const c32* cs, const Core::Char32String<N>& s) {
+inline bool operator!=(const c32* cs, const Core::Char32String& s) {
     return s != cs;
 }
 

+ 3 - 1
include/core/utils/Check.hpp

@@ -18,4 +18,6 @@
 #error "please add a 'check_format' option"
 #endif
 
-#endif
+#define CError check_return Core::Error
+
+#endif

+ 60 - 22
include/core/utils/Error.hpp

@@ -1,39 +1,77 @@
 #ifndef CORE_ERROR_HPP
 #define CORE_ERROR_HPP
 
+#include "core/utils/Check.hpp"
+
 namespace Core {
-    enum class Error {
-        NONE = 0,
-        NEGATIVE_ARGUMENT,
-        CAPACITY_REACHED,
-        BLOCKED_STDOUT,
-        OUT_OF_MEMORY,
-        INVALID_CHAR,
-        NOT_FOUND,
-        INVALID_STATE,
-        INVALID_INDEX,
-        INVALID_ARGUMENT,
-        TIME_NOT_AVAILABLE,
-        SLEEP_INTERRUPTED,
-        THREAD_ERROR,
-        MUTEX_ERROR,
-        EXISTING_KEY,
-        CANNOT_OPEN_FILE,
-        END_OF_FILE
+    struct Error {
+        using Code = unsigned int;
+        static_assert(sizeof(Code) >= 4, "error code too small");
+        Code code;
+
+        constexpr Error(Code c) : code(c) {
+        }
+
+        bool check() const {
+            return code != 0;
+        }
+
+        bool contains(Error e) const {
+            return code & e.code;
+        }
+
+        bool operator==(Error e) const {
+            return code == e.code;
+        }
+
+        bool operator!=(Error e) const {
+            return !(*this == e);
+        }
+
+        Error& operator|=(Error e) {
+            code |= e.code;
+            return *this;
+        }
+
+        Error operator|(Error e) const {
+            e |= *this;
+            return e;
+        }
     };
-    const char* getErrorName(Error e);
+
+    namespace ErrorCode {
+        static constexpr Error NONE = 0;
+        static constexpr Error NEGATIVE_ARGUMENT = 1 << 0;
+        static constexpr Error CAPACITY_REACHED = 1 << 1;
+        static constexpr Error BLOCKED_STDOUT = 1 << 2;
+        static constexpr Error OUT_OF_MEMORY = 1 << 3;
+        static constexpr Error INVALID_CHAR = 1 << 4;
+        static constexpr Error NOT_FOUND = 1 << 5;
+        static constexpr Error INVALID_STATE = 1 << 6;
+        static constexpr Error INVALID_INDEX = 1 << 7;
+        static constexpr Error INVALID_ARGUMENT = 1 << 8;
+        static constexpr Error TIME_NOT_AVAILABLE = 1 << 9;
+        static constexpr Error SLEEP_INTERRUPTED = 1 << 10;
+        static constexpr Error THREAD_ERROR = 1 << 11;
+        static constexpr Error MUTEX_ERROR = 1 << 12;
+        static constexpr Error EXISTING_KEY = 1 << 13;
+        static constexpr Error CANNOT_OPEN_FILE = 1 << 14;
+        static constexpr Error END_OF_FILE = 1 << 15;
+    }
+
+    CError toString(Error e, char* buffer, int size);
 
     inline bool checkError(Error& storage, Error e) {
-        return (storage = e) != Error::NONE;
+        return (storage = e).check();
     }
 
 #define CORE_RETURN_ERROR(checked)                                             \
     {                                                                          \
-        Core::Error error = Core::Error::NONE;                                 \
+        Core::Error error = Core::ErrorCode::NONE;                             \
         if(checkError(error, checked)) [[unlikely]] {                          \
             return error;                                                      \
         }                                                                      \
     }
 }
 
-#endif
+#endif

+ 2 - 1
include/core/utils/HashCode.hpp

@@ -3,6 +3,7 @@
 
 #include <limits.h>
 
+#include "core/utils/Meta.hpp"
 #include "core/utils/Types.hpp"
 
 namespace Core {
@@ -91,4 +92,4 @@ namespace Core {
     }
 }
 
-#endif
+#endif

+ 2 - 2
include/core/utils/Logger.hpp

@@ -16,7 +16,7 @@ namespace Core::Logger {
     const char* getFileName(const char* path);
 
     inline bool filterError(Error e) {
-        return e != Error::NONE && e != Error::CAPACITY_REACHED;
+        return e != ErrorCode::NONE && e != ErrorCode::CAPACITY_REACHED;
     }
 
     // aborts on critical logging failure
@@ -84,4 +84,4 @@ namespace Core::Logger {
 #define CORE_LOG_DEBUG(format, ...)
 #endif
 
-#endif
+#endif

+ 1 - 1
include/core/utils/Meta.hpp

@@ -84,4 +84,4 @@ namespace Core {
     }
 }
 
-#endif
+#endif

+ 279 - 26
src/ArrayString.cpp

@@ -3,7 +3,16 @@
 #include "core/utils/Error.hpp"
 
 using CharString = Core::CharString;
+using Char32String = Core::Char32String;
 using Error = Core::Error;
+namespace ErrorCode = Core::ErrorCode;
+
+template<typename T>
+constexpr int stringLength(const T* c) {
+    const T* i = c + 1;
+    while(*(c++) != '\0') {}
+    return static_cast<int>(c - i);
+}
 
 static c32 read(const char*& s) {
     if(*s == '\0') {
@@ -12,42 +21,42 @@ static c32 read(const char*& s) {
     return static_cast<c32>(*(s++));
 }
 
-Error Core::readUnicode(c32& u, const char*& s) {
+static Error readUnicode(c32& u, const char*& s) {
     u = read(s);
     if((u & 0x80) == 0) {
-        return Error::NONE;
+        return ErrorCode::NONE;
     }
     if((u & 0xE0) == 0xC0) {
         c32 u2 = read(s);
         if(u2 == 0) {
-            return Error::INVALID_CHAR;
+            return ErrorCode::INVALID_CHAR;
         }
         u = ((u & 0x1F) << 6) | (u2 & 0x3F);
-        return Error::NONE;
+        return ErrorCode::NONE;
     } else if((u & 0xF0) == 0xE0) {
         c32 u2 = read(s);
         c32 u3 = read(s);
         if(u2 == 0 || u3 == 0) {
-            return Error::INVALID_CHAR;
+            return ErrorCode::INVALID_CHAR;
         }
         u = ((u & 0xF) << 12) | ((u2 & 0x3F) << 6) | (u3 & 0x3F);
-        return Error::NONE;
+        return ErrorCode::NONE;
     } else if((u & 0xF8) == 0xF0) {
         c32 u2 = read(s);
         c32 u3 = read(s);
         c32 u4 = read(s);
         if(u2 == 0 || u3 == 0 || u4 == 0) {
-            return Error::INVALID_CHAR;
+            return ErrorCode::INVALID_CHAR;
         }
         u = ((u & 0x07) << 18) | ((u2 & 0x3F) << 12) | ((u3 & 0x3F) << 6) |
             (u4 & 0x3F);
-        return Error::NONE;
+        return ErrorCode::NONE;
     }
-    return Error::INVALID_CHAR;
+    return ErrorCode::INVALID_CHAR;
 }
 
 template<unsigned int L>
-void unicodeToChar(c32 c, char (&buffer)[L]) {
+static void unicodeToChar(c32 c, char (&buffer)[L]) {
     static_assert(L >= 5, "to small char buffer");
     buffer[0] = '\0';
     if(c < (1 << 7)) {
@@ -71,6 +80,10 @@ void unicodeToChar(c32 c, char (&buffer)[L]) {
     }
 }
 
+static Error printChar(c32 u, u32 shift, u32 a, u32 o) {
+    return Core::putChar(static_cast<int>(((u >> shift) & a) | o));
+}
+
 CharString::CharString(char* buffer, i32 bufferSize)
     : length(0), capacity(bufferSize), hash(0), data(buffer) {
     data[0] = '\0';
@@ -124,12 +137,12 @@ int CharString::getCapacity() const {
 
 Error CharString::append(char c) {
     if(length >= capacity - 1) {
-        return Error::CAPACITY_REACHED;
+        return ErrorCode::CAPACITY_REACHED;
     }
     data[length++] = c;
     data[length] = '\0';
     addToHash(static_cast<c32>(c));
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Error CharString::append(signed char c) {
@@ -155,7 +168,7 @@ Error CharString::append(const char* s) {
     for(int i = stringLength(s); i > 0; i--) {
         CORE_RETURN_ERROR(append(*(s++)));
     }
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Error CharString::append(const c32* s) {
@@ -163,7 +176,7 @@ Error CharString::append(const c32* s) {
     for(int i = stringLength(s); i > 0; i--) {
         CORE_RETURN_ERROR(append(*(s++)));
     }
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Error CharString::append(const signed char* s) {
@@ -178,16 +191,16 @@ Error CharString::append(bool b) {
     return b ? append("true") : append("false");
 }
 
-Error CharString::append(Error e) {
-    return append(getErrorName(e));
-}
-
 Error CharString::toString(CharString& s) const {
     int l = length; // length changes if &s == this
     for(int i = 0; i < l; i++) {
         CORE_RETURN_ERROR(s.append(data[i]));
     }
-    return Error::NONE;
+    return ErrorCode::NONE;
+}
+
+Error CharString::toString(Char32String& s) const {
+    return s.append(static_cast<const char*>(data));
 }
 
 void CharString::clear() {
@@ -204,13 +217,13 @@ Error CharString::print() const {
     for(int i = 0; i < length; i++) {
         CORE_RETURN_ERROR(Core::putChar(data[i]));
     }
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Error CharString::printLine() const {
     CORE_RETURN_ERROR(print());
     CORE_RETURN_ERROR(Core::putChar('\n'));
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 bool CharString::startsWidth(const CharString& other, int from) const {
@@ -258,7 +271,7 @@ Error CharString::substring(CharString& s, int from, int to) const {
     for(int i = from; i <= to; i++) {
         CORE_RETURN_ERROR(s.append(data[i]));
     }
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Error CharString::substring(CharString& s, int from) const {
@@ -298,9 +311,249 @@ void CharString::addToHash(c32 u) {
     hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
 }
 
-Error CharString::formatBuffer(CharString& s, int index) {
-    while(index < length) {
-        CORE_RETURN_ERROR(s.append(data[index++]));
+Char32String::Char32String(c32* buffer, i32 bufferSize)
+    : length(0), capacity(bufferSize), hash(0), data(buffer) {
+    data[0] = '\0';
+}
+
+Error Char32String::copyFrom(const Char32String& s) {
+    clear();
+    return s.toString(*this);
+}
+
+bool Char32String::operator==(const c32* s) const {
+    const c32* p = data;
+    while(*s == *p && *s != '\0') {
+        s++;
+        p++;
     }
-    return Error::NONE;
+    return *s == *p;
+}
+
+bool Char32String::operator==(const Char32String& other) const {
+    if(length != other.getLength()) {
+        return false;
+    }
+    for(int i = 0; i < length; i++) {
+        if(data[i] != other[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool Char32String::operator!=(const c32* s) const {
+    return !((*this) == s);
+}
+
+bool Char32String::operator!=(const Char32String& other) const {
+    return !((*this) == other);
+}
+
+c32 Char32String::operator[](int index) const {
+    return data[index];
+}
+
+int Char32String::getLength() const {
+    return length;
+}
+
+int Char32String::getCapacity() const {
+    return capacity - 1;
+}
+
+Error Char32String::append(char c) {
+    return append(static_cast<c32>(c));
+}
+
+Error Char32String::append(signed char c) {
+    return append(static_cast<char>(c));
+}
+
+Error Char32String::append(unsigned char c) {
+    return append(static_cast<char>(c));
+}
+
+Error Char32String::append(wchar_t c) {
+    return append(static_cast<c32>(c));
+}
+
+Error Char32String::append(c32 c) {
+    if(length >= capacity - 1) {
+        return ErrorCode::CAPACITY_REACHED;
+    }
+    data[length++] = c;
+    data[length] = '\0';
+    addToHash(static_cast<c32>(c));
+    return ErrorCode::NONE;
+}
+
+Error Char32String::append(const char* s) {
+    while(true) {
+        c32 u = 0;
+        CORE_RETURN_ERROR(readUnicode(u, s));
+        if(u == 0) {
+            return ErrorCode::NONE;
+        }
+        CORE_RETURN_ERROR(append(u));
+    }
+}
+
+Error Char32String::append(const c32* s) {
+    // stringLength as s could be some part of data
+    for(int i = stringLength(s); i > 0; i--) {
+        CORE_RETURN_ERROR(append(*(s++)));
+    }
+    return ErrorCode::NONE;
+}
+
+Error Char32String::append(const signed char* s) {
+    return append(reinterpret_cast<const char*>(s));
+}
+
+Error Char32String::append(const unsigned char* s) {
+    return append(reinterpret_cast<const char*>(s));
+}
+
+Error Char32String::append(bool b) {
+    return b ? append("true") : append("false");
+}
+
+Error Char32String::toString(CharString& s) const {
+    int l = length; // length changes if &s == this
+    for(int i = 0; i < l; i++) {
+        CORE_RETURN_ERROR(s.append(data[i]));
+    }
+    return ErrorCode::NONE;
+}
+
+Error Char32String::toString(Char32String& s) const {
+    int l = length; // length changes if &s == this
+    for(int i = 0; i < l; i++) {
+        CORE_RETURN_ERROR(s.append(data[i]));
+    }
+    return ErrorCode::NONE;
+}
+
+void Char32String::clear() {
+    length = 0;
+    hash = 0;
+    data[0] = '\0';
+}
+
+u32 Char32String::hashCode() const {
+    return hash;
+}
+
+Error Char32String::print() const {
+    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 ErrorCode::NONE;
+}
+
+Error Char32String::printLine() const {
+    CORE_RETURN_ERROR(print());
+    CORE_RETURN_ERROR(Core::putChar('\n'));
+    return ErrorCode::NONE;
+}
+
+bool Char32String::startsWidth(const Char32String& other, int from) const {
+    if(from > length - other.getLength()) {
+        return false;
+    }
+    for(int i = 0; i < other.getLength(); i++) {
+        if(data[from + i] != other[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+int Char32String::search(const Char32String& other, int from) const {
+    for(int i = from; i < length; i++) {
+        if(startsWidth(other, i)) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+bool Char32String::contains(const Char32String& other, int from) const {
+    return search(other, from) >= 0;
+}
+
+int Char32String::search(c32 u, int from) const {
+    for(int i = from; i < length; i++) {
+        if(data[i] == u) {
+            return i;
+        }
+    }
+    return -1;
+}
+
+bool Char32String::contains(c32 u, int from) const {
+    return search(u, from) >= 0;
+}
+
+Error Char32String::substring(Char32String& s, int from, int to) const {
+    s.clear();
+    from = Math::max(from, 0);
+    to = Math::min(to, length - 1);
+    for(int i = from; i <= to; i++) {
+        CORE_RETURN_ERROR(s.append(data[i]));
+    }
+    return ErrorCode::NONE;
+}
+
+Error Char32String::substring(Char32String& s, int from) const {
+    return substring(s, from, length - 1);
+}
+
+Error Char32String::replace(Char32String& s, const Char32String& search,
+                            const Char32String& replace) {
+    int i = 0;
+    while(i < length) {
+        if(startsWidth(search, i)) {
+            CORE_RETURN_ERROR(s.append(replace));
+            i += search.getLength();
+        } else {
+            CORE_RETURN_ERROR(s.append(data[i]));
+            i++;
+        }
+    }
+    return copyFrom(s);
+}
+
+void Char32String::replace(c32 search, c32 replace) {
+    hash = 0;
+    for(int i = 0; i < length; i++) {
+        if(data[i] == search) {
+            data[i] = replace;
+        }
+        addToHash(static_cast<c32>(data[i]));
+    }
+}
+
+Char32String::operator const c32*() const {
+    return data;
+}
+
+void Char32String::addToHash(c32 u) {
+    hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
 }

+ 4 - 4
src/BitArray.cpp

@@ -57,7 +57,7 @@ check_return Core::Error Core::BitArray::copyFrom(const BitArray& other) {
     for(u64 i = 0; i < length; i++) {
         set(i, other.get(i));
     }
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Core::BitArray::BitArray(BitArray&& other) : BitArray() {
@@ -136,12 +136,12 @@ void Core::BitArray::fill(u64 value) {
 
 check_return Core::Error Core::BitArray::resize(u64 newLength, u64 newBits) {
     if(newLength == 0 || newBits == 0 || newBits > 64) {
-        return Error::INVALID_ARGUMENT;
+        return ErrorCode::INVALID_ARGUMENT;
     }
     u64 arrayLength = getArrayLength(newLength, newBits);
     u64* newData = new(noThrow) u64[arrayLength];
     if(newData == nullptr) {
-        return Error::OUT_OF_MEMORY;
+        return ErrorCode::OUT_OF_MEMORY;
     }
     Core::memorySet(newData, 0, static_cast<i64>(arrayLength) * CORE_SIZE(int));
 
@@ -155,7 +155,7 @@ check_return Core::Error Core::BitArray::resize(u64 newLength, u64 newBits) {
     delete[] data;
     data = newData;
     lengthBits = newLength | (newBits << LENGTH_BITS);
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 void Core::BitArray::swap(BitArray& other) {

+ 2 - 2
src/Buffer.cpp

@@ -34,7 +34,7 @@ Core::Error Core::Buffer::add(const void* data, int size) {
     }
     memoryCopy(buffer + length, data, size);
     length += size;
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 int Core::Buffer::getLength() const {
@@ -57,4 +57,4 @@ void Core::Buffer::swap(Buffer& other) {
 
 void Core::Buffer::clear() {
     length = 0;
-}
+}

+ 7 - 7
src/Clock.cpp

@@ -14,7 +14,7 @@ Core::Error Core::Clock::update(Clock::Nanos& n) {
     if(last == 0) {
         last = current;
         n = 0;
-        return Error::NONE;
+        return ErrorCode::NONE;
     }
     index = (index + 1) & (time.getLength() - 1);
     sum -= time[index];
@@ -22,7 +22,7 @@ Core::Error Core::Clock::update(Clock::Nanos& n) {
     sum += time[index];
     last = current;
     n = time[index];
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 float Core::Clock::getUpdatesPerSecond() const {
@@ -32,17 +32,17 @@ float Core::Clock::getUpdatesPerSecond() const {
 Core::Error Core::Clock::getNanos(Clock::Nanos& n) {
     timespec ts;
     if(timespec_get(&ts, TIME_UTC) == 0 || CORE_TIME_GET_FAIL) {
-        return Error::TIME_NOT_AVAILABLE;
+        return ErrorCode::TIME_NOT_AVAILABLE;
     }
     n = static_cast<Clock::Nanos>(ts.tv_sec) * 1'000'000'000L +
         static_cast<Clock::Nanos>(ts.tv_nsec);
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 Core::Error Core::Clock::wait(Nanos nanos) {
     timespec t;
     t.tv_nsec = nanos % 1'000'000'000;
     t.tv_sec = nanos / 1'000'000'000;
-    return thrd_sleep(&t, nullptr) != 0 ? Error::SLEEP_INTERRUPTED
-                                        : Error::NONE;
-}
+    return thrd_sleep(&t, nullptr) != 0 ? ErrorCode::SLEEP_INTERRUPTED
+                                        : ErrorCode::NONE;
+}

+ 17 - 24
src/Error.cpp

@@ -1,27 +1,20 @@
 #include "core/utils/Error.hpp"
 
-#define CASE_RETURN_ENUM_NAME(type)                                            \
-    case Error::type: return #type
-
-const char* Core::getErrorName(Error e) {
-    switch(e) {
-        CASE_RETURN_ENUM_NAME(NONE);
-        CASE_RETURN_ENUM_NAME(NEGATIVE_ARGUMENT);
-        CASE_RETURN_ENUM_NAME(CAPACITY_REACHED);
-        CASE_RETURN_ENUM_NAME(BLOCKED_STDOUT);
-        CASE_RETURN_ENUM_NAME(OUT_OF_MEMORY);
-        CASE_RETURN_ENUM_NAME(INVALID_CHAR);
-        CASE_RETURN_ENUM_NAME(NOT_FOUND);
-        CASE_RETURN_ENUM_NAME(INVALID_STATE);
-        CASE_RETURN_ENUM_NAME(INVALID_INDEX);
-        CASE_RETURN_ENUM_NAME(INVALID_ARGUMENT);
-        CASE_RETURN_ENUM_NAME(TIME_NOT_AVAILABLE);
-        CASE_RETURN_ENUM_NAME(SLEEP_INTERRUPTED);
-        CASE_RETURN_ENUM_NAME(THREAD_ERROR);
-        CASE_RETURN_ENUM_NAME(MUTEX_ERROR);
-        CASE_RETURN_ENUM_NAME(EXISTING_KEY);
-        CASE_RETURN_ENUM_NAME(CANNOT_OPEN_FILE);
-        CASE_RETURN_ENUM_NAME(END_OF_FILE);
+CError Core::toString(Error e, char* buffer, int size) {
+    int index = 0;
+    Error::Code c = e.code;
+    size--;
+    while(true) {
+        if(index >= size) {
+            buffer[index] = '\0';
+            return ErrorCode::CAPACITY_REACHED;
+        }
+        buffer[index++] = (c & 1) ? '1' : '0';
+        c >>= 1;
+        if(c == 0) {
+            break;
+        }
     }
-    return "?";
-}
+    buffer[index] = '\0';
+    return ErrorCode::NONE;
+}

+ 1 - 1
src/ErrorSimulator.cpp

@@ -14,4 +14,4 @@ bool Core::Fail::freeAndReturn(void* p) {
     return true;
 }
 
-#endif
+#endif

+ 1 - 1
src/ErrorSimulator.hpp

@@ -20,4 +20,4 @@ namespace Core::Fail {
 #define CORE_TIME_GET_FAIL false
 #endif
 
-#endif
+#endif

+ 9 - 9
src/FileReader.cpp

@@ -33,40 +33,40 @@ const Core::Path& Core::FileReader::getPath() const {
 
 Core::Error Core::FileReader::open(const Path& p) {
     if(file != nullptr) {
-        return Error::INVALID_STATE;
+        return ErrorCode::INVALID_STATE;
     }
     path = p;
     file = fopen(path, "rb");
-    return file != nullptr ? Error::NONE : Error::CANNOT_OPEN_FILE;
+    return file != nullptr ? ErrorCode::NONE : ErrorCode::CANNOT_OPEN_FILE;
 }
 
 Core::Error Core::FileReader::open(const char* p) {
     if(file != nullptr) {
-        return Error::INVALID_STATE;
+        return ErrorCode::INVALID_STATE;
     }
     CORE_RETURN_ERROR(path.append(p));
     file = fopen(path, "rb");
-    return file != nullptr ? Error::NONE : Error::CANNOT_OPEN_FILE;
+    return file != nullptr ? ErrorCode::NONE : ErrorCode::CANNOT_OPEN_FILE;
 }
 
 Core::Error Core::FileReader::readChar(int& c) {
     if(file == nullptr) {
-        return Error::INVALID_STATE;
+        return ErrorCode::INVALID_STATE;
     }
     c = fgetc(static_cast<FILE*>(file));
-    return c == EOF ? Error::END_OF_FILE : Error::NONE;
+    return c == EOF ? ErrorCode::END_OF_FILE : ErrorCode::NONE;
 }
 
 Core::Error Core::FileReader::readChars(char* buffer, int bufferSize) {
     if(file == nullptr) {
-        return Error::INVALID_STATE;
+        return ErrorCode::INVALID_STATE;
     } else if(bufferSize <= 0) {
-        return Error::INVALID_ARGUMENT;
+        return ErrorCode::INVALID_ARGUMENT;
     }
     size_t size = static_cast<size_t>(bufferSize - 1);
     size_t readBytes = fread(buffer, 1, size, static_cast<FILE*>(file));
     buffer[readBytes] = '\0';
-    return readBytes != size ? Error::END_OF_FILE : Error::NONE;
+    return readBytes != size ? ErrorCode::END_OF_FILE : ErrorCode::NONE;
 }
 
 void Core::FileReader::swap(FileReader& other) {

+ 1 - 1
src/Logger.cpp

@@ -11,4 +11,4 @@ const char* Core::Logger::getFileName(const char* path) {
         end--;
     }
     return path + end;
-}
+}

+ 1 - 1
src/Math.cpp

@@ -25,4 +25,4 @@ void Core::Math::sinCos(float a, float& s, float& c) {
 
 float Core::Math::squareRoot(float f) {
     return sqrtf(f);
-}
+}

+ 8 - 7
src/Mutex.cpp

@@ -27,19 +27,20 @@ Core::Mutex::~Mutex() {
 
 check_return Core::Error Core::Mutex::init() {
     if(doesExist(mutex.as<mtx_t>())) {
-        return Error::INVALID_STATE;
+        return ErrorCode::INVALID_STATE;
     }
     return mtx_init(mutex.as<mtx_t>(), mtx_plain) != thrd_success
-               ? Error::MUTEX_ERROR
-               : Error::NONE;
+               ? ErrorCode::MUTEX_ERROR
+               : ErrorCode::NONE;
 }
 
 check_return Core::Error Core::Mutex::lock() {
-    return mtx_lock(mutex.as<mtx_t>()) != thrd_success ? Error::MUTEX_ERROR
-                                                       : Error::NONE;
+    return mtx_lock(mutex.as<mtx_t>()) != thrd_success ? ErrorCode::MUTEX_ERROR
+                                                       : ErrorCode::NONE;
 }
 
 check_return Core::Error Core::Mutex::unlock() {
-    return mtx_unlock(mutex.as<mtx_t>()) != thrd_success ? Error::MUTEX_ERROR
-                                                         : Error::NONE;
+    return mtx_unlock(mutex.as<mtx_t>()) != thrd_success
+               ? ErrorCode::MUTEX_ERROR
+               : ErrorCode::NONE;
 }

+ 1 - 1
src/Plane.cpp

@@ -9,4 +9,4 @@ Core::Plane::Plane(const Vector3& a, const Vector3& b, const Vector3& c)
 
 float Core::Plane::getSignedDistance(const Vector3& v) const {
     return abc.dot(v) + d;
-}
+}

+ 1 - 1
src/Quaternion.cpp

@@ -40,4 +40,4 @@ Core::Vector3 Core::Quaternion::operator*(const Vector3& v) const {
     Vector3 qv = v * w + xyz.cross(v);
     Vector3 qvq = xyz * xyz.dot(v) + qv * w - qv.cross(xyz);
     return qvq;
-}
+}

+ 4 - 4
src/Thread.cpp

@@ -42,14 +42,14 @@ Core::Thread& Core::Thread::operator=(Thread&& other) {
 
 check_return Core::Error Core::Thread::start(Function f, void* p) {
     return thrd_create(thread.as<thrd_t>(), f, p) != thrd_success
-               ? Error::THREAD_ERROR
-               : Error::NONE;
+               ? ErrorCode::THREAD_ERROR
+               : ErrorCode::NONE;
 }
 
 check_return Core::Error Core::Thread::join(int* returnValue) {
     int e = thrd_join(*thread.as<thrd_t>(), returnValue);
     reset(thread.as<thrd_t>());
-    return e != thrd_success ? Error::THREAD_ERROR : Error::NONE;
+    return e != thrd_success ? ErrorCode::THREAD_ERROR : ErrorCode::NONE;
 }
 
 void Core::Thread::swap(Thread& other) {
@@ -57,4 +57,4 @@ void Core::Thread::swap(Thread& other) {
     memoryCopy(&tmp, thread.as<thrd_t>(), sizeof(thrd_t));
     memoryCopy(thread.as<thrd_t>(), other.thread.as<thrd_t>(), sizeof(thrd_t));
     memoryCopy(other.thread.as<thrd_t>(), &tmp, sizeof(thrd_t));
-}
+}

+ 8 - 8
src/Utility.cpp

@@ -30,12 +30,12 @@ void Core::setExitHandler(ExitHandler eh, void* data) {
 #define CORE_TO_STRING(type, cast, format)                                     \
     check_return Core::Error Core::toString(type t, char* buffer, int size) {  \
         if(size < 0) {                                                         \
-            return Error::NEGATIVE_ARGUMENT;                                   \
+            return ErrorCode::NEGATIVE_ARGUMENT;                               \
         }                                                                      \
         return snprintf(buffer, static_cast<unsigned int>(size), format,       \
                         static_cast<cast>(t)) >= size                          \
-                   ? Error::CAPACITY_REACHED                                   \
-                   : Error::NONE;                                              \
+                   ? ErrorCode::CAPACITY_REACHED                               \
+                   : ErrorCode::NONE;                                          \
     }
 
 CORE_TO_STRING(signed short, signed short, "%hd")
@@ -51,7 +51,7 @@ CORE_TO_STRING(double, double, "%.2lf")
 CORE_TO_STRING(long double, long double, "%.2Lf")
 
 Core::Error Core::putChar(int c) {
-    return putchar(c) == EOF ? Error::BLOCKED_STDOUT : Error::NONE;
+    return putchar(c) == EOF ? ErrorCode::BLOCKED_STDOUT : ErrorCode::NONE;
 }
 
 void Core::memorySet(void* p, int c, i64 n) {
@@ -76,16 +76,16 @@ Core::Error Core::reallocate(char*& p, i64 n) {
     if(n <= 0) {
         free(p);
         p = nullptr;
-        return Error::NONE;
+        return ErrorCode::NONE;
     }
     char* newP = static_cast<char*>(realloc(p, static_cast<u64>(n)));
     if(newP == nullptr || CORE_REALLOC_FAIL(newP)) {
-        return Error::OUT_OF_MEMORY;
+        return ErrorCode::OUT_OF_MEMORY;
     }
     p = newP;
-    return Error::NONE;
+    return ErrorCode::NONE;
 }
 
 void Core::free(void* p) {
     ::free(p);
-}
+}

+ 1 - 1
src/Vector.cpp

@@ -18,4 +18,4 @@ Core::Vector3 Core::Vector3::cross(const Vector3& other) const {
     return Vector3(values[1] * other.values[2] - values[2] * other.values[1],
                    values[2] * other.values[0] - values[0] * other.values[2],
                    values[0] * other.values[1] - values[1] * other.values[0]);
-}
+}

+ 1 - 2
test/Test.cpp

@@ -1,7 +1,6 @@
 #include "Test.hpp"
 
 namespace Internal = Core::Test::Internal;
-namespace Logger = Core::Logger;
 
 Core::HashMap<Internal::FileName, Internal::Result> Internal::results;
 
@@ -25,4 +24,4 @@ void Core::Test::finalize() {
                     e.value.successTests, e.value.tests);
     }
     Internal::results.clear();
-}
+}

+ 4 - 4
test/Test.hpp

@@ -20,7 +20,7 @@ namespace Core::Test {
         bool check(const char* file, int line, const T& wanted, const T& actual,
                    bool c) {
             file = Logger::getFileName(file);
-            Error e = Error::NONE;
+            Error e = ErrorCode::NONE;
             FileName fileName;
             if(checkError(e, fileName.append(file))) {
                 warn(file, line, e);
@@ -52,7 +52,7 @@ namespace Core::Test {
         template<typename A, typename B>
         bool checkString(const char* file, int line, const A& wanted,
                          const B& actual) {
-            Error e = Error::NONE;
+            Error e = ErrorCode::NONE;
             String32<2048> a;
             if(checkError(e, a.append(wanted))) {
                 warn(file, line, e);
@@ -91,7 +91,7 @@ namespace Core::Test {
     Core::Test::Internal::checkString(__FILE__, __LINE__, wanted, actual)
 #define CORE_TEST_FALSE(actual) CORE_TEST_EQUAL(false, actual)
 #define CORE_TEST_TRUE(actual) CORE_TEST_EQUAL(true, actual)
-#define CORE_TEST_ERROR(actual) CORE_TEST_EQUAL(Core::Error::NONE, actual)
+#define CORE_TEST_ERROR(actual) CORE_TEST_EQUAL(Core::ErrorCode::NONE, actual)
 #define CORE_TEST_NULL(actual) CORE_TEST_EQUAL(true, actual == nullptr)
 // double check to make the null check clear for the compiler
 #define CORE_TEST_NOT_NULL(actual)                                             \
@@ -102,4 +102,4 @@ namespace Core::Test {
     Core::Test::Internal::checkVector(__FILE__, __LINE__, wanted, actual,      \
                                       0.0001f)
 
-#endif
+#endif

+ 5 - 5
test/modules/ArrayListTests.cpp

@@ -45,7 +45,7 @@ static void testOverflow(bool light) {
     }
     int limit = light ? 1000 : 100000;
     for(int i = 0; i < limit; i++) {
-        CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, list.add(i));
+        CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, list.add(i));
     }
     for(int i = 0; i < list.getLength(); i++) {
         CORE_TEST_EQUAL(i, list[i]);
@@ -136,9 +136,9 @@ static void testRemove() {
     CORE_TEST_EQUAL(2, list[0]);
     CORE_TEST_EQUAL(3, list[1]);
     CORE_TEST_EQUAL(2, list.getLength());
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.removeBySwap(4));
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.removeBySwap(-1));
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.removeBySwap(-5));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.removeBySwap(4));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.removeBySwap(-1));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.removeBySwap(-5));
     CORE_TEST_EQUAL(2, list[0]);
     CORE_TEST_EQUAL(3, list[1]);
     CORE_TEST_EQUAL(2, list.getLength());
@@ -177,4 +177,4 @@ void Core::testArrayList(bool light) {
     testToString3();
     testRemove();
     testForRange();
-}
+}

+ 44 - 31
test/modules/ArrayStringTests.cpp

@@ -2,7 +2,8 @@
 #include "core/data/HashMap.hpp"
 #include "core/utils/ArrayString.hpp"
 
-template class Core::Char32String<128>;
+template class Core::ArrayString<128, char, Core::CharString>;
+template class Core::ArrayString<128, c32, Core::Char32String>;
 
 using String8 = Core::String8<128>;
 using String32 = Core::String32<128>;
@@ -50,9 +51,9 @@ static void testStringAppend8() {
 }
 
 static void testStringAppendOverflow8() {
-    Core::ArrayCharString<6> s;
+    Core::String8<6> s;
     CORE_TEST_ERROR(s.append("te"));
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append("23334444"));
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, s.append("23334444"));
     CORE_TEST_TRUE(build("te23334444") != s);
 }
 
@@ -192,8 +193,8 @@ static void testBool8() {
 }
 
 static void testIntOverflow8() {
-    Core::ArrayCharString<4> s;
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append(123456));
+    Core::String8<4> s;
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, s.append(123456));
 
     String8 o;
     for(int i = 0; i < s.getCapacity(); i++) {
@@ -468,8 +469,8 @@ static void testAppendUnsignedChar8() {
 
 static void testAppendError8() {
     String8 s;
-    CORE_TEST_ERROR(s.append(Core::Error::NONE));
-    CORE_TEST_TRUE(s == "NONE");
+    CORE_TEST_ERROR(s.append(Core::ErrorCode::NONE));
+    CORE_TEST_STRING("0", s);
 }
 
 static void testPrint8() {
@@ -532,9 +533,9 @@ static void testStringAppend32() {
 }
 
 static void testStringAppendOverflow32() {
-    Core::Char32String<6> s;
+    Core::String32<6> s;
     CORE_TEST_ERROR(s.append(U"te"));
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append(U"23334444"));
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, s.append(U"23334444"));
     CORE_TEST_TRUE(build(U"te23334444") != s);
 }
 
@@ -674,8 +675,8 @@ static void testBool32() {
 }
 
 static void testIntOverflow32() {
-    Core::Char32String<4> s;
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append(123456));
+    Core::String32<4> s;
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, s.append(123456));
 
     String32 o;
     for(int i = 0; i < s.getCapacity(); i++) {
@@ -867,18 +868,30 @@ static void testSubString32() {
     String32 s;
     CORE_TEST_ERROR(s.append(U"01üää3ä"));
 
-    CORE_TEST_STRING(U"01üää3ä", s.substring(-2));
-    CORE_TEST_STRING(U"1üää3ä", s.substring(1));
-    CORE_TEST_STRING(U"üää3ä", s.substring(2));
-    CORE_TEST_STRING(U"ää3ä", s.substring(3));
-    CORE_TEST_STRING(U"ä3ä", s.substring(4));
-
-    CORE_TEST_STRING(U"01üää3ä", s.substring(0, 6));
-    CORE_TEST_STRING(U"1üää3", s.substring(1, 5));
-    CORE_TEST_STRING(U"üää", s.substring(2, 4));
-    CORE_TEST_STRING(U"ä", s.substring(3, 3));
-    CORE_TEST_STRING(U"", s.substring(4, 2));
-    CORE_TEST_STRING(U"ä3ä", s.substring(4, 23));
+    String32 sub;
+    CORE_TEST_ERROR(s.substring(sub, -2));
+    CORE_TEST_STRING(U"01üää3ä", sub);
+    CORE_TEST_ERROR(s.substring(sub, 1));
+    CORE_TEST_STRING(U"1üää3ä", sub);
+    CORE_TEST_ERROR(s.substring(sub, 2));
+    CORE_TEST_STRING(U"üää3ä", sub);
+    CORE_TEST_ERROR(s.substring(sub, 3));
+    CORE_TEST_STRING(U"ää3ä", sub);
+    CORE_TEST_ERROR(s.substring(sub, 4));
+    CORE_TEST_STRING(U"ä3ä", sub);
+
+    CORE_TEST_ERROR(s.substring(sub, 0, 6));
+    CORE_TEST_STRING(U"01üää3ä", sub);
+    CORE_TEST_ERROR(s.substring(sub, 1, 5));
+    CORE_TEST_STRING(U"1üää3", sub);
+    CORE_TEST_ERROR(s.substring(sub, 2, 4));
+    CORE_TEST_STRING(U"üää", sub);
+    CORE_TEST_ERROR(s.substring(sub, 3, 3));
+    CORE_TEST_STRING(U"ä", sub);
+    CORE_TEST_ERROR(s.substring(sub, 4, 2));
+    CORE_TEST_STRING(U"", sub);
+    CORE_TEST_ERROR(s.substring(sub, 4, 23));
+    CORE_TEST_STRING(U"ä3ä", sub);
 }
 
 static void testReplace32() {
@@ -949,8 +962,8 @@ static void testAppendUnsignedChar32() {
 
 static void testAppendError32() {
     String32 s;
-    CORE_TEST_ERROR(s.append(Core::Error::NONE));
-    CORE_TEST_TRUE(s == U"NONE");
+    CORE_TEST_ERROR(s.append(Core::ErrorCode::NONE));
+    CORE_TEST_STRING(U"0", s);
 }
 
 static void testPrint32() {
@@ -971,12 +984,12 @@ static void testVariousUnicode32() {
     const unsigned char buffer5[] = {0xF0, 1, 2, 3, 0};
     const unsigned char buffer6[] = {0xFF, 0};
     String32 s;
-    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer));
-    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer2));
-    CORE_TEST_EQUAL(Core::Error::NONE, s.append(buffer3));
-    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer4));
-    CORE_TEST_EQUAL(Core::Error::NONE, s.append(buffer5));
-    CORE_TEST_EQUAL(Core::Error::INVALID_CHAR, s.append(buffer6));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_CHAR, s.append(buffer));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_CHAR, s.append(buffer2));
+    CORE_TEST_EQUAL(Core::ErrorCode::NONE, s.append(buffer3));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_CHAR, s.append(buffer4));
+    CORE_TEST_EQUAL(Core::ErrorCode::NONE, s.append(buffer5));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_CHAR, s.append(buffer6));
 }
 
 static void testKeepHash32() {

+ 1 - 1
test/modules/ArrayTests.cpp

@@ -46,4 +46,4 @@ void Core::testArray() {
     testToString2();
     testReadConst();
     testRangeFor();
-}
+}

+ 8 - 8
test/modules/BitArrayTests.cpp

@@ -136,25 +136,25 @@ static void testMoveAssignment() {
 
 static void testInvalidArgument() {
     Core::BitArray bits;
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT, bits.resize(0, 5));
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT, bits.resize(5, 0));
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT, bits.resize(0, 0));
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT, bits.resize(1, 65));
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT, bits.resize(5, 68));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(0, 5));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(5, 0));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(0, 0));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(1, 65));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, bits.resize(5, 68));
 }
 
 static void testOutOfMemory() {
 #ifdef ERROR_SIMULATOR
     Core::BitArray bits;
     Core::Fail::leftAllocations = 0;
-    CORE_TEST_EQUAL(Core::Error::OUT_OF_MEMORY, bits.resize(8, 4));
+    CORE_TEST_EQUAL(Core::ErrorCode::OUT_OF_MEMORY, bits.resize(8, 4));
     Core::Fail::leftAllocations = -1;
 #endif
 }
 
 static void testOutOfMemory2() {
     Core::BitArray bits;
-    CORE_TEST_EQUAL(Core::Error::OUT_OF_MEMORY,
+    CORE_TEST_EQUAL(Core::ErrorCode::OUT_OF_MEMORY,
                     bits.resize(0x01FF'FFFF'FFFF'FFFF, 64));
 }
 
@@ -175,4 +175,4 @@ void Core::testBitArray(bool outOfMemoryTest) {
         testOutOfMemory();
     }
     testOutOfMemory2();
-}
+}

+ 1 - 1
test/modules/BoxTests.cpp

@@ -57,4 +57,4 @@ void Core::testBox() {
     testCollidesWith();
     testExpand();
     testGrow();
-}
+}

+ 1 - 1
test/modules/BufferTests.cpp

@@ -66,4 +66,4 @@ void Core::testBuffer(bool light) {
     testCopy();
     testMoveConstruct();
     testMove();
-}
+}

+ 1 - 1
test/modules/BufferedValueTests.cpp

@@ -92,4 +92,4 @@ void Core::testBufferedValue() {
     testUpdate();
     testCalculate();
     testVector2();
-}
+}

+ 3 - 2
test/modules/ClockTests.cpp

@@ -41,7 +41,8 @@ static void testFail() {
 #ifdef ERROR_SIMULATOR
     Core::Clock::Nanos n = 0;
     Core::Fail::timeGet = true;
-    CORE_TEST_EQUAL(Core::Error::TIME_NOT_AVAILABLE, Core::Clock::getNanos(n));
+    CORE_TEST_EQUAL(Core::ErrorCode::TIME_NOT_AVAILABLE,
+                    Core::Clock::getNanos(n));
     Core::Fail::timeGet = false;
 #endif
 }
@@ -52,4 +53,4 @@ void Core::testClock(bool light) {
     testWait(light ? 5'000'000 : 50'000'000);
     testWait(light ? 50'000'000 : 1'300'000'000);
     testFail();
-}
+}

+ 1 - 1
test/modules/ColorTests.cpp

@@ -60,4 +60,4 @@ void Core::testColor() {
     testColor4<Core::Color4>();
     testColor4<const Core::Color4>();
     testColor4Empty();
-}
+}

+ 4 - 4
test/modules/ComponentsTests.cpp

@@ -145,9 +145,9 @@ static void testRemove() {
     CORE_TEST_ERROR(c.add(5, 20));
     CORE_TEST_ERROR(c.add(10, 30));
 
-    CORE_TEST_EQUAL(Core::Error::NOT_FOUND, c.remove(20));
+    CORE_TEST_EQUAL(Core::ErrorCode::NOT_FOUND, c.remove(20));
     CORE_TEST_ERROR(c.remove(5));
-    CORE_TEST_EQUAL(Core::Error::NOT_FOUND, c.remove(30));
+    CORE_TEST_EQUAL(Core::ErrorCode::NOT_FOUND, c.remove(30));
 
     CORE_TEST_ERROR(c.add(20, 40));
     CORE_TEST_ERROR(c.remove(20));
@@ -194,7 +194,7 @@ static void testOutOfMemory() {
     for(int i = 0; i < 40; i++) {
         Core::Fail::leftAllocations = 2;
         Core::Error e = c.put(i1, 1, 10);
-        if(e == Core::Error::OUT_OF_MEMORY) {
+        if(e == Core::ErrorCode::OUT_OF_MEMORY) {
             memFails++;
         }
     }
@@ -224,4 +224,4 @@ void Core::testComponents(bool outOfMemoryTest) {
         testOutOfMemory();
     }
     testConstSearch();
-}
+}

+ 29 - 23
test/modules/ErrorTests.cpp

@@ -1,27 +1,33 @@
 #include "../Tests.hpp"
 #include "core/utils/Error.hpp"
 
-static void test(Core::Error e, const char* s) {
-    CORE_TEST_STRING(getErrorName(e), s);
-}
-
 void Core::testError() {
-    test(Error::NONE, "NONE");
-    test(Error::NEGATIVE_ARGUMENT, "NEGATIVE_ARGUMENT");
-    test(Error::CAPACITY_REACHED, "CAPACITY_REACHED");
-    test(Error::BLOCKED_STDOUT, "BLOCKED_STDOUT");
-    test(Error::OUT_OF_MEMORY, "OUT_OF_MEMORY");
-    test(Error::INVALID_CHAR, "INVALID_CHAR");
-    test(Error::NOT_FOUND, "NOT_FOUND");
-    test(Error::INVALID_STATE, "INVALID_STATE");
-    test(Error::INVALID_INDEX, "INVALID_INDEX");
-    test(Error::INVALID_ARGUMENT, "INVALID_ARGUMENT");
-    test(Error::TIME_NOT_AVAILABLE, "TIME_NOT_AVAILABLE");
-    test(Error::SLEEP_INTERRUPTED, "SLEEP_INTERRUPTED");
-    test(Error::THREAD_ERROR, "THREAD_ERROR");
-    test(Error::MUTEX_ERROR, "MUTEX_ERROR");
-    test(Error::EXISTING_KEY, "EXISTING_KEY");
-    test(Error::CANNOT_OPEN_FILE, "CANNOT_OPEN_FILE");
-    test(Error::END_OF_FILE, "END_OF_FILE");
-    test(static_cast<Error>(200), "?");
-}
+    CORE_TEST_STRING("0", ErrorCode::NONE);
+    CORE_TEST_STRING("1", ErrorCode::NEGATIVE_ARGUMENT);
+    CORE_TEST_STRING("01", ErrorCode::CAPACITY_REACHED);
+    CORE_TEST_STRING("001", ErrorCode::BLOCKED_STDOUT);
+    CORE_TEST_STRING("0001", ErrorCode::OUT_OF_MEMORY);
+    CORE_TEST_STRING("00001", ErrorCode::INVALID_CHAR);
+    CORE_TEST_STRING("000001", ErrorCode::NOT_FOUND);
+    CORE_TEST_STRING("0000001", ErrorCode::INVALID_STATE);
+    CORE_TEST_STRING("00000001", ErrorCode::INVALID_INDEX);
+    CORE_TEST_STRING("000000001", ErrorCode::INVALID_ARGUMENT);
+    CORE_TEST_STRING("0000000001", ErrorCode::TIME_NOT_AVAILABLE);
+    CORE_TEST_STRING("00000000001", ErrorCode::SLEEP_INTERRUPTED);
+    CORE_TEST_STRING("000000000001", ErrorCode::THREAD_ERROR);
+    CORE_TEST_STRING("0000000000001", ErrorCode::MUTEX_ERROR);
+    CORE_TEST_STRING("00000000000001", ErrorCode::EXISTING_KEY);
+    CORE_TEST_STRING("000000000000001", ErrorCode::CANNOT_OPEN_FILE);
+    CORE_TEST_STRING("0000000000000001", ErrorCode::END_OF_FILE);
+
+    CORE_TEST_STRING(
+        "1111111111111111",
+        ErrorCode::NEGATIVE_ARGUMENT | ErrorCode::CAPACITY_REACHED |
+            ErrorCode::BLOCKED_STDOUT | ErrorCode::OUT_OF_MEMORY |
+            ErrorCode::INVALID_CHAR | ErrorCode::NOT_FOUND |
+            ErrorCode::INVALID_STATE | ErrorCode::INVALID_INDEX |
+            ErrorCode::INVALID_ARGUMENT | ErrorCode::TIME_NOT_AVAILABLE |
+            ErrorCode::SLEEP_INTERRUPTED | ErrorCode::THREAD_ERROR |
+            ErrorCode::MUTEX_ERROR | ErrorCode::EXISTING_KEY |
+            ErrorCode::CANNOT_OPEN_FILE | ErrorCode::END_OF_FILE);
+}

+ 10 - 10
test/modules/FileReaderTests.cpp

@@ -10,7 +10,7 @@ static void testReadChar() {
     Core::String8<128> s;
     while(true) {
         int c = 0;
-        if(r.readChar(c) != Core::Error::NONE) {
+        if(r.readChar(c) != Core::ErrorCode::NONE) {
             break;
         }
         CORE_TEST_ERROR(s.append(static_cast<c32>(c)));
@@ -26,7 +26,7 @@ static void testReadCharPath() {
     Core::String8<128> s;
     while(true) {
         int c = 0;
-        if(r.readChar(c) != Core::Error::NONE) {
+        if(r.readChar(c) != Core::ErrorCode::NONE) {
             break;
         }
         CORE_TEST_ERROR(s.append(static_cast<c32>(c)));
@@ -38,7 +38,7 @@ static void testReadChars() {
     Core::FileReader r;
     CORE_TEST_ERROR(r.open(TEST_FILE));
     char buffer[128];
-    CORE_TEST_EQUAL(Core::Error::END_OF_FILE,
+    CORE_TEST_EQUAL(Core::ErrorCode::END_OF_FILE,
                     r.readChars(buffer, sizeof(buffer)));
     CORE_TEST_STRING("abc\nBaum\n", buffer);
 }
@@ -59,7 +59,7 @@ static void testMoveConstruct() {
     CORE_TEST_STRING(TEST_FILE, r2.getPath());
 
     int c = 0;
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, r.readChar(c));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, r.readChar(c));
     CORE_TEST_ERROR(r2.readChar(c));
     CORE_TEST_EQUAL('a', c);
 }
@@ -73,7 +73,7 @@ static void testMoveAssignment() {
     CORE_TEST_STRING(TEST_FILE, r2.getPath());
 
     int c = 0;
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, r.readChar(c));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, r.readChar(c));
     CORE_TEST_ERROR(r2.readChar(c));
     CORE_TEST_EQUAL('a', c);
 }
@@ -81,11 +81,11 @@ static void testMoveAssignment() {
 static void testInvalidAccess() {
     char buffer[4];
     Core::FileReader r;
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE,
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE,
                     r.readChars(buffer, sizeof(buffer)));
     CORE_TEST_ERROR(r.open(TEST_FILE));
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT, r.readChars(buffer, -1));
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, r.open(TEST_FILE));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT, r.readChars(buffer, -1));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, r.open(TEST_FILE));
 }
 
 static void testInvalidAccessPath() {
@@ -93,7 +93,7 @@ static void testInvalidAccessPath() {
     Core::Path path;
     CORE_TEST_ERROR(path.append(TEST_FILE));
     CORE_TEST_ERROR(r.open(path));
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, r.open(path));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, r.open(path));
 }
 
 static void testCloseFail() {
@@ -117,4 +117,4 @@ void Core::testFileReader() {
     testInvalidAccess();
     testInvalidAccessPath();
     testCloseFail();
-}
+}

+ 1 - 1
test/modules/FrustumTests.cpp

@@ -60,4 +60,4 @@ void Core::testFrustum() {
     testPointIsInside();
     testSphereIsInside();
     testUpdateProjection();
-}
+}

+ 6 - 5
test/modules/HashMapTests.cpp

@@ -95,7 +95,7 @@ struct HashMapTestStruct final {
         CORE_RETURN_ERROR(s.append(", "));
         CORE_RETURN_ERROR(s.append(b));
         CORE_RETURN_ERROR(s.append(")"));
-        return Core::Error::NONE;
+        return Core::ErrorCode::NONE;
     }
 };
 
@@ -106,8 +106,9 @@ static void testEmplace() {
     CORE_TEST_ERROR(map.tryEmplace(ar, 0, 3, 4));
     CORE_TEST_ERROR(map.tryEmplace(ar, 3, 4, 5));
     CORE_TEST_ERROR(map.tryEmplace(ar, 20, 5, 6));
-    CORE_TEST_EQUAL(Core::Error::EXISTING_KEY, map.tryEmplace(ar, 3, 6, 7));
-    CORE_TEST_EQUAL(Core::Error::EXISTING_KEY, map.tryEmplace(ar, 20, 7, 8));
+    CORE_TEST_EQUAL(Core::ErrorCode::EXISTING_KEY, map.tryEmplace(ar, 3, 6, 7));
+    CORE_TEST_EQUAL(Core::ErrorCode::EXISTING_KEY,
+                    map.tryEmplace(ar, 20, 7, 8));
 
     HashMapTestStruct* a = map.search(0);
     HashMapTestStruct* b = map.search(3);
@@ -215,7 +216,7 @@ static void testRemove() {
     CORE_TEST_ERROR(map.add(3, 5));
 
     CORE_TEST_ERROR(map.remove(2));
-    CORE_TEST_EQUAL(Core::Error::NOT_FOUND, map.remove(7));
+    CORE_TEST_EQUAL(Core::ErrorCode::NOT_FOUND, map.remove(7));
 
     int* a = map.search(1);
     int* b = map.search(2);
@@ -319,7 +320,7 @@ static void testOutOfMemory() {
         Core::Fail::leftAllocations = 2;
         int* v = nullptr;
         Core::Error e = map.put(v, 1, 1);
-        if(e == Core::Error::OUT_OF_MEMORY) {
+        if(e == Core::ErrorCode::OUT_OF_MEMORY) {
             memFails++;
         }
     }

+ 1 - 1
test/modules/LinkedListTests.cpp

@@ -281,7 +281,7 @@ static void testOutOfMemory() {
     for(int i = 0; i < 40; i++) {
         Core::Fail::leftAllocations = i;
         Core::Error e = list.add(1);
-        if(e == Core::Error::OUT_OF_MEMORY) {
+        if(e == Core::ErrorCode::OUT_OF_MEMORY) {
             memFails++;
         }
     }

+ 8 - 8
test/modules/ListTests.cpp

@@ -135,9 +135,9 @@ static void testRemoveBySwap() {
     CORE_TEST_ERROR(list.add(4));
     CORE_TEST_ERROR(list.add(3));
     CORE_TEST_ERROR(list.add(2));
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.removeBySwap(-1));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.removeBySwap(-1));
     CORE_TEST_ERROR(list.removeBySwap(0));
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.removeBySwap(2));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.removeBySwap(2));
     CORE_TEST_EQUAL(2, list[0]);
     CORE_TEST_EQUAL(3, list[1]);
     CORE_TEST_EQUAL(2, list.getLength());
@@ -146,7 +146,7 @@ static void testRemoveBySwap() {
     CORE_TEST_EQUAL(1, list.getLength());
     CORE_TEST_ERROR(list.removeBySwap(0));
     CORE_TEST_EQUAL(0, list.getLength());
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.removeBySwap(0));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.removeBySwap(0));
 }
 
 static void testRemove() {
@@ -154,19 +154,19 @@ static void testRemove() {
     CORE_TEST_ERROR(list.add(4));
     CORE_TEST_ERROR(list.add(3));
     CORE_TEST_ERROR(list.add(2));
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.remove(-1));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.remove(-1));
     CORE_TEST_ERROR(list.remove(0));
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.remove(2));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.remove(2));
     CORE_TEST_EQUAL(3, list[0]);
     CORE_TEST_EQUAL(2, list[1]);
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.remove(2));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.remove(2));
     CORE_TEST_EQUAL(2, list.getLength());
     CORE_TEST_ERROR(list.remove(1));
     CORE_TEST_EQUAL(3, list[0]);
     CORE_TEST_EQUAL(1, list.getLength());
     CORE_TEST_ERROR(list.remove(0));
     CORE_TEST_EQUAL(0, list.getLength());
-    CORE_TEST_EQUAL(Core::Error::INVALID_INDEX, list.remove(0));
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_INDEX, list.remove(0));
 }
 
 static void testResize() {
@@ -233,4 +233,4 @@ void Core::testList(bool light) {
     testShrinkExact();
     testShrinkResize();
     testCopyEmpty();
-}
+}

+ 1 - 1
test/modules/MathTests.cpp

@@ -101,4 +101,4 @@ void Core::testMath() {
     testSinCos();
     testRadianToDegree();
     testDegreeToRadian();
-}
+}

+ 3 - 3
test/modules/MatrixStackTests.cpp

@@ -30,7 +30,7 @@ static void testPush(bool light) {
     }
     int limit = light ? 10000 : 1000000;
     for(int i = 0; i < limit; i++) {
-        CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, stack.push());
+        CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, stack.push());
     }
 }
 
@@ -101,7 +101,7 @@ static void testToString3() {
 
 static void testInvalidPop() {
     Matrices stack;
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, stack.pop());
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, stack.pop());
 }
 
 static void testConstPeek() {
@@ -123,4 +123,4 @@ void Core::testMatrixStack(bool light) {
     testToString3();
     testInvalidPop();
     testConstPeek();
-}
+}

+ 1 - 1
test/modules/PlaneTests.cpp

@@ -34,4 +34,4 @@ void Core::testPlane() {
     testToString1();
     testToString2();
     testSignedDistance();
-}
+}

+ 7 - 6
test/modules/ProbingHashMapTests.cpp

@@ -115,7 +115,7 @@ struct ProbingHashMapTestStruct final {
         CORE_RETURN_ERROR(s.append(", "));
         CORE_RETURN_ERROR(s.append(b));
         CORE_RETURN_ERROR(s.append(")"));
-        return Core::Error::NONE;
+        return Core::ErrorCode::NONE;
     }
 };
 
@@ -127,8 +127,9 @@ static void testEmplace() {
         CORE_TEST_ERROR(map.tryEmplace(ar, 0, 3, 4));
         CORE_TEST_ERROR(map.tryEmplace(ar, 3, 4, 5));
         CORE_TEST_ERROR(map.tryEmplace(ar, 20, 5, 6));
-        CORE_TEST_EQUAL(Core::Error::EXISTING_KEY, map.tryEmplace(ar, 3, 6, 7));
-        CORE_TEST_EQUAL(Core::Error::EXISTING_KEY,
+        CORE_TEST_EQUAL(Core::ErrorCode::EXISTING_KEY,
+                        map.tryEmplace(ar, 3, 6, 7));
+        CORE_TEST_EQUAL(Core::ErrorCode::EXISTING_KEY,
                         map.tryEmplace(ar, 20, 7, 8));
 
         ProbingHashMapTestStruct* a = map.search(0);
@@ -320,7 +321,7 @@ static void testOutOfMemory() {
         Core::Fail::leftAllocations = i;
         int* v = nullptr;
         Core::Error e = map.put(v, 1, 1);
-        if(e == Core::Error::OUT_OF_MEMORY) {
+        if(e == Core::ErrorCode::OUT_OF_MEMORY) {
             memFails++;
         }
     }
@@ -336,9 +337,9 @@ static void testOutOfMemory() {
 static void testInsertInvalid() {
     IntMap map;
     int* v;
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT,
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT,
                     map.tryEmplace(v, Core::emptyValue<int>(), 2));
-    CORE_TEST_EQUAL(Core::Error::INVALID_ARGUMENT,
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_ARGUMENT,
                     map.put(v, Core::emptyValue<int>(), 2));
 }
 

+ 1 - 1
test/modules/RandomTests.cpp

@@ -87,4 +87,4 @@ void Core::testRandom(bool light) {
     testFloatAverage(light);
     testFloatCoin(light);
     testFloatDistribution(light);
-}
+}

+ 5 - 5
test/modules/RingBufferTests.cpp

@@ -64,8 +64,8 @@ static void testOverflow() {
     CORE_TEST_ERROR(buffer.add(1));
     CORE_TEST_ERROR(buffer.add(2));
     CORE_TEST_ERROR(buffer.add(3));
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, buffer.add(4));
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, buffer.add(5));
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, buffer.add(4));
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, buffer.add(5));
     CORE_TEST_EQUAL(3, buffer.getLength());
     CORE_TEST_EQUAL(1, buffer[0]);
     CORE_TEST_ERROR(buffer.remove());
@@ -84,7 +84,7 @@ static void testRefill() {
     CORE_TEST_ERROR(buffer.add(1));
     CORE_TEST_ERROR(buffer.add(2));
     CORE_TEST_ERROR(buffer.add(3));
-    CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, buffer.add(4));
+    CORE_TEST_EQUAL(Core::ErrorCode::CAPACITY_REACHED, buffer.add(4));
     CORE_TEST_EQUAL(3, buffer.getLength());
     CORE_TEST_TRUE(buffer.canRemove());
     CORE_TEST_EQUAL(1, buffer[0]);
@@ -260,7 +260,7 @@ static void testOverall() {
 
 static void testInvalidRemove() {
     Core::RingBuffer<int, 3> buffer;
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, buffer.remove());
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, buffer.remove());
 }
 
 void Core::testRingBuffer() {
@@ -275,4 +275,4 @@ void Core::testRingBuffer() {
     testMoveAssignmentDestruct();
     testOverall();
     testInvalidRemove();
-}
+}

+ 2 - 2
test/modules/StackTests.cpp

@@ -60,7 +60,7 @@ template<typename T>
 static void testPop(int amount) {
     T stack;
     for(int i = 0; i < amount; i++) {
-        CORE_TEST_EQUAL(Core::Error::INVALID_STATE, stack.pop());
+        CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, stack.pop());
     }
 }
 
@@ -88,4 +88,4 @@ static void testType(int amount) {
 void Core::testStack(bool light) {
     testType<Core::ListStack<int>>(light ? 10000 : 100000);
     testType<Core::ArrayStack<int, 100>>(100);
-}
+}

+ 4 - 4
test/modules/ThreadTests.cpp

@@ -41,7 +41,7 @@ static void testLambda() {
 
 static void testJoinWithoutStart() {
     Core::Thread t;
-    CORE_TEST_EQUAL(Core::Error::THREAD_ERROR, t.join(nullptr));
+    CORE_TEST_EQUAL(Core::ErrorCode::THREAD_ERROR, t.join(nullptr));
 }
 
 static void testAutoJoin() {
@@ -75,7 +75,7 @@ static void testDoubleJoin() {
     Core::Thread t;
     CORE_TEST_ERROR(t.start([](void*) { return 0; }, nullptr));
     CORE_TEST_ERROR(t.join(nullptr));
-    CORE_TEST_EQUAL(Core::Error::THREAD_ERROR, t.join(nullptr));
+    CORE_TEST_EQUAL(Core::ErrorCode::THREAD_ERROR, t.join(nullptr));
 }
 
 struct MutexCounter {
@@ -96,7 +96,7 @@ static int incrementMutexCounter(void* p) {
 static void testMutex() {
     MutexCounter mc;
     CORE_TEST_ERROR(mc.m.init());
-    CORE_TEST_EQUAL(Core::Error::INVALID_STATE, mc.m.init());
+    CORE_TEST_EQUAL(Core::ErrorCode::INVALID_STATE, mc.m.init());
     Core::Thread t[2];
     CORE_TEST_ERROR(t[0].start(incrementMutexCounter, &mc));
     CORE_TEST_ERROR(t[1].start(incrementMutexCounter, &mc));
@@ -115,4 +115,4 @@ void Core::testThread() {
     testMoveIntoActive();
     testDoubleJoin();
     testMutex();
-}
+}

+ 3 - 2
test/modules/UtilityTests.cpp

@@ -41,7 +41,8 @@ static void testReallocateFail() {
 #ifdef ERROR_SIMULATOR
     char* buffer = nullptr;
     Core::Fail::realloc = true;
-    CORE_TEST_EQUAL(Core::Error::OUT_OF_MEMORY, Core::reallocate(buffer, 16));
+    CORE_TEST_EQUAL(Core::ErrorCode::OUT_OF_MEMORY,
+                    Core::reallocate(buffer, 16));
     CORE_TEST_TRUE(buffer == nullptr);
     Core::Fail::realloc = false;
 #endif
@@ -53,4 +54,4 @@ void Core::testUtility() {
     testNegativeArguments();
     testNegativeRellocate();
     testReallocateFail();
-}
+}

+ 1 - 1
test/modules/VectorTests.cpp

@@ -225,4 +225,4 @@ void Core::testVector() {
     testCast();
     testToString();
     testNormalizeIntVector();
-}
+}

+ 1 - 1
test/modules/ViewTests.cpp

@@ -38,4 +38,4 @@ void Core::testView() {
     testFromAngles();
     testFromQuaternion();
     testUpdateMatrix();
-}
+}