#ifndef CORE_ARRAY_STRING_HPP #define CORE_ARRAY_STRING_HPP #include "core/math/Math.hpp" #include "core/utils/Check.hpp" #include "core/utils/Error.hpp" #include "core/utils/Meta.hpp" #include "core/utils/Types.hpp" #include "core/utils/Utility.hpp" namespace Core { template constexpr int stringLength(const T* c) { const T* i = c + 1; while(*(c++) != '\0') {} return static_cast(c - i); } Error readUnicode(c32& u, const char*& s); class Char32String; class CharString { protected: i32 length; i32 capacity; u32 hash; char* data; public: 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; bool operator!=(const char* s) const; bool operator!=(const CharString& other) const; 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); template 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(buffer)); } } 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 check_return Error format(CharString& s, Args&&... args) { Error e = formatBuffer(s, 0, Core::forward(args)...); if(e == Error::NONE) { return copyFrom(s); } else if(e == Error::CAPACITY_REACHED) { (void)copyFrom(s); } return e; } bool startsWidth(const CharString& other, int from = 0) const; int search(const CharString& other, int from = 0) const; 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); void replace(char search, char replace); operator const char*() const; private: void addToHash(c32 u); template 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)...); } check_return Error formatBuffer(CharString& s, int index); }; class Char32String { protected: i32 length; i32 capacity; u32 hash; c32* data; public: 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(bool b); check_return Error append(Error e); template 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(buffer)); } } 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 check_return Error format(Char32String& s, Args&&... args) { Error e = formatBuffer(s, 0, Core::forward(args)...); if(e == Error::NONE) { return copyFrom(s); } else if(e == Error::CAPACITY_REACHED) { (void)copyFrom(s); } return e; } 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); void addToHash(c32 u); template 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)...); } check_return Error formatBuffer(Char32String& s, int index); }; template class ArrayString final : public B { static_assert(N > 0, "size of array string must be positive"); C data[static_cast(N)]; public: ArrayString() : B(data, N) { } ArrayString(const ArrayString& other) : B(data, N) { Core::memoryCopy(data, other.data, sizeof(data)); B::length = other.length; B::hash = other.hash; } ArrayString& operator=(const ArrayString& other) { if(this != &other) { Core::memoryCopy(data, other.data, sizeof(data)); B::length = other.length; B::hash = other.hash; } return *this; } template check_return Error format(Args&&... args) { ArrayString s; return B::format(s, Core::forward(args)...); } check_return Error replace(const B& search, const B& replace) { ArrayString s; return B::replace(s, search, replace); } using B::replace; }; template check_return Error toString(String& s, const Iterable& i) { CORE_RETURN_ERROR(s.append("[")); auto current = i.begin(); auto end = i.end(); while(current != end) { CORE_RETURN_ERROR(s.append(*current)); ++current; if(current != end) { CORE_RETURN_ERROR(s.append(", ")); } } return s.append("]"); } template using String8 = ArrayString; template using String32 = ArrayString; } inline bool operator==(const c32* cs, const Core::Char32String& s) { return s == cs; } inline bool operator!=(const c32* cs, const Core::Char32String& s) { return s != cs; } inline bool operator==(const char* cs, const Core::CharString& s) { return s == cs; } inline bool operator!=(const char* cs, const Core::CharString& s) { return s != cs; } #endif