#include "core/utils/ArrayString.hpp" #include #include #include #include "core/data/Array.hpp" #include "core/math/Math.hpp" #include "core/utils/Error.hpp" #include "core/utils/Utility.hpp" using CharString = Core::CharString; using Char32String = Core::Char32String; using Error = Core::Error; namespace ErrorCode = Core::ErrorCode; constexpr size_t stringLength(const c32* c) { const c32* i = c + 1; while(*(c++) != '\0') {} return static_cast(c - i); } static Error readUnicode(c32& u, const char*& s) { size_t limit = MB_CUR_MAX; size_t n = mbrtoc32(&u, s, limit, nullptr); if(n > limit) { return ErrorCode::INVALID_CHAR; } s += n; return ErrorCode::NONE; } using C32Buffer = Core::Array; static Error convertC32(C32Buffer& buffer, c32 c) { size_t n = c32rtomb(buffer.begin(), c, nullptr); if(n >= buffer.getLength()) { return ErrorCode::INVALID_CHAR; } buffer[n] = '\0'; return ErrorCode::NONE; } CharString::CharString(char* buffer, size_t bufferSize) : length(0), capacity(bufferSize <= 0 ? 0 : bufferSize - 1), data(buffer) { data[0] = '\0'; } Error CharString::copyFrom(const CharString& s) { clear(); return s.toString(*this); } bool CharString::operator==(const char* s) const { return strcmp(data, s) == 0; } bool CharString::operator==(const CharString& other) const { return length == other.length && strcmp(data, other.data) == 0; } bool CharString::operator!=(const char* s) const { return !((*this) == s); } bool CharString::operator!=(const CharString& other) const { return !((*this) == other); } char CharString::operator[](size_t index) const { return data[index]; } size_t CharString::getLength() const { return length; } size_t CharString::getCapacity() const { return capacity; } Error CharString::append(char c) { if(length >= capacity) { return ErrorCode::CAPACITY_REACHED; } data[length++] = c; data[length] = '\0'; return ErrorCode::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) { C32Buffer buffer; CORE_RETURN_ERROR(convertC32(buffer, c)); return append(static_cast(buffer.begin())); } Error CharString::append(const char* s) { // stringLength as s could be some part of data for(size_t i = strlen(s); i > 0; i--) { CORE_RETURN_ERROR(append(*(s++))); } return ErrorCode::NONE; } Error CharString::append(const c32* s) { // stringLength as s could be some part of data for(size_t i = stringLength(s); i > 0; i--) { CORE_RETURN_ERROR(append(*(s++))); } return ErrorCode::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::toString(CharString& s) const { size_t l = length; // length changes if &s == this for(size_t i = 0; i < l; i++) { CORE_RETURN_ERROR(s.append(data[i])); } return ErrorCode::NONE; } Error CharString::toString(Char32String& s) const { return s.append(static_cast(data)); } void CharString::clear() { length = 0; data[0] = '\0'; } void CharString::print() const { Core::print(data); } void CharString::printLine() const { Core::printLine(data); } bool CharString::startsWith(const CharString& other, size_t from) const { return length >= from + other.getLength() && strncmp(data + from, other.data, other.getLength()) == 0; } size_t CharString::search(const CharString& other, size_t from) const { char* f = strstr(data + from, other.data); return f == nullptr ? SIZE_MAX : static_cast(f - data); } bool CharString::contains(const CharString& other, size_t from) const { return search(other, from) != SIZE_MAX; } size_t CharString::search(char u, size_t from) const { char* f = strchr(data + from, u); return f == nullptr ? SIZE_MAX : static_cast(f - data); } bool CharString::contains(char u, size_t from) const { return search(u, from) != SIZE_MAX; } Error CharString::substring(CharString& s, size_t from, size_t to) const { s.clear(); to = Math::min(to + 1, length); for(size_t i = from; i < to; i++) { CORE_RETURN_ERROR(s.append(data[i])); } return ErrorCode::NONE; } Error CharString::substring(CharString& s, size_t from) const { return substring(s, from, length - 1); } Error CharString::replace(CharString& s, const CharString& search, const CharString& replace) { size_t i = 0; while(i < length) { if(startsWith(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) { for(size_t i = 0; i < length; i++) { if(data[i] == search) { data[i] = replace; } } } CharString::operator const char*() const { return data; } Char32String::Char32String(c32* buffer, size_t bufferSize) : length(0), capacity(bufferSize <= 0 ? 0 : bufferSize - 1), 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(size_t 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[](size_t index) const { return data[index]; } size_t Char32String::getLength() const { return length; } size_t Char32String::getCapacity() const { return capacity; } Error Char32String::append(char c) { return append(static_cast(c)); } Error Char32String::append(signed char c) { return append(static_cast(c)); } Error Char32String::append(unsigned char c) { return append(static_cast(c)); } Error Char32String::append(wchar_t c) { return append(static_cast(c)); } Error Char32String::append(c32 c) { if(length >= capacity) { return ErrorCode::CAPACITY_REACHED; } data[length++] = c; data[length] = '\0'; 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(size_t 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(s)); } Error Char32String::append(const unsigned char* s) { return append(reinterpret_cast(s)); } Error Char32String::append(bool b) { return b ? append("true") : append("false"); } Error Char32String::toString(CharString& s) const { size_t l = length; // length changes if &s == this for(size_t i = 0; i < l; i++) { CORE_RETURN_ERROR(s.append(data[i])); } return ErrorCode::NONE; } Error Char32String::toString(Char32String& s) const { size_t l = length; // length changes if &s == this for(size_t i = 0; i < l; i++) { CORE_RETURN_ERROR(s.append(data[i])); } return ErrorCode::NONE; } void Char32String::clear() { length = 0; data[0] = '\0'; } void Char32String::print() const { for(size_t i = 0; i < length; i++) { C32Buffer buffer; if(convertC32(buffer, data[i]).check()) { Core::print('?'); } else { Core::print(buffer.begin()); } } } void Char32String::printLine() const { print(); Core::print('\n'); } bool Char32String::startsWith(const Char32String& other, size_t from) const { if(from + other.getLength() > length) { return false; } for(size_t i = 0; i < other.getLength(); i++) { if(data[from + i] != other[i]) { return false; } } return true; } size_t Char32String::search(const Char32String& other, size_t from) const { for(size_t i = from; i < length; i++) { if(startsWith(other, i)) { return i; } } return SIZE_MAX; } bool Char32String::contains(const Char32String& other, size_t from) const { return search(other, from) != SIZE_MAX; } size_t Char32String::search(c32 u, size_t from) const { for(size_t i = from; i < length; i++) { if(data[i] == u) { return i; } } return SIZE_MAX; } bool Char32String::contains(c32 u, size_t from) const { return search(u, from) != SIZE_MAX; } Error Char32String::substring(Char32String& s, size_t from, size_t to) const { s.clear(); to = Math::min(to + 1, length); for(size_t i = from; i < to; i++) { CORE_RETURN_ERROR(s.append(data[i])); } return ErrorCode::NONE; } Error Char32String::substring(Char32String& s, size_t from) const { return substring(s, from, length - 1); } Error Char32String::replace(Char32String& s, const Char32String& search, const Char32String& replace) { size_t i = 0; while(i < length) { if(startsWith(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) { for(size_t i = 0; i < length; i++) { if(data[i] == search) { data[i] = replace; } } } Char32String::operator const c32*() const { return data; }