Browse Source

Move c32 string to cpp as well

Kajetan Johannes Hammerle 2 weeks ago
parent
commit
ba27558413
3 changed files with 417 additions and 384 deletions
  1. 67 368
      include/core/utils/ArrayString.hpp
  2. 322 1
      src/ArrayString.cpp
  3. 28 15
      test/modules/ArrayStringTests.cpp

+ 67 - 368
include/core/utils/ArrayString.hpp

@@ -18,7 +18,6 @@ namespace Core {
 
     Error readUnicode(c32& u, const char*& s);
 
-    template<int N>
     class Char32String;
 
     class CharString {
@@ -32,7 +31,6 @@ namespace Core {
         CharString(char* buffer, i32 bufferSize);
         CharString(const CharString&) = delete;
         CharString& operator=(const CharString&) = delete;
-
         check_return Error copyFrom(const CharString& s);
         bool operator==(const char* s) const;
         bool operator==(const CharString& other) const;
@@ -65,12 +63,7 @@ namespace Core {
         }
 
         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));
-        }
-
+        check_return Error toString(Char32String& s) const;
         void clear();
         u32 hashCode() const;
         check_return Error print() const;
@@ -123,373 +116,86 @@ namespace Core {
         check_return Error formatBuffer(CharString& s, int index);
     };
 
-    template<int N>
-    class Char32String final {
-        int length;
+    class Char32String {
+    protected:
+        i32 length;
+        i32 capacity;
         u32 hash;
-        static_assert(N > 0, "size of array string must be positive");
-        c32 data[static_cast<unsigned int>(N)];
+        c32* data;
 
     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));
-        }
-
-        check_return Error append(signed short s) {
-            return convertAppend(s);
-        }
-
-        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));
-        }
+        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;
+        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(signed short s);
+        check_return Error append(unsigned short s);
+        check_return Error append(signed int i);
+        check_return Error append(unsigned int i);
+        check_return Error append(signed long l);
+        check_return Error append(unsigned long l);
+        check_return Error append(signed long long ll);
+        check_return Error append(unsigned long long ll);
+        check_return Error append(float f);
+        check_return Error append(double d);
+        check_return Error append(long double ld);
+        check_return Error append(bool b);
+        check_return Error append(Error 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;
-            }
-        }
-
-        check_return Error printLine() const {
-            CORE_RETURN_ERROR(print());
-            CORE_RETURN_ERROR(Core::putChar('\n'));
-            return Error::NONE;
-        }
+        check_return Error toString(CharString& s) const;
+        check_return Error toString(Char32String& s) const;
+        void clear();
+        u32 hashCode() const;
+        check_return Error print() const;
+        check_return Error printLine() const;
 
         template<typename... Args>
