EHS/include/ehs/Str.h

1937 lines
46 KiB
C
Raw Normal View History

2024-02-05 22:25:30 -08:00
#pragma once
#include "Types.h"
#include "BaseObj.h"
#include "Util.h"
#include "Vector.h"
#include <utility>
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<typename T = Char_8, typename N = UInt_64>
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<T, N>& 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<T, N>& 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<T, N>& operator+=(const Str<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N> operator+(const T* const str) const
{
N inSize = Len(str);
Str<T, N> 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<T, N> operator+(const Str<T, N>& str) const
{
Str<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N> 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<T, N>& 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<T, N>& 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<T, N>& 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<T, N> &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<T, N> GetLower() const
{
Str<T, N> 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<T, N> GetUpper() const
{
Str<T, N> 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<T, N> GetReverse()
{
if (size <= 1 || !data)
return *this;
Str<T, N> 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<T, N> 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<T, N>::FromNum(index) + "\" is greater than the string's size, \"" + Str<T, N>::FromNum(this->size) + "\".");
return Str<T, N>();
}
if (size)
{
if (size > this->size)
{
//Log_8 log(__FUNCSIG__, LogType::ERR, 1, "The given size parameter, \"" + Str<T, N>::FromNum(size) + "\" is greater than the string's size, \"" + Str<T, N>::FromNum(this->size) + "\", at the index, \"" + Str<T, N>::FromNum(index) + "\".");
return Str<T, N>();
}
Str<T, N> result(size);
Util::Copy(result, &data[index], result.Size(true));
return result;
}
else
{
Str<T, N> 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<Str<T, N>, N> Split(const Str<T, N>& ide, const N max = 0) const
{
Vector<Str<T, N>, 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<T, N>());
else
result.Push(Str<T, N>(&data[b], r));
b = i + 1;
c = 0;
if (max && result.Size() == max)
break;
}
}
else
{
c = 0;
}
}
if (b < size)
result.Push(Str<T, N>(&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<T, N> RemoveAll(const Str<T, N>& ide) const
{
Str<T, N> 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<T, N> 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<T, N>& 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<T, N>& 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<typename I = int>
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<typename I = int>
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<typename I = int>
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<typename I = N>
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<T, N> FromNum(const SInt_64 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const UInt_64 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const SInt_32 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const UInt_32 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const SInt_16 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const UInt_16 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const SInt_8 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const UInt_8 num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const DWORD num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const HRESULT num)
{
if (num == 0)
{
Str<T, N> z(1);
z[0] = 48;
return z;
}
Str<T, N> 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<T, N> FromNum(const float num, const UInt_8 maxDecimals = 5)
{
SInt_64 whole = (SInt_64)num;
Str<T, N> result;
if (whole < 0)
result += "-";
result += Str<T, N>::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<T, N> 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<T, N> FromNum(const double num, const UInt_8 maxDecimals = 5)
{
SInt_64 whole = (SInt_64)num;
Str<T, N> result;
if (whole < 0)
result += "-";
result += Str<T, N>::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<T, N> 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<T, N> FromNum(const long double num, const UInt_8 maxDecimals = 5)
{
SInt_64 whole = (SInt_64)num;
Str<T, N> result;
if (whole < 0)
result += "-";
result += Str<T, N>::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<T, N> 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<T, N>& str)
{
2024-02-05 22:25:30 -08:00
if (!str.Size())
return 0;
const Byte* const bytes = str.ToBytes();
2024-02-05 22:25:30 -08:00
UInt_32 hash = 2166136261ul;
2024-02-05 22:25:30 -08:00
for (N i = 0; i < str.Size(true); ++i)
hash = (hash ^ bytes[i]) * 16777619;
2024-02-05 22:25:30 -08:00
return hash;
}
2024-02-05 22:25:30 -08:00
/// 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.
2024-02-05 22:25:30 -08:00
/// @returns The resulting hash. Zero if string does not contain any characters.
static UInt_64 Hash_64(const Str<T, N>& str)
{
2024-02-05 22:25:30 -08:00
if (!str.Size())
return 0;
const Byte* const bytes = str.ToBytes();
2024-02-05 22:25:30 -08:00
UInt_64 hash = 14695981039346656037ull;
2024-02-05 22:25:30 -08:00
for (N i = 0; i < str.Size(true); ++i)
hash = (hash ^ bytes[i]) * 1099511628211;
2024-02-05 22:25:30 -08:00
return hash;
}
2024-02-05 22:25:30 -08:00
/// 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;
2024-07-03 19:49:18 -07:00
return Util::Compare(a, b, aSize);
2024-02-05 22:25:30 -08:00
}
};
2024-07-21 10:45:06 -07:00
EHS_LIB_IO typedef Str<Char_32, UInt_64> Str_32;
EHS_LIB_IO typedef Str<Char_16, UInt_64> Str_16;
EHS_LIB_IO typedef Str<Char_8, UInt_64> Str_8;
2024-02-05 22:25:30 -08:00
}
template<typename T = ehs::Char_8, typename N = ehs::UInt_64>
bool operator==(const T* const first, const ehs::Str<T, N>& second)
{
N inSize = ehs::Str<T, N>::Len(first);
if (second.Size() != inSize)
return false;
return ehs::Util::Compare(first, second, second.Size(true));
}
template<typename T = ehs::Char_8, typename N = ehs::UInt_64>
bool operator!=(const T* const first, const ehs::Str<T, N>& second)
{
N inSize = ehs::Str<T, N>::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<typename T = ehs::Char_8, typename N = ehs::UInt_64>
ehs::Str<T, N> operator+(const T* const first, const ehs::Str<T, N>& second)
{
N inSize = ehs::Str<T, N>::Len(first);
ehs::Str<T, N> 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;
}