#ifndef CORE_ARRAY_STRING_HPP #define CORE_ARRAY_STRING_HPP #include "core/utils/Error.hpp" #include "core/utils/Meta.hpp" #include "core/utils/Types.hpp" #include "core/utils/Utility.hpp" namespace Core { namespace Internal { template CError genericAppend(String& s, const T& t) { if constexpr(requires { t.toString(s); }) { return t.toString(s); } else if constexpr(requires { static_cast(t); }) { return s.append(static_cast(t)); } else { char buffer[64]; CORE_RETURN_ERROR(toString(t, buffer, CORE_SIZE(buffer))); return s.append(static_cast(buffer)); } } template 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)...); } while(index < f.getLength()) { CORE_RETURN_ERROR(s.append(f[index++])); } return ErrorCode::NONE; } } template CError copyFormat(String& result, String& s, Args&&... args) { if constexpr(sizeof...(args) > 0) { Error e = Internal::formatR(result, s, 0, forward(args)...); return e | result.copyFrom(s); } return ErrorCode::NONE; } class Char32String; class CharString { protected: i32 length; i32 capacity; char* data; public: CharString(char* buffer, i32 bufferSize); CharString(const CharString&) = delete; CharString& operator=(const CharString&) = delete; CError 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; 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 CError append(const T& t) { return Internal::genericAppend(*this, t); } CError toString(CharString& s) const; CError toString(Char32String& s) const; void clear(); CError print() const; CError printLine() const; template CError format(CharString& s, Args&&... args) { return copyFormat(*this, s, Core::forward(args)...); } 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; 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; }; class Char32String { protected: i32 length; i32 capacity; 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; 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 CError append(const T& t) { return Internal::genericAppend(*this, t); } CError toString(CharString& s) const; CError toString(Char32String& s) const; void clear(); CError print() const; CError printLine() const; template CError format(Char32String& s, Args&&... args) { return copyFormat(*this, s, Core::forward(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; }; 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; } ArrayString& operator=(const ArrayString& other) { if(this != &other) { Core::memoryCopy(data, other.data, sizeof(data)); B::length = other.length; } return *this; } template CError format(Args&&... args) { ArrayString s; return B::format(s, Core::forward(args)...); } CError replace(const B& search, const B& replace) { ArrayString s; return B::replace(s, search, replace); } using B::replace; }; template CError 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