-        check_return Error format(Args&&... args) {
-            Char32String s;
+        check_return Error format(Char32String& s, Args&&... args) {
             Error e = formatBuffer(s, 0, Core::forward<Args>(args)...);
-            if(e == Error::NONE || e == Error::CAPACITY_REACHED) {
-                *this = s;
+            if(e == Error::NONE) {
+                return copyFrom(s);
+            } else if(e == Error::CAPACITY_REACHED) {
+                (void)copyFrom(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;
-        }
-
-        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;
-        }
-
-        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;
-        }
+        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;
+        check_return Error substring(Char32String& s, int from, int to) const;
+        check_return Error substring(Char32String& s, int from = 0) const;
+        check_return Error replace(Char32String& s, const Char32String& search,
+                                   const Char32String& replace);
+        void replace(c32 search, c32 replace);
+        operator const c32*() const;
 
     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);
-        }
+        Error add(c32 c);
+        void addToHash(c32 u);
 
         template<typename T, typename... Args>
         check_return Error formatBuffer(Char32String& s, int index, const T& t,
@@ -509,12 +215,7 @@ namespace Core {
             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;
-        }
+        check_return Error formatBuffer(Char32String& s, int index);
 
         template<typename T>
         check_return Error convertAppend(T t) {
@@ -581,16 +282,14 @@ namespace Core {
     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;
 }
 

+ 322 - 1
src/ArrayString.cpp

@@ -3,6 +3,7 @@
 #include "core/utils/Error.hpp"
 
 using CharString = Core::CharString;
+using Char32String = Core::Char32String;
 using Error = Core::Error;
 
 static c32 read(const char*& s) {
@@ -47,7 +48,7 @@ Error Core::readUnicode(c32& u, const char*& s) {
 }
 
 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 +72,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';
@@ -190,6 +195,10 @@ Error CharString::toString(CharString& s) const {
     return Error::NONE;
 }
 
+Error CharString::toString(Char32String& s) const {
+    return s.append(static_cast<const char*>(data));
+}
+
 void CharString::clear() {
     length = 0;
     hash = 0;
@@ -304,3 +313,315 @@ Error CharString::formatBuffer(CharString& s, int index) {
     }
     return Error::NONE;
 }
+
+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 *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 add(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 constexpr(IsSame<c32, char>) {
+        char buffer[5];
+        unicodeToChar(c, buffer);
+        return append(static_cast<const char*>(buffer));
+    } else {
+        return add(c);
+    }
+}
+
+Error Char32String::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));
+    }
+}
+
+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 Error::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(signed short s) {
+    return convertAppend(s);
+}
+
+Error Char32String::append(unsigned short s) {
+    return convertAppend(s);
+}
+
+Error Char32String::append(signed int i) {
+    return convertAppend(i);
+}
+
+Error Char32String::append(unsigned int i) {
+    return convertAppend(i);
+}
+
+Error Char32String::append(signed long l) {
+    return convertAppend(l);
+}
+
+Error Char32String::append(unsigned long l) {
+    return convertAppend(l);
+}
+
+Error Char32String::append(signed long long ll) {
+    return convertAppend(ll);
+}
+
+Error Char32String::append(unsigned long long ll) {
+    return convertAppend(ll);
+}
+
+Error Char32String::append(float f) {
+    return convertAppend(f);
+}
+
+Error Char32String::append(double d) {
+    return convertAppend(d);
+}
+
+Error Char32String::append(long double ld) {
+    return convertAppend(ld);
+}
+
+Error Char32String::append(bool b) {
+    return b ? append("true") : append("false");
+}
+
+Error Char32String::append(Error e) {
+    return append(getErrorName(e));
+}
+
+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 Error::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 Error::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 Error::NONE;
+}
+
+Error Char32String::printLine() const {
+    CORE_RETURN_ERROR(print());
+    CORE_RETURN_ERROR(Core::putChar('\n'));
+    return Error::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 Error::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;
+}
+
+Error Char32String::add(c32 c) {
+    if(length >= capacity - 1) {
+        return Error::CAPACITY_REACHED;
+    }
+    data[length++] = c;
+    data[length] = '\0';
+    addToHash(static_cast<c32>(c));
+    return Error::NONE;
+}
+
+void Char32String::addToHash(c32 u) {
+    hash = static_cast<u32>(2120251889) * hash + static_cast<u32>(u);
+}
+
+Error Char32String::formatBuffer(Char32String& s, int index) {
+    while(index < length) {
+        CORE_RETURN_ERROR(s.append(data[index++]));
+    }
+    return Error::NONE;
+}

+ 28 - 15
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>;
@@ -532,7 +533,7 @@ 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_TRUE(build(U"te23334444") != s);
@@ -674,7 +675,7 @@ static void testBool32() {
 }
 
 static void testIntOverflow32() {
-    Core::Char32String<4> s;
+    Core::String32<4> s;
     CORE_TEST_EQUAL(Core::Error::CAPACITY_REACHED, s.append(123456));
 
     String32 o;
@@ -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() {