#pragma once #include "Types.h" #include "BaseObj.h" #include "Util.h" #include "Vector.h" #include namespace ehs { enum class SearchPattern { LEFT_RIGHT, RIGHT_LEFT }; enum class IndexResult { BEGINNING, ENDING }; /// A helper class for C-style strings. /// @tparam T The character's data type to use. /// @tparam N The number data type to use. template class Str : public BaseObj { private: N size; T* data; public: /// Frees any data created on the heap. ~Str() override { delete[] data; } /// Default members initialization. Str() : size(0), data(nullptr) { AddType("Str"); } /// Initializes members with given C-style string. /// @param [in] str The C-style string. /// @param [in] size The size of the given C-style string. Str(const T* const str, const N size) : size((size) ? size : Len(str)), data(nullptr) { data = new T[this->size + 1]; Util::Copy(data, str, Size(true)); data[this->size] = 0; AddType("Str"); } /// Initializes members with given C-style string. /// @param [in] str The C-style string. Str(const T* const str) : size(Len(str)), data(nullptr) { data = new T[size + 1]; Util::Copy(data, str, Size(true)); data[size] = 0; AddType("Str"); } /// Initializes string with the given size. /// @param [in] size The size. Str(const N size) : size(size), data(new T[size + 1]) { data[size] = 0; AddType("Str"); } /// A move constructor. Str(Str&& str) noexcept : BaseObj((BaseObj&&)str), size(str.size), data(str.data) { str.size = 0; str.data = nullptr; } /// Copies all members from the given string object. /// @param [in] str The string object to copy from. Str(const Str& str) : BaseObj(str), size(str.size), data(new T[size + 1]) { Util::Copy(data, str.data, Size(true)); data[size] = 0; } Str& operator=(Str&& str) noexcept { if (this == &str) return *this; BaseObj::operator=((BaseObj&&)str); size = str.size; delete[] data; data = str.data; str.size = 0; str.data = nullptr; return *this; } /// Copies all members from the given string object. /// @param [in] str The string object to copy from. /// @returns The string that has been assigned to. Str& operator=(const Str& str) { if (&str == this) return *this; BaseObj::operator=(str); size = str.size; delete[] data; data = new T[size + 1]; Util::Copy(data, str.data, Size(true)); data[size] = 0; return *this; } /// Copies the given C-style string and retrieves the size. /// @param [in] str The C-style string to copy from. /// @returns The string object that has been assigned to. Str& operator=(const T* const str) { size = Len(str); delete[] data; data = new T[size + 1]; Util::Copy(data, str, Size(true)); data[size] = 0; return *this; } /// Concatenates with the given C-style string. /// @param [in] str The given C-style string. /// @returns The resulting string object. Str& operator+=(const T* const str) { N inputSize = Len(str); T* result = new T[size + inputSize + 1]; Util::Copy(result, data, Size(true)); delete[] data; Util::Copy(&result[size], str, inputSize * sizeof(T)); result[size + inputSize] = 0; size += inputSize; data = result; return *this; } /// Concatenates with the given string object. /// @param [in] str The given string object. /// @returns The resulting string object. Str& operator+=(const Str& str) { T* result = new T[size + str.size + 1]; Util::Copy(result, data, Size(true)); delete[] data; Util::Copy(&result[size], str, str.Size(true)); result[size + str.size] = 0; size += str.Size(); data = result; return *this; } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const SInt_64 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const UInt_64 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const SInt_32 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const UInt_32 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const SInt_16 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const UInt_16 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const SInt_8 num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const UInt_8 num) { return operator+=(FromNum(num)); } #ifdef EHS_OS_WINDOWS /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The result. Str& operator+=(const DWORD num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The result. Str& operator+=(const HRESULT num) { return operator+=(FromNum(num)); } #endif /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const float num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const double num) { return operator+=(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to concatenate. /// @returns The resulting string object. Str& operator+=(const long double num) { return operator+=(FromNum(num)); } /// Concatenates with the given C-style string. /// @param [in] str The given C-style string. /// @returns The resulting string object. Str operator+(const T* const str) const { N inSize = Len(str); Str result(size + inSize); Util::Copy(result.data, data, Size(true)); Util::Copy(&result.data[size], str, inSize * sizeof(T)); result.data[size + inSize] = 0; return result; } /// Concatenates with the given string object. /// @param [in] str The given string object. /// @returns The resulting string object. Str operator+(const Str& str) const { Str result(size + str.size); Util::Copy(result.data, data, Size(true)); Util::Copy(&result.data[size], str.data, str.Size(true)); result.data[size + str.size] = 0; return result; } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const SInt_64 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const UInt_64 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const SInt_32 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const UInt_32 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const SInt_16 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const UInt_16 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const SInt_8 num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const UInt_8 num) const { return operator+(FromNum(num)); } #ifdef EHS_OS_WINDOWS /// Concatenates with the given number. /// @param [in] str The given number to Concatenate. /// @returns The result. Str operator+(const DWORD num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] str The given number to Concatenate. /// @returns The result. Str operator+(const HRESULT num) const { return operator+(FromNum(num)); } #endif /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const float num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const double num) const { return operator+(FromNum(num)); } /// Concatenates with the given number. /// @param [in] num The given number to Concatenate. /// @returns The resulting string object. Str operator+(const long double num) const { return operator+(FromNum(num)); } /// Compares with a another string. First comparing sizes. /// @param [in] str The string object to compare with. /// @returns Whether or not they are equal. bool operator==(T* str) const { if (size != Len(str)) return false; return Util::Compare(data, str, Size(true)); } /// Compares with a C-style string. First comparing sizes. /// @param [in] str The C-style string to compare with. /// @returns Whether or not they are equal. bool operator==(const T* const str) const { if (size != Len(str)) return false; return Util::Compare(data, str, Size(true)); } /// Compares with a string object. First comparing sizes. /// @param [in] str The string object to compare with. /// @returns Whether or not they are equal. bool operator==(const Str& str) const { if (size != str.size) return false; return Util::Compare(data, str, Size(true)); } /// Compares with a C-style string. First comparing sizes. /// @param [in] str The C-style string to compare with. /// @returns Whether or not they are equal. bool operator!=(const T* const str) const { if (size != Len(str)) return true; return !Util::Compare(data, str, Size(true)); } /// Compares with a string object. First comparing sizes. /// @param [in] str The string to compare with. /// @returns Whether or not they are equal. bool operator!=(const Str& str) const { if (size != str.size) return true; return !Util::Compare(data, str, Size(true)); } /// Retrieves the raw C-style string from casting a string object. operator T* () const { return data; } /// Resizes the string. /// @param [in] newSize The size to change to. void Resize(const N newSize) { if (newSize == size) return; T* result = new T[newSize + 1]; if (newSize > size) Util::Copy(result, data, Size(true)); else Util::Copy(result, data, newSize * sizeof(T)); size = newSize; delete[] data; data = result; data[size] = 0; } /// Retrieves the size of the string. /// @param [in] inBytes To retrieve the size in bytes. /// @returns The resulting size. N Size(bool inBytes = false) const { if (inBytes) return sizeof(T) * size; else return size; } /// Finds the null terminator in the string and makes it the exact size if greater than. void ExactSize() { size = Len(data); T* result = new T[size + 1]; Util::Copy(result, data, Size(true)); delete[] data; result[size] = 0; data = result; } /// Copies a string object to the referenced string object. /// @param dstOffset The offset index to copy to. /// @param src The source string object to copy from. void Copy(const N dstOffset, const Str& src) { if (dstOffset + src.size > size) { //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(src.Size()) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ")."); return; } Util::Copy(data[dstOffset], src, src.Size(true)); } /// Copies a C-style string to the referenced string object. /// @param dstOffset The offset index to copy to. /// @param src The source C-style string to copy from. void Copy(const N dstOffset, const T* const src) { N srcSize = Len(src); if (dstOffset + srcSize > size) { //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(srcSize) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ")."); return; } Util::Copy(data[dstOffset], src, srcSize * sizeof(T)); } /// Copies a C-style string to the referenced string object. /// @param dstOffset The offset index to copy to. /// @param src The source C-style string to copy from. /// @param srcSize The size of the source C-style string. void Copy(const N dstOffset, const T* const src, const N srcSize) { if (dstOffset + srcSize > size) { //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The parameters \"dstOffset\" (" + Str_8::FromNum(dstOffset) + ") + \"srcSize\" (" + Str_8::FromNum(srcSize) + ") is greater than the referenced string object's size (" + Str_8::FromNum(size) + ")."); return; } Util::Copy(data[dstOffset], src, srcSize * sizeof(T)); } /// Inserts a string at a specified index. /// @param [in] index The index to insert the string at. /// @param [in] value The string to insert. void Insert(const N index, const Str& value) { if (!value.size) return; N newSize = size + value.size; T* result = new T[newSize + 1]; Util::Copy(result, data, index * sizeof(T)); Util::Copy(&result[index], value.data, value.Size(true)); Util::Copy(&result[index + value.size], &data[index], size - index); result[newSize] = 0; delete[] data; data = result; size = newSize; } /// Inserts a character at a specified index. /// @param [in] index The index to insert the character at. /// @param [in] value The character to insert. void Insert(const N index, const T value) { N newSize = 0; if (index > size - 1) newSize = size + ((index + 1) - size); else newSize = size + 1; T* result = new T[newSize + 1]; for (N i = 0; i < index; ++i) result[i] = data[i]; result[index] = value; for (N i = index; i < size; ++i) result[i + 1] = data[i]; result[newSize] = 0; delete[] data; data = result; size = newSize; } /// Removes characters withing the given range. /// @param [in] start The index to start. /// @param [in] end The index to end. /// @returns The removed string object. Str Remove(const N start, const N end) { if (!size || start >= size || end > size || end <= start) return {}; Str popped(&data[start], end - start); N newSize = size - popped.size; T* result = new T[newSize + 1]; Util::Copy(result, data, start * sizeof(T)); Util::Copy(&result[start], &data[end], (size - end) * sizeof(T)); result[newSize] = 0; delete[] data; data = result; size = newSize; return popped; } /// Removes a character at the given index. /// @param [in] index The index to remove a character. /// @returns The character removed. T Remove(const N index) { T popped = {}; if (!size || index >= size) return popped; popped = data[index]; N newSize = size - 1; T* result = new T[newSize]; for (N i = 0; i < index; ++i) result[i] = data[i]; for (N i = index + 1; i < size; ++i) result[i - 1] = data[i]; delete[] data; data = result; size = newSize; return popped; } /// Adds a value at the end of the string. /// @param [in] value The character to push to the end of the string. void Push(const Str &value) { T* result = new T[size + value.size + 1]; Util::Copy(result, data, Size(true)); Util::Copy(&result[size], value, value.Size(true)); result[size + value.Size()] = 0; delete[] data; data = result; size += value.size; } /// Adds a value at the end of the string. /// @param [in] value The C-style string to push to the end of the string. /// @param [in] size The size of the given C-style string. void Push(const T* const value, const N size) { T* result = new T[this->size + size + 1]; Util::Copy(result, data, Size(true)); Util::Copy(&result[this->size], value, size * sizeof(T)); result[this->size + size] = 0; delete[] data; data = result; this->size += size; } /// Adds a value at the end of the string. /// @param [in] value The C-style string to push to the end of the string. void Push(const T* const value) { N inSize = Len(value); T* result = new T[size + inSize + 1]; Util::Copy(result, data, Size(true)); Util::Copy(result[size], value, inSize * sizeof(T)); result[size + inSize] = 0; delete[] data; data = result; size += inSize; } /// Adds a value at the end of the string. /// @param [in] value The character to push to the end of the string. void Push(const T value) { T* result = new T[size + 2]; Util::Copy(result, data, Size(true)); result[size] = value; result[size + 1] = 0; delete[] data; data = result; ++size; } /// Removes the value at the end of the array. /// @returns The value that was popped. T Pop() { T* result = new T[size--]; T value = data[size]; Util::Copy(result, data, Size(true)); result[size] = 0; delete[] data; data = result; return value; } /// Retrieves the string in bytes for serialization. /// @returns The string in bytes. const Byte* ToBytes() const { return (Byte*)data; } /// Retrieves the string in bytes for serialization. /// @returns The string in bytes. Byte* ToBytes() { return (Byte*)data; } /// Converts all upper-case ASCII characters to lower-case. void ToLower() { for (N i = 0; i < size; ++i) if (data[i] > 64 && data[i] < 91) data[i] += 32; } /// Converts all upper-case ASCII characters to lower-case. /// @returns The resulting string object. Str GetLower() const { Str result(size); for (N i = 0; i < size; ++i) if (data[i] > 64 && data[i] < 91) result[i] = data[i] + 32; else result[i] = data[i]; return result; } /// Converts all lower-case ASCII characters to upper-case. void ToUpper() { for (N i = 0; i < size; ++i) if (data[i] > 96 && data[i] < 123) data[i] -= 32; } /// Converts all lower-case ASCII characters to upper-case. /// @returns The resulting string object. Str GetUpper() const { Str result(size); for (N i = 0; i < size; ++i) if (data[i] > 96 && data[i] < 123) result[i] = data[i] - 32; else result[i] = data[i]; return result; } /// Reverses the entire string object. void Reverse() { if (size <= 1 || !data) return; T* r = new T[size + 1]; for (N i = 0; i < size; ++i) r[i] = data[size - 1 - i]; r[size] = 0; delete[] data; data = r; } /// Reverses the entire string object. /// @returns The resulting string object. Str GetReverse() { if (size <= 1 || !data) return *this; Str r(size); for (N i = 0; i < size; ++i) r[i] = data[size - 1 - i]; return r; } /// Clips the string at the given index and with the given size. /// @param [in] index The index to clip at. /// @param [in] size The size for the clip starting from the index. /// @returns The resulting string object. Str Sub(const N index, const N size = 0) const { if (index >= this->size) { //Log_8 log(__FUNCSIG__, LogType::ERR, 0, "The given index parameter, \"" + Str::FromNum(index) + "\" is greater than the string's size, \"" + Str::FromNum(this->size) + "\"."); return Str(); } if (size) { if (size > this->size) { //Log_8 log(__FUNCSIG__, LogType::ERR, 1, "The given size parameter, \"" + Str::FromNum(size) + "\" is greater than the string's size, \"" + Str::FromNum(this->size) + "\", at the index, \"" + Str::FromNum(index) + "\"."); return Str(); } Str result(size); Util::Copy(result, &data[index], result.Size(true)); return result; } else { Str result(this->size - index); Util::Copy(result, &data[index], result.Size(true)); return result; } } /// Splits a string into a Vector with the given separator. /// @param [in] ide The given string as the separator. /// @param [in] max The max amount of times to split the string. /// @returns The resulting string object. Vector, N> Split(const Str& ide, const N max = 0) const { Vector, N> result(0, 5); N b = 0; for (N i = 0, c = 0; i < size; ++i) { if (data[i] == ide[c]) { if (++c == ide.Size()) { N r = i - (c - 1) - b; if (!r) result.Push(Str()); else result.Push(Str(&data[b], r)); b = i + 1; c = 0; if (max && result.Size() == max) break; } } else { c = 0; } } if (b < size) result.Push(Str(&data[b], size - b)); return result; } /// Removes all instances of the ide. /// @param [in] ide The string to look for. /// @returns The resulting string object. Str RemoveAll(const Str& ide) const { Str result(size); for (N i = 0, b = 0, c = 0; i < size; ++i) { if (data[i] == ide[c]) { if (++c == ide.Size()) c = 0; } else { if (c) for (N d = c; d < 0; --d) result[b++] = data[i - d]; else result[b++] = data[i]; c = 0; } } return result; } /// Replaces all instances of ide with the replacer. /// @param [in] ide The string to look for. /// @param [in] replacer The string placed. /// @returns The resulting string object. Str ReplaceAll(const Str& ide, const Str& replacer) const { Str result; for (N i = 0, b = 0; i < size; ++i) { if (data[i] == ide[b]) { if (++b == ide.Size()) { result.Push(replacer); b = 0; } } else { result.Push(data[i]); } } return result; } /// Finds the first instance of the given string object. /// @param [in] ide The string to look for. /// @param [out] index The index of the string found. Can be a nullptr. /// @param [in] pattern The search pattern for optimization. /// @param [in] result What index to return where the first instance is found. /// @returns The index where the instance was found with the result varying from the result parameter. bool Find(const Str& ide, N* const index = nullptr, const SearchPattern pattern = SearchPattern::LEFT_RIGHT, const IndexResult result = IndexResult::BEGINNING) const { if (pattern == SearchPattern::LEFT_RIGHT) { for (N i = 0, c = 0; i < size; ++i) { if (data[i] == ide[c]) { if (++c == ide.Size()) { if (result == IndexResult::BEGINNING) { if (index) *index = i - (c - 1); return true; } else { if (index) *index = i; return true; } } } } } else if (pattern == SearchPattern::RIGHT_LEFT) { for (N i = size, c = ide.Size(); i > 0; --i) { if (data[i - 1] == ide[c - 1]) { if (--c == 0) { if (result == IndexResult::BEGINNING) { if (index) *index = i - (ide.Size() - 1); return true; } else { if (index) *index = i; return true; } } } } } return false; } /// Checks if the current string contains the given ide. /// @param [in] ide The given ide to check for. /// @param [in] pattern The search pattern to use. /// @returns True if the current string does contain the ide. bool Contains(const Str& ide, const SearchPattern pattern = SearchPattern::LEFT_RIGHT) const { if (pattern == SearchPattern::LEFT_RIGHT) { for (N i = 0, c = 0; i < size; ++i) { if (data[i] == ide[c]) { if (++c == ide.Size()) { return true; } } } } else if (pattern == SearchPattern::RIGHT_LEFT) { for (N i = size, c = ide.Size(); i > 0; --i) { if (data[i - 1] == ide[c - 1]) { if (--c == 0) { return true; } } } } return false; } /// Checks if the string represents a number. Must not have any alphabetical characters. /// @returns The result. bool IsNum() const { if (!size) return false; if ((data[0] < '0' || data[0] > '9') && data[0] != '-' && data[0] != '.') return false; for (N i = 1; i < size; ++i) if ((data[i] < '0' || data[i] > '9') && data[i] != '.') return false; return true; } /// Converts a number into hexadecimal string representation. /// @tparam I The data type of the number given. /// @param [in] num The number to convert. /// @returns The resulting hexadecimal. template static Str NumToHex(const I num) { static const T hex[] = "0123456789ABCDEF"; Str result(sizeof(I) * 2); for (UInt_8 i = 0; i < sizeof(I); ++i) { result[i * 2] = hex[((Byte*)&num)[i] / 16]; result[i * 2 + 1] = hex[((Byte*)&num)[i] % 16]; } return result; } /// Converts a string hexadecimal into a number. /// @tparam I The data type of the number outputted. /// @param [in] in The string to convert. /// @returns The resulting number. template static I HexToNum(const Str& in) { N offset = 0; bool neg = false; if (in[offset] == 45) { neg = true; ++offset; } else if (in[offset] == 43) ++offset; if (in[offset] == 48 && (in[offset + 1] == 88 || in[offset + 1] == 120)) offset += 2; N acc = 0; for (N i = offset; i < in.Size(); ++i) { I value = 0; if (in[i] > 47 && in[i] < 58) value = in[i] - 48; else if (in[i] > 64 && in[i] < 71) value = in[i] - 55; else if (in[i] > 96 && in[i] < 103) value = in[i] - 87; if (value >= 16) return 0; acc *= 16; acc += value; } return neg ? -acc : acc; } /// Converts the current string from hexadecimal into a number. /// @tparam I The data type of the number outputted. /// @returns The resulting number. template I HexToNum() const { N offset = 0; bool neg = false; if (data[offset] == 45) { neg = true; ++offset; } else if (data[offset] == 43) ++offset; if (data[offset] == 48 && (data[offset + 1] == 88 || data[offset + 1] == 120)) offset += 2; N acc = 0; for (N i = offset; i < size; ++i) { I value = 0; if (data[i] > 47 && data[i] < 58) value = data[i] - 48; else if (data[i] > 64 && data[i] < 71) value = data[i] - 55; else if (data[i] > 96 && data[i] < 103) value = data[i] - 87; if (value >= 16) return 0; acc *= 16; acc += value; } return neg ? -acc : acc; } /// Converts the string into a number. /// @tparam I The resulting number's data type. /// @returns The result. /// @note Use "IsNum" before this if the string object is not guaranteed to be a number. template I ToDecimal() const { I r = 0; if (!size) return r; for (N i = data[0] == '-' ? 1 : 0; i < size; ++i) r = r * 10 + data[i] - '0'; if (data[0] == '-') r *= -1; return r; } /// Converts the string into a floating point number. /// @returns The resulting float. /// @note Use "IsNum" before this if the string object is not guaranteed to be a number. float ToFloat() const { N decPoint = size; Find(".", &decPoint); float result = 0.0f; float fraction = 0.0f; float scale = 1.0f; for (N i = 0; i < decPoint; ++i) result = result * 10.0f + data[i] - '0'; for (N i = decPoint + 1; i < size; ++i) { fraction = fraction * 10.0f + data[i] - '0'; scale *= 10.0f; } result += fraction / scale; return result; } /// Converts the string into a double floating point number. /// @returns The resulting double. /// @note Use "IsNum" before this if the string object is not guaranteed to be a number. double ToDouble() const { N decPoint = size; Find(".", &decPoint); double result = 0.0f; double fraction = 0.0f; double scale = 1.0f; for (N i = 0; i < decPoint; ++i) result = result * 10.0f + data[i] - '0'; for (N i = decPoint + 1; i < size; ++i) { fraction = fraction * 10.0f + data[i] - '0'; scale *= 10.0f; } result += fraction / scale; return result; } /// Converts the string into a long double floating point number. /// @returns The resulting long double. /// @note Use "IsNum" before this if the string object is not guaranteed to be a number. long double ToLDouble() const { N decPoint = size; Find(".", &decPoint); long double result = 0.0f; long double fraction = 0.0f; long double scale = 1.0f; for (N i = 0; i < decPoint; ++i) result = result * 10.0f + data[i] - '0'; for (N i = decPoint + 1; i < size; ++i) { fraction = fraction * 10.0f + data[i] - '0'; scale *= 10.0f; } result += fraction / scale; return result; } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const SInt_64 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(21); SInt_64 nonNeg; if (num < 0) nonNeg = -num; else nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } if (num < 0) r[i++] = 45; r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const UInt_64 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(21); UInt_64 nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const SInt_32 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(11); SInt_32 nonNeg; if (num < 0) nonNeg = -num; else nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } if (num < 0) r[i++] = 45; r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const UInt_32 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(11); UInt_32 nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const SInt_16 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(6); SInt_16 nonNeg; if (num < 0) nonNeg = -num; else nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } if (num < 0) r[i++] = 45; r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const UInt_16 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(6); UInt_16 nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const SInt_8 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(4); SInt_8 nonNeg; if (num < 0) nonNeg = -num; else nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } if (num < 0) r[i++] = 45; r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @param [in] num The given number to convert. /// @returns The resulting string representation. static Str FromNum(const UInt_8 num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(4); UInt_8 nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } r.Resize(i); return r.GetReverse(); } #ifdef EHS_OS_WINDOWS /// Converts the given number into a string. /// @returns The result. static Str FromNum(const DWORD num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(11); DWORD nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } r.Resize(i); return r.GetReverse(); } /// Converts the given number into a string. /// @returns The result. static Str FromNum(const HRESULT num) { if (num == 0) { Str z(1); z[0] = 48; return z; } Str r(11); HRESULT nonNeg; if (num < 0) nonNeg = -num; else nonNeg = num; N i = 0; while (nonNeg != 0) { r[i++] = 48 + nonNeg % 10; nonNeg /= 10; } if (num < 0) r[i++] = 45; r.Resize(i); return r.GetReverse(); } #endif /// Converts the given floating point into a string. /// @param [in] num The given floating point to convert. /// @param [in] maxDecimals The max decimal places to add. /// @returns The resulting string representation. static Str FromNum(const float num, const UInt_8 maxDecimals = 5) { SInt_64 whole = (SInt_64)num; Str result; if (whole < 0) result += "-"; result += Str::FromNum(whole); UInt_64 power = 10; for (UInt_64 i = 0; i < (UInt_64)maxDecimals - 1; ++i) power *= 10; SInt_64 fraction = (SInt_64)((num - (float)whole) * (float)power); if (!fraction) return result; result += "."; Str fResult(maxDecimals); N i = 0; while (fraction) { fResult[i++] = 48 + fraction % 10; fraction /= 10; } while (i < maxDecimals) fResult[i++] = 48; fResult.Reverse(); result += fResult; return result; } /// Converts the given double floating point into a string. /// @param [in] num The given double floating point to convert. /// @param [in] maxDecimals The max decimal places to add. /// @returns The resulting string representation. static Str FromNum(const double num, const UInt_8 maxDecimals = 5) { SInt_64 whole = (SInt_64)num; Str result; if (whole < 0) result += "-"; result += Str::FromNum(whole); UInt_64 power = 10; for (UInt_64 i = 0; i < (UInt_64)maxDecimals - 1; ++i) power *= 10; SInt_64 fraction = (SInt_64)((num - (double)whole) * (double)power); if (!fraction) return result; result += "."; Str fResult(maxDecimals); N i = 0; while (fraction) { fResult[i++] = 48 + fraction % 10; fraction /= 10; } while (i < maxDecimals) fResult[i++] = 48; fResult.Reverse(); result += fResult; return result; } /// Converts the given long double floating point into a string. /// @param [in] num The given long double floating point to convert. /// @param [in] maxDecimals The max decimal places to add. /// @returns The resulting string representation. static Str FromNum(const long double num, const UInt_8 maxDecimals = 5) { SInt_64 whole = (SInt_64)num; Str result; if (whole < 0) result += "-"; result += Str::FromNum(whole); UInt_64 power = 10; for (UInt_64 i = 0; i < (UInt_64)maxDecimals - 1; ++i) power *= 10; SInt_64 fraction = (SInt_64)((num - (long double)whole) * (long double)power); if (!fraction) return result; result += "."; Str fResult(maxDecimals); N i = 0; while (fraction) { fResult[i++] = 48 + fraction % 10; fraction /= 10; } while (i < maxDecimals) fResult[i++] = 48; fResult.Reverse(); result += fResult; return result; } /// A 32-bit FNV-1a hash algorithm. /// @param [in] str The string to hash. /// @returns The resulting hash. Zero if string does not contain any characters. static UInt_32 Hash_32(const Str& str) { if (!str.Size()) return 0; const Byte* const bytes = str.ToBytes(); UInt_32 hash = 2166136261ul; for (N i = 0; i < str.Size(true); ++i) hash = (hash ^ bytes[i]) * 16777619; return hash; } /// A 32-bit FNV-1a hash algorithm. /// @returns The resulting hash. Zero if string does not contain any characters. UInt_32 Hash_32() const { if (!size) return 0; const Byte* const bytes = ToBytes(); UInt_32 hash = 2166136261ul; for (N i = 0; i < Size(true); ++i) hash = (hash ^ bytes[i]) * 16777619; return hash; } /// A 64-bit FNV-1a hash algorithm. /// @param [in] str The string to hash. /// @returns The resulting hash. Zero if string does not contain any characters. static UInt_64 Hash_64(const Str& str) { if (!str.Size()) return 0; const Byte* const bytes = str.ToBytes(); UInt_64 hash = 14695981039346656037ull; for (N i = 0; i < str.Size(true); ++i) hash = (hash ^ bytes[i]) * 1099511628211; return hash; } /// A 64-bit FNV-1a hash algorithm. /// @returns The resulting hash. Zero if string does not contain any characters. UInt_64 Hash_64() const { if (!size) return 0; const Byte* const bytes = ToBytes(); UInt_64 hash = 14695981039346656037ull; for (N i = 0; i < Size(true); ++i) hash = (hash ^ bytes[i]) * 1099511628211; return hash; } /// Calculates the length of a C-Style string. /// @param [in] str The C-Style string to calculate. /// @returns The character count. static N Len(const T* const str) { N count = 0; while (str[count]) ++count; return count; } /// Compares two C-style string with each other. /// @param [in] a The first C-style string to compare. /// @param [in] b The second C-style string to compare. /// @returns True if both C-style strings are equal. static bool Cmp(const T* const a, const T* const b) { N aSize = Len(a); N bSize = Len(b); if (aSize != bSize) return false; return Util::Compare(a, b, aSize); } }; typedef Str Str_32; typedef Str Str_16; typedef Str Str_8; } template bool operator==(const T* const first, const ehs::Str& second) { N inSize = ehs::Str::Len(first); if (second.Size() != inSize) return false; return ehs::Util::Compare(first, second, second.Size(true)); } template bool operator!=(const T* const first, const ehs::Str& second) { N inSize = ehs::Str::Len(first); if (second.Size() != inSize) return true; return !ehs::Util::Compare(first, second, second.Size(true)); } /// Concatenates a C-style string with a string. /// @param [in] first The given C-style string. /// @param [in] second The given string. /// @returns The result. template ehs::Str operator+(const T* const first, const ehs::Str& second) { N inSize = ehs::Str::Len(first); ehs::Str result(inSize + second.Size()); ehs::Util::Copy(result, first, inSize * sizeof(T)); ehs::Util::Copy(&result[inSize], &second[0], second.Size(true)); result[inSize + second.Size()] = 0; return result; }