#include "core/utils/ArrayString.hpp" #include "core/utils/Error.hpp" using CharString = Core::CharString; using Error = Core::Error; static c32 read(const char*& s) { if(*s == '\0') { return 0; } return static_cast(*(s++)); } Error Core::readUnicode(c32& u, const char*& s) { u = read(s); if((u & 0x80) == 0) { return Error::NONE; } if((u & 0xE0) == 0xC0) { c32 u2 = read(s); if(u2 == 0) { return Error::INVALID_CHAR; } u = ((u & 0x1F) << 6) | (u2 & 0x3F); return Error::NONE; } else if((u & 0xF0) == 0xE0) { c32 u2 = read(s); c32 u3 = read(s); if(u2 == 0 || u3 == 0) { return Error::INVALID_CHAR; } u = ((u & 0xF) << 12) | ((u2 & 0x3F) << 6) | (u3 & 0x3F); return Error::NONE; } else if((u & 0xF8) == 0xF0) { c32 u2 = read(s); c32 u3 = read(s); c32 u4 = read(s); if(u2 == 0 || u3 == 0 || u4 == 0) { return Error::INVALID_CHAR; } u = ((u & 0x07) << 18) | ((u2 & 0x3F) << 12) | ((u3 & 0x3F) << 6) | (u4 & 0x3F); return Error::NONE; } return Error::INVALID_CHAR; } template 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(((c >> 0) & 0x7F) | 0x0); buffer[1] = '\0'; } else if(c < (1 << 11)) { buffer[0] = static_cast(((c >> 6) & 0x1F) | 0xC0); buffer[1] = static_cast(((c >> 0) & 0x3F) | 0x80); buffer[2] = '\0'; } else if(c < (1 << 16)) { buffer[0] = static_cast(((c >> 12) & 0x0F) | 0xE0); buffer[1] = static_cast(((c >> 6) & 0x3F) | 0x80); buffer[2] = static_cast(((c >> 0) & 0x3F) | 0x80); buffer[3] = '\0'; } else if(c < (1 << 21)) { buffer[0] = static_cast(((c >> 18) & 0x07) | 0xF0); buffer[1] = static_cast(((c >> 12) & 0x3F) | 0x80); buffer[2] = static_cast(((c >> 6) & 0x3F) | 0x80); buffer[3] = static_cast(((c >> 0) & 0x3F) | 0x80); buffer[4] = '\0'; } } CharString::CharString(char* buffer, i32 bufferSize) : length(0), capacity(bufferSize), hash(0), data(buffer) { data[0] = '\0'; } Error CharString::copyFrom(const CharString& s) { clear(); return s.toString(*this); } bool CharString::operator==(const char* s) const { const char* p = data; while(*s == *p && *s != '\0') { s++; p++; } return *s == *p; } bool CharString::operator==(const CharString& 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 CharString::operator!=(const char* s) const { return !((*this) == s); } bool CharString::operator!=(const CharString& other) const { return !((*this) == other); } char CharString::operator[](int index) const { return data[index]; } int CharString::getLength() const { return length; } int CharString::getCapacity() const { return capacity - 1; } Error CharString::append(char c) { if(length >= capacity - 1) { return Error::CAPACITY_REACHED; } data[length++] = c; data[length] = '\0'; addToHash(static_cast(c)); return Error::NONE; } Error CharString::append(signed char c) { return append(static_cast(c)); } Error CharString::append(unsigned char c) { return append(static_cast(c)); } Error CharString::append(wchar_t c) { return append(static_cast(c)); } Error CharString::append(c32 c) { char buffer[5]; unicodeToChar(c, buffer); return append(static_cast(buffer)); } Error CharString::append(const char* 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 CharString::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 CharString::append(const signed char* s) { return append(reinterpret_cast(s)); } Error CharString::append(const unsigned char* s) { return append(reinterpret_cast(s)); } 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; } void CharString::clear() { length = 0; hash = 0; data[0] = '\0'; } u32 CharString::hashCode() const { return hash; } Error CharString::print() const { for(int i = 0; i < length; i++) { CORE_RETURN_ERROR(Core::putChar(data[i])); } return Error::NONE; } Error CharString::printLine() const { CORE_RETURN_ERROR(print()); CORE_RETURN_ERROR(Core::putChar('\n')); return Error::NONE; } bool CharString::startsWidth(const CharString& 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 CharString::search(const CharString& other, int from) const { for(int i = from; i < length; i++) { if(startsWidth(other, i)) { return i; } } return -1; } bool CharString::contains(const CharString& other, int from) const { return search(other, from) >= 0; } int CharString::search(char u, int from) const { for(int i = from; i < length; i++) { if(data[i] == u) { return i; } } return -1; } bool CharString::contains(char u, int from) const { return search(u, from) >= 0; } Error CharString::substring(CharString& 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 CharString::substring(CharString& s, int from) const { return substring(s, from, length - 1); } Error CharString::replace(CharString& s, const CharString& search, const CharString& 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 CharString::replace(char search, char replace) { hash = 0; for(int i = 0; i < length; i++) { if(data[i] == search) { data[i] = replace; } addToHash(static_cast(data[i])); } } CharString::operator const char*() const { return data; } void CharString::addToHash(c32 u) { hash = static_cast(2120251889) * hash + static_cast(u); } Error CharString::formatBuffer(CharString& s, int index) { while(index < length) { CORE_RETURN_ERROR(s.append(data[index++])); } return Error::NONE; }