mirror of
https://github.com/Mauler125/r5sdk.git
synced 2025-02-09 19:15:03 +01:00
1670 lines
53 KiB
C++
1670 lines
53 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <string_view>
|
|
#include <stdarg.h>
|
|
#include <Windows.h>
|
|
#include "stdext.h"
|
|
#include "ListBase.h"
|
|
#include "ImmutableStringBase.h"
|
|
|
|
template<class Tchar>
|
|
class StringBase
|
|
{
|
|
public:
|
|
constexpr StringBase();
|
|
constexpr StringBase(const uint32_t InitialSize, const Tchar InitialValue = (Tchar)'\0\0', const bool Initialized = true);
|
|
constexpr StringBase(const Tchar* Value);
|
|
constexpr StringBase(const Tchar* Value, size_t ValueSize);
|
|
constexpr StringBase(std::basic_string_view<Tchar> Value);
|
|
constexpr StringBase(ImmutableStringBase<Tchar> Value);
|
|
|
|
template<size_t Size>
|
|
constexpr StringBase(const Tchar(&Value)[Size]);
|
|
|
|
constexpr StringBase(const StringBase& Value);
|
|
constexpr StringBase(StringBase&& Value) noexcept;
|
|
|
|
~StringBase();
|
|
|
|
// Returns a null-terminated string
|
|
constexpr const Tchar* ToCString() const;
|
|
// Returns a copy of the current instance
|
|
constexpr StringBase<char> ToString() const;
|
|
// Returns a wide copy of the current instance
|
|
constexpr StringBase<wchar_t> ToWString() const;
|
|
// Returns a string_view of the current instance
|
|
constexpr std::basic_string_view<Tchar> ToStringView() const;
|
|
// Returns the length of the string in characters
|
|
constexpr uint32_t Length() const;
|
|
|
|
// Checks the string for equality, returns 0 when a match is found
|
|
constexpr int32_t Compare(const Tchar* Rhs) const noexcept;
|
|
// Checks the string for equality, returns 0 when a match is found
|
|
constexpr int32_t Compare(const StringBase<Tchar>& Rhs) const noexcept;
|
|
// Checks the string for equality, returns 0 when a match is found
|
|
constexpr int32_t Compare(std::basic_string_view<Tchar> Rhs) const noexcept;
|
|
|
|
// Creates an array of strings by splitting this string at each occurrence of the separator
|
|
constexpr List<StringBase<Tchar>> Split(const Tchar Separator) const;
|
|
// Creates an array of strings by splitting this string at each occurrence of the separator
|
|
constexpr List<StringBase<Tchar>> Split(const Tchar* Separator) const;
|
|
// Creates an array of strings by splitting this string at each occurrence of the separator
|
|
constexpr List<StringBase<Tchar>> Split(const StringBase<Tchar>& Separator) const;
|
|
// Creates an array of strings by splitting this string at each occurrence of the separator
|
|
constexpr List<StringBase<Tchar>> Split(const std::basic_string_view<Tchar> Separator) const;
|
|
|
|
// Trims the whitespace from both ends of the string
|
|
constexpr StringBase<Tchar> Trim() const;
|
|
// Trims the whitespace from the start of the string
|
|
constexpr StringBase<Tchar> TrimStart() const;
|
|
// Trims the whitespace from the end of the string
|
|
constexpr StringBase<Tchar> TrimEnd() const;
|
|
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(const Tchar Rhs, uint32_t Pos = 0) const noexcept;
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(const Tchar* Rhs, uint32_t Pos = 0) const;
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(const Tchar* Rhs, uint32_t Pos, uint32_t Count) const;
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos = 0) const noexcept;
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos, uint32_t Count) const noexcept;
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos = 0) const noexcept;
|
|
// Returns the index of the first occurrence of value in the current instance
|
|
constexpr uint32_t IndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos, uint32_t Count) const noexcept;
|
|
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(const Tchar Rhs, uint32_t Pos = 0) const noexcept;
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(const Tchar* Rhs, uint32_t Pos = 0) const;
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(const Tchar* Rhs, uint32_t Pos, uint32_t Count) const;
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos = 0) const noexcept;
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos, uint32_t Count) const noexcept;
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos = 0) const noexcept;
|
|
// Returns the index of the last occurrence of value in the current instance
|
|
constexpr uint32_t LastIndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos, uint32_t Count) const noexcept;
|
|
|
|
// Creates a copy of this string in lower case
|
|
constexpr StringBase<Tchar> ToLower() const;
|
|
// Creates a copy of this string in upper case
|
|
constexpr StringBase<Tchar> ToUpper() const;
|
|
|
|
// Replaces all instances of the Old value with New
|
|
constexpr StringBase<Tchar> Replace(const Tchar Old, const Tchar New) const;
|
|
// Replaces all instances of the Old value with New
|
|
constexpr StringBase<Tchar> Replace(const Tchar* Old, const Tchar* New) const;
|
|
// Replaces all instances of the Old value with New
|
|
constexpr StringBase<Tchar> Replace(const StringBase<Tchar>& Old, const StringBase<Tchar>& New) const;
|
|
// Replaces all instances of the Old value with New
|
|
constexpr StringBase<Tchar> Replace(std::basic_string_view<Tchar> Old, std::basic_string_view<Tchar> New) const;
|
|
|
|
// Whether or not the string starts with the value
|
|
constexpr bool StartsWith(const Tchar* Rhs) const;
|
|
// Whether or not the string starts with the value
|
|
constexpr bool StartsWith(const StringBase<Tchar>& Rhs) const;
|
|
// Whether or not the string starts with the value
|
|
constexpr bool StartsWith(std::basic_string_view<Tchar> Rhs) const;
|
|
|
|
// Whether or not the string ends with the value
|
|
constexpr bool EndsWith(const Tchar* Rhs) const;
|
|
// Whether or not the string ends with the value
|
|
constexpr bool EndsWith(const StringBase<Tchar>& Rhs) const;
|
|
// Whether or not the string ends with the value
|
|
constexpr bool EndsWith(std::basic_string_view<Tchar> Rhs) const;
|
|
|
|
// Whether or not the string contains the value
|
|
constexpr bool Contains(const Tchar* Rhs) const;
|
|
// Whether or not the string contains the value
|
|
constexpr bool Contains(const StringBase<Tchar>& Rhs) const;
|
|
// Whether or not the string contains the value
|
|
constexpr bool Contains(std::basic_string_view<Tchar> Rhs) const;
|
|
|
|
// Returns a substring of this string
|
|
constexpr StringBase<Tchar> SubString(uint32_t StartIndex) const;
|
|
// Returns a substring of this string
|
|
constexpr StringBase<Tchar> SubString(uint32_t StartIndex, uint32_t Length) const;
|
|
|
|
// Appends a character to this string
|
|
constexpr void Append(Tchar Rhs);
|
|
// Appends a null-terminated string to this string
|
|
constexpr void Append(const Tchar* Rhs);
|
|
// Appends a predetermined size string to this string
|
|
constexpr void Append(Tchar* Rhs, uint32_t Count);
|
|
// Appends a string to this string
|
|
constexpr void Append(const StringBase<Tchar>& Rhs);
|
|
|
|
// Standard logical casts
|
|
constexpr operator Tchar*(void) const;
|
|
constexpr operator const Tchar*(void) const;
|
|
|
|
// Cast to string_view
|
|
constexpr operator std::basic_string_view<Tchar>(void) const; // NOTE: Breaks intellisense but IS defined and DOES function...
|
|
|
|
// Iterator definitions, for for(& :) loop
|
|
constexpr Tchar* begin() const noexcept;
|
|
constexpr Tchar* end() const noexcept;
|
|
|
|
// Standard logical operators
|
|
constexpr StringBase<Tchar>& operator+=(const Tchar Rhs);
|
|
constexpr StringBase<Tchar>& operator+=(const Tchar* Rhs);
|
|
constexpr StringBase<Tchar>& operator+=(const StringBase<Tchar>& Rhs);
|
|
constexpr StringBase<Tchar>& operator+=(std::basic_string_view<Tchar> Rhs);
|
|
constexpr StringBase<Tchar>& operator+=(ImmutableStringBase<Tchar> Rhs);
|
|
|
|
// Assignment operators
|
|
constexpr StringBase<Tchar>& operator=(const Tchar* Rhs);
|
|
constexpr StringBase<Tchar>& operator=(const StringBase<Tchar>& Rhs);
|
|
constexpr StringBase<Tchar>& operator=(std::basic_string_view<Tchar> Rhs);
|
|
constexpr StringBase<Tchar>& operator=(ImmutableStringBase<Tchar> Rhs);
|
|
|
|
// Equality operators
|
|
constexpr bool operator==(const Tchar* Rhs) const;
|
|
constexpr bool operator==(const StringBase<Tchar>& Rhs) const;
|
|
constexpr bool operator==(std::basic_string_view<Tchar> Rhs) const;
|
|
|
|
// Inequality operators
|
|
constexpr bool operator!=(const Tchar* Rhs) const;
|
|
constexpr bool operator!=(const StringBase<Tchar>& Rhs) const;
|
|
constexpr bool operator!=(std::basic_string_view<Tchar> Rhs) const;
|
|
|
|
// Complex logical operators
|
|
friend StringBase<Tchar> operator+(StringBase<Tchar> Lhs, const Tchar Rhs)
|
|
{
|
|
Lhs += Rhs;
|
|
return Lhs;
|
|
}
|
|
friend StringBase<Tchar> operator+(StringBase<Tchar> Lhs, const Tchar* Rhs)
|
|
{
|
|
Lhs += Rhs;
|
|
return Lhs;
|
|
}
|
|
friend StringBase<Tchar> operator+(StringBase<Tchar> Lhs, const StringBase<Tchar>& Rhs)
|
|
{
|
|
Lhs += Rhs;
|
|
return Lhs;
|
|
}
|
|
friend StringBase<Tchar> operator+(StringBase<Tchar> Lhs, std::basic_string_view<Tchar>& Rhs)
|
|
{
|
|
Lhs += Rhs;
|
|
return Lhs;
|
|
}
|
|
friend StringBase<Tchar> operator+(StringBase<Tchar> Lhs, ImmutableStringBase<Tchar>& Rhs)
|
|
{
|
|
Lhs += Rhs;
|
|
return Lhs;
|
|
}
|
|
|
|
// Array index operator
|
|
constexpr Tchar& operator[](size_t Index);
|
|
constexpr Tchar& operator[](size_t Index) const;
|
|
|
|
// Indicates no matches in the string
|
|
static constexpr auto InvalidPosition{ static_cast<uint32_t>(-1) };
|
|
|
|
//
|
|
// Static helper routines
|
|
//
|
|
|
|
// Whether or not the string is initialized and not blank
|
|
constexpr bool IsNullOrEmpty();
|
|
static constexpr bool IsNullOrEmpty(const StringBase<Tchar>& Rhs);
|
|
// Whether or not the string is initialized and not whitespace
|
|
constexpr bool IsNullOrWhiteSpace();
|
|
static constexpr bool IsNullOrWhiteSpace(const StringBase<Tchar>& Rhs);
|
|
|
|
// Formats a string based on the provided input
|
|
static constexpr StringBase<Tchar> Format(const Tchar* Format, ...);
|
|
|
|
static constexpr StringBase<Tchar> Format(const Tchar* Format, va_list vArgs);
|
|
|
|
|
|
private:
|
|
Tchar* _Buffer;
|
|
uint32_t _BufferSize;
|
|
uint32_t _StoreSize;
|
|
|
|
constexpr void EnsureCapacity(uint32_t Capacity);
|
|
};
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase()
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(const uint32_t InitialSize, const Tchar InitialValue, const bool Initialized)
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
this->EnsureCapacity(InitialSize);
|
|
|
|
if (!Initialized)
|
|
_StoreSize = 0;
|
|
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
std::memset(this->_Buffer, InitialValue, InitialSize);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
std::wmemset(this->_Buffer, InitialValue, InitialSize);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(const Tchar* Value)
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
size_t vLen = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vLen = strlen(Value);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
vLen = wcslen(Value);
|
|
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, Value, vLen * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(const Tchar* Value, size_t ValueSize)
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
this->EnsureCapacity((uint32_t)ValueSize);
|
|
|
|
std::memcpy(this->_Buffer, Value, ValueSize * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(std::basic_string_view<Tchar> Value)
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
auto vLen = Value.size();
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, Value.data(), vLen * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(ImmutableStringBase<Tchar> Value)
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
auto vLen = Value.Length();
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, (Tchar*)Value, vLen * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
template<size_t Size>
|
|
inline constexpr StringBase<Tchar>::StringBase(const Tchar(&Value)[Size])
|
|
: _Buffer(nullptr), _BufferSize(0), _StoreSize(0)
|
|
{
|
|
size_t vLen = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vLen = strlen(Value);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
vLen = wcslen(Value);
|
|
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, Value, vLen * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(const StringBase& Value)
|
|
: StringBase(Value._Buffer, Value._StoreSize)
|
|
{
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::StringBase(StringBase&& Value) noexcept
|
|
{
|
|
this->_Buffer = Value._Buffer;
|
|
this->_BufferSize = Value._BufferSize;
|
|
this->_StoreSize = Value._StoreSize;
|
|
|
|
Value._Buffer = nullptr;
|
|
Value._BufferSize = 0;
|
|
Value._StoreSize = 0;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline StringBase<Tchar>::~StringBase()
|
|
{
|
|
if (this->_Buffer)
|
|
delete[] this->_Buffer;
|
|
|
|
this->_Buffer = nullptr;
|
|
this->_BufferSize = 0;
|
|
this->_StoreSize = 0;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr const Tchar * StringBase<Tchar>::ToCString() const
|
|
{
|
|
return this->_Buffer;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<char> StringBase<Tchar>::ToString() const
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
return StringBase<char>(this->_Buffer, this->_StoreSize);
|
|
else
|
|
{
|
|
auto cbBuffer = WideCharToMultiByte(CP_UTF8, NULL, this->_Buffer, this->_StoreSize, NULL, NULL, NULL, FALSE);
|
|
if (cbBuffer == 0)
|
|
return "";
|
|
|
|
auto Result = StringBase<char>(cbBuffer);
|
|
|
|
WideCharToMultiByte(CP_UTF8, NULL, this->_Buffer, this->_StoreSize, (char*)Result, cbBuffer, NULL, FALSE);
|
|
|
|
return std::move(Result);
|
|
}
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<wchar_t> StringBase<Tchar>::ToWString() const
|
|
{
|
|
if (sizeof(Tchar) == sizeof(wchar_t))
|
|
return StringBase<wchar_t>((const wchar_t*)this->_Buffer, this->_StoreSize);
|
|
else
|
|
{
|
|
auto cbBuffer = MultiByteToWideChar(CP_UTF8, NULL, this->_Buffer, this->_StoreSize, NULL, NULL);
|
|
if (cbBuffer == 0)
|
|
return L"";
|
|
|
|
auto Result = StringBase<wchar_t>(cbBuffer);
|
|
|
|
MultiByteToWideChar(CP_UTF8, NULL, this->_Buffer, this->_StoreSize, (wchar_t*)Result, cbBuffer);
|
|
|
|
return std::move(Result);
|
|
}
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr std::basic_string_view<Tchar> StringBase<Tchar>::ToStringView() const
|
|
{
|
|
return std::basic_string_view<Tchar>(this->_Buffer, this->_StoreSize);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::Length() const
|
|
{
|
|
return this->_StoreSize;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr int32_t StringBase<Tchar>::Compare(const Tchar* Rhs) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
size_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
const int Res = std::memcmp(this->_Buffer, Rhs, (size_t)std::min<uint32_t>((uint32_t)LhsSize, (uint32_t)RhsSize));
|
|
|
|
if (Res != 0)
|
|
return Res;
|
|
if (LhsSize < RhsSize)
|
|
return (-1);
|
|
if (LhsSize > RhsSize)
|
|
return (1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr int32_t StringBase<Tchar>::Compare(const StringBase<Tchar>& Rhs) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
const int Res = std::memcmp(this->_Buffer, Rhs._Buffer, (size_t)std::min<uint32_t>((uint32_t)LhsSize, (uint32_t)RhsSize));
|
|
|
|
if (Res != 0)
|
|
return Res;
|
|
if (LhsSize < RhsSize)
|
|
return (-1);
|
|
if (LhsSize > RhsSize)
|
|
return (1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr int32_t StringBase<Tchar>::Compare(std::basic_string_view<Tchar> Rhs) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
const int Res = std::memcmp(this->_Buffer, Rhs.data(), (size_t)std::min<uint32_t>((uint32_t)LhsSize, (uint32_t)RhsSize));
|
|
|
|
if (Res != 0)
|
|
return Res;
|
|
if (LhsSize < RhsSize)
|
|
return (-1);
|
|
if (LhsSize > RhsSize)
|
|
return (1);
|
|
|
|
return 0;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr List<StringBase<Tchar>> StringBase<Tchar>::Split(const Tchar Delimiter) const
|
|
{
|
|
// TODO: This sometimes skips last one: "Imakewins = {".split(' ') missing {
|
|
auto Result = List<StringBase<Tchar>>();
|
|
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Delimiter, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result.Emplace(this->SubString(CurrentIndex, LocatedPosition - CurrentIndex));
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + 1;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result.Emplace(this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex));
|
|
|
|
return Result;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr List<StringBase<Tchar>> StringBase<Tchar>::Split(const Tchar* Separator) const
|
|
{
|
|
auto Result = List<StringBase<Tchar>>();
|
|
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
|
|
uint32_t LhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
LhsSize = (uint32_t)strlen(Separator);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
LhsSize = (uint32_t)wcslen(Separator);
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Separator, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result.Emplace(this->SubString(CurrentIndex, LocatedPosition - CurrentIndex));
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + LhsSize;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result.Emplace(this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex));
|
|
|
|
return Result;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr List<StringBase<Tchar>> StringBase<Tchar>::Split(const StringBase<Tchar>& Separator) const
|
|
{
|
|
auto Result = List<StringBase<Tchar>>();
|
|
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
|
|
auto LhsSize = Separator._StoreSize;
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Separator, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result.Emplace(this->SubString(CurrentIndex, LocatedPosition - CurrentIndex));
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + LhsSize;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result.Emplace(this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex));
|
|
|
|
return Result;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr List<StringBase<Tchar>> StringBase<Tchar>::Split(const std::basic_string_view<Tchar> Separator) const
|
|
{
|
|
auto Result = List<StringBase<Tchar>>();
|
|
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
|
|
auto LhsSize = Separator.size();
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Separator, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result.Emplace(this->SubString(CurrentIndex, LocatedPosition - CurrentIndex));
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + LhsSize;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result.Emplace(this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex));
|
|
|
|
return Result;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Trim() const
|
|
{
|
|
int64_t Index = 0, Ending = (int64_t)this->_StoreSize - 1;
|
|
|
|
for (Index = 0; Index < this->_StoreSize; Index++)
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
{
|
|
if (!::isspace(this->_Buffer[Index]))
|
|
break;
|
|
}
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
{
|
|
if (!::iswspace(this->_Buffer[Index]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
for (Ending = (int64_t)this->_StoreSize - 1; Ending >= Index; Ending--)
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
{
|
|
if (!::isspace(this->_Buffer[Ending]))
|
|
break;
|
|
}
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
{
|
|
if (!::iswspace(this->_Buffer[Ending]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
auto Length = Ending - Index + 1;
|
|
if (Length == this->_StoreSize)
|
|
return *this;
|
|
else if (Length == 0)
|
|
return "";
|
|
|
|
return StringBase<Tchar>(this->_Buffer + Index, (uint32_t)Length);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::TrimStart() const
|
|
{
|
|
int64_t Index = 0, Ending = (int64_t)this->_StoreSize - 1;
|
|
|
|
for (Index = 0; Index < this->_StoreSize; Index++)
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
{
|
|
if (!::isspace(this->_Buffer[Index]))
|
|
break;
|
|
}
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
{
|
|
if (!::iswspace(this->_Buffer[Index]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
auto Length = Ending - Index + 1;
|
|
if (Length == this->_StoreSize)
|
|
return *this;
|
|
else if (Length == 0)
|
|
return "";
|
|
|
|
return StringBase<Tchar>(this->_Buffer + Index, (uint32_t)Length);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::TrimEnd() const
|
|
{
|
|
int64_t Index = 0, Ending = (int64_t)this->_StoreSize - 1;
|
|
|
|
for (Ending = (int64_t)this->_StoreSize - 1; Ending >= Index; Ending--)
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
{
|
|
if (!::isspace(this->_Buffer[Ending]))
|
|
break;
|
|
}
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
{
|
|
if (!::iswspace(this->_Buffer[Ending]))
|
|
break;
|
|
}
|
|
}
|
|
|
|
auto Length = Ending - Index + 1;
|
|
if (Length == this->_StoreSize)
|
|
return *this;
|
|
else if (Length == 0)
|
|
return "";
|
|
|
|
return StringBase<Tchar>(this->_Buffer + Index, (uint32_t)Length);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(const Tchar Rhs, uint32_t Pos) const noexcept
|
|
{
|
|
if (this->_StoreSize == 0 || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memchr((void*)(this->_Buffer + Pos), (int32_t)Rhs, this->_StoreSize) : (Tchar*)std::wmemchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs, this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(const Tchar* Rhs, uint32_t Pos) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
size_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((const char*)(this->_Buffer + Pos), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0]);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((const char*)(fChPos + 1), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0]);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(const Tchar* Rhs, uint32_t Pos, uint32_t Count) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
size_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize || RhsSize < (Count * sizeof(Tchar)))
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
RhsSize = (Count * sizeof(Tchar));
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((const char*)(this->_Buffer + Pos), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0]);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((const char*)(fChPos + 1), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0]);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((const char*)(this->_Buffer + Pos), (int32_t)Rhs._Buffer[0]) : (Tchar*)std::wcschr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs._Buffer[0]);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs._Buffer, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((const char*)(fChPos + 1), (int32_t)Rhs._Buffer[0]) : (Tchar*)std::wcschr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs._Buffer[0]);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos, uint32_t Count) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize || Rhs._StoreSize < Count)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
RhsSize = (Count * sizeof(Tchar));
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((void*)(this->_Buffer + Pos), (int32_t)Rhs._Buffer[0]) : (Tchar*)std::wcschr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs._Buffer[0]);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs._Buffer, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((void*)(fChPos + 1), (int32_t)Rhs._Buffer[0]) : (Tchar*)std::wcschr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs._Buffer[0]);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((void*)(this->_Buffer + Pos), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0]);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs.data(), RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((void*)(fChPos + 1), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0]);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::IndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos, uint32_t Count) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize || Rhs.size() < Count)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
RhsSize = (Count * sizeof(Tchar));
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((void*)(this->_Buffer + Pos), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0]);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs.data(), RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::strchr((void*)(fChPos + 1), (int32_t)Rhs[0]) : (Tchar*)std::wcschr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0]);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(const Tchar Rhs, uint32_t Pos) const noexcept
|
|
{
|
|
if (this->_StoreSize == 0 || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs, this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs, this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(const Tchar* Rhs, uint32_t Pos) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
size_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(fChPos + 1), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(const Tchar* Rhs, uint32_t Pos, uint32_t Count) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
size_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize || RhsSize < (Count * sizeof(Tchar)))
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
RhsSize = (Count * sizeof(Tchar));
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(fChPos + 1), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs._Buffer[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs._Buffer[0], (size_t)this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs._Buffer, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(fChPos + 1), (int32_t)Rhs._Buffer[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs._Buffer[0], (size_t)this->_StoreSize);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(const StringBase<Tchar>& Rhs, uint32_t Pos, uint32_t Count) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize || Rhs._StoreSize < Count)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
RhsSize = (Count * sizeof(Tchar));
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs._Buffer[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs._Buffer[0], (size_t)this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs._Buffer, RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(fChPos + 1), (int32_t)Rhs._Buffer[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs._Buffer[0], (size_t)this->_StoreSize);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs.data(), RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(fChPos + 1), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr uint32_t StringBase<Tchar>::LastIndexOf(std::basic_string_view<Tchar> Rhs, uint32_t Pos, uint32_t Count) const noexcept
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (RhsSize == 0 || RhsSize > LhsSize || Pos >= this->_StoreSize || Rhs.size() < Count)
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
|
|
RhsSize = (Count * sizeof(Tchar));
|
|
|
|
auto fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(this->_Buffer + Pos), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(this->_Buffer + Pos), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (fChPos != nullptr)
|
|
{
|
|
while (std::memcmp(fChPos, Rhs.data(), RhsSize))
|
|
{
|
|
fChPos = (sizeof(Tchar) == sizeof(char)) ? (Tchar*)std::memrchr((void*)(fChPos + 1), (int32_t)Rhs[0], (size_t)this->_StoreSize) : (Tchar*)std::wmemrchr((const wchar_t*)(fChPos + 1), (wchar_t)Rhs[0], (size_t)this->_StoreSize);
|
|
if (!fChPos)
|
|
break;
|
|
}
|
|
|
|
if (fChPos != nullptr)
|
|
return (uint32_t)(fChPos - this->_Buffer);
|
|
}
|
|
|
|
return StringBase<Tchar>::InvalidPosition;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::ToLower() const
|
|
{
|
|
auto Result = StringBase<Tchar>(this->_Buffer, this->_StoreSize);
|
|
|
|
std::transform(Result._Buffer, Result._Buffer + Result._StoreSize, Result._Buffer, (sizeof(Tchar) == sizeof(char)) ? ::tolower : (int(__cdecl*)(int))::towlower);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::ToUpper() const
|
|
{
|
|
auto Result = StringBase<Tchar>(this->_Buffer, this->_StoreSize);
|
|
|
|
std::transform(Result._Buffer, Result._Buffer + Result._StoreSize, Result._Buffer, (sizeof(Tchar) == sizeof(char)) ? ::toupper : (int(__cdecl*)(int))::towupper);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Replace(const Tchar Old, const Tchar New) const
|
|
{
|
|
auto Result = StringBase<Tchar>(this->_Buffer, this->_StoreSize);
|
|
|
|
for (uint32_t i = 0; i < this->_StoreSize; i++)
|
|
{
|
|
if (Result[i] == Old)
|
|
Result[i] = New;
|
|
}
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Replace(const Tchar* Old, const Tchar* New) const
|
|
{
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
|
|
uint32_t LhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
LhsSize = (uint32_t)strlen(Old);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
LhsSize = (uint32_t)wcslen(Old);
|
|
|
|
auto Result = StringBase<Tchar>();
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Old, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result += this->SubString(CurrentIndex, LocatedPosition - CurrentIndex);
|
|
Result += New;
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + LhsSize;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result += this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Replace(const StringBase<Tchar>& Old, const StringBase<Tchar>& New) const
|
|
{
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
uint32_t LhsSize = Old._StoreSize;
|
|
|
|
auto Result = StringBase<Tchar>();
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Old, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result += this->SubString(CurrentIndex, LocatedPosition - CurrentIndex);
|
|
Result += New;
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + LhsSize;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result += this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Replace(std::basic_string_view<Tchar> Old, std::basic_string_view<Tchar> New) const
|
|
{
|
|
uint32_t CurrentIndex = 0, LocatedPosition = 0;
|
|
uint32_t LhsSize = (uint32_t)Old.size();
|
|
|
|
auto Result = StringBase<Tchar>();
|
|
|
|
// Optimized for large strings and lots of occurrences
|
|
while ((LocatedPosition = this->IndexOf(Old, CurrentIndex)) != StringBase<Tchar>::InvalidPosition)
|
|
{
|
|
Result += this->SubString(CurrentIndex, LocatedPosition - CurrentIndex);
|
|
Result += New;
|
|
|
|
// Advance past the size of old and the position
|
|
CurrentIndex = LocatedPosition + LhsSize;
|
|
}
|
|
|
|
if (CurrentIndex != this->_StoreSize)
|
|
Result += this->SubString(CurrentIndex, this->_StoreSize - CurrentIndex);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::StartsWith(const Tchar* Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
uint32_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = (uint32_t)strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = (uint32_t)wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (RhsSize > LhsSize || RhsSize == 0)
|
|
return false;
|
|
|
|
return (std::memcmp(this->_Buffer, Rhs, RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::StartsWith(const StringBase<Tchar>& Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (RhsSize > LhsSize || RhsSize == 0)
|
|
return false;
|
|
|
|
return (std::memcmp(this->_Buffer, Rhs._Buffer, RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::StartsWith(std::basic_string_view<Tchar> Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (RhsSize > LhsSize || RhsSize == 0)
|
|
return false;
|
|
|
|
return (std::memcmp(this->_Buffer, Rhs.data(), RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::EndsWith(const Tchar* Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
uint32_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = (uint32_t)strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = (uint32_t)wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (RhsSize > LhsSize || RhsSize == 0)
|
|
return false;
|
|
|
|
return (std::memcmp((char*)this->_Buffer + (LhsSize - RhsSize), Rhs, RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::EndsWith(const StringBase<Tchar>& Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (RhsSize > LhsSize || RhsSize == 0)
|
|
return false;
|
|
|
|
return (std::memcmp((char*)this->_Buffer + (LhsSize - RhsSize), Rhs._Buffer, RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::EndsWith(std::basic_string_view<Tchar> Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (RhsSize > LhsSize || RhsSize == 0)
|
|
return false;
|
|
|
|
return (std::memcmp((char*)this->_Buffer + (LhsSize - RhsSize), Rhs.data(), RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::Contains(const Tchar* Rhs) const
|
|
{
|
|
return (this->IndexOf(Rhs) != StringBase<Tchar>::InvalidPosition);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::Contains(const StringBase<Tchar>& Rhs) const
|
|
{
|
|
return (this->IndexOf(Rhs) != StringBase<Tchar>::InvalidPosition);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::Contains(std::basic_string_view<Tchar> Rhs) const
|
|
{
|
|
return (this->IndexOf(Rhs) != StringBase<Tchar>::InvalidPosition);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::SubString(uint32_t StartIndex) const
|
|
{
|
|
return this->SubString(StartIndex, this->_StoreSize - StartIndex);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::SubString(uint32_t StartIndex, uint32_t Length) const
|
|
{
|
|
if (Length > 0 && StartIndex < this->_StoreSize && (StartIndex + Length) <= this->_StoreSize)
|
|
{
|
|
auto Result = StringBase<Tchar>(Length);
|
|
|
|
std::memcpy(Result._Buffer, this->_Buffer + StartIndex, Length * sizeof(Tchar));
|
|
|
|
return Result;
|
|
}
|
|
|
|
return StringBase<Tchar>();
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr void StringBase<Tchar>::Append(Tchar Rhs)
|
|
{
|
|
auto nPos = this->_StoreSize;
|
|
this->EnsureCapacity(nPos + 1);
|
|
this->_Buffer[nPos] = Rhs;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr void StringBase<Tchar>::Append(const Tchar* Rhs)
|
|
{
|
|
size_t vLen = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vLen = strlen(Rhs);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
vLen = wcslen(Rhs);
|
|
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, Rhs, vLen * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr void StringBase<Tchar>::Append(Tchar* Rhs, uint32_t Count)
|
|
{
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)Count + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, Rhs, Count * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr void StringBase<Tchar>::Append(const StringBase<Tchar>& Rhs)
|
|
{
|
|
auto vLen = Rhs.Length();
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, Rhs._Buffer, vLen * sizeof(Tchar));
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::operator Tchar*(void) const
|
|
{
|
|
return this->_Buffer;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::operator const Tchar*(void) const
|
|
{
|
|
return (const Tchar*)this->_Buffer;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>::operator std::basic_string_view<Tchar>(void) const
|
|
{
|
|
return std::basic_string_view<Tchar>(this->_Buffer, this->_StoreSize);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr Tchar& StringBase<Tchar>::operator[](size_t Index)
|
|
{
|
|
return this->_Buffer[Index];
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr Tchar& StringBase<Tchar>::operator[](size_t Index) const
|
|
{
|
|
return this->_Buffer[Index];
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator+=(const Tchar* Rhs)
|
|
{
|
|
size_t vLen = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vLen = strlen(Rhs);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
vLen = wcslen(Rhs);
|
|
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, Rhs, vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr Tchar * StringBase<Tchar>::begin() const noexcept
|
|
{
|
|
return this->_Buffer;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr Tchar * StringBase<Tchar>::end() const noexcept
|
|
{
|
|
return (this->_Buffer + this->_StoreSize);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator+=(const Tchar Rhs)
|
|
{
|
|
auto nPos = this->_StoreSize;
|
|
this->EnsureCapacity(nPos + 1);
|
|
this->_Buffer[nPos] = Rhs;
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator+=(const StringBase<Tchar>& Rhs)
|
|
{
|
|
size_t vLen = Rhs._StoreSize;
|
|
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, Rhs._Buffer, vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator+=(std::basic_string_view<Tchar> Rhs)
|
|
{
|
|
size_t vLen = Rhs.size();
|
|
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, Rhs.data(), vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator+=(ImmutableStringBase<Tchar> Rhs)
|
|
{
|
|
size_t vLen = Rhs.Length();
|
|
|
|
auto cPosition = this->_StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen + this->_StoreSize);
|
|
|
|
std::memcpy(this->_Buffer + cPosition, (Tchar*)Rhs, vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator=(const Tchar* Rhs)
|
|
{
|
|
if (this->_Buffer)
|
|
delete[] this->_Buffer;
|
|
this->_Buffer = nullptr;
|
|
this->_BufferSize = 0;
|
|
|
|
size_t vLen = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vLen = strlen(Rhs);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
vLen = wcslen(Rhs);
|
|
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, Rhs, vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator=(const StringBase<Tchar>& Rhs)
|
|
{
|
|
if (this->_Buffer)
|
|
delete[] this->_Buffer;
|
|
this->_Buffer = nullptr;
|
|
this->_BufferSize = 0;
|
|
|
|
auto vLen = Rhs._StoreSize;
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, Rhs._Buffer, vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator=(std::basic_string_view<Tchar> Rhs)
|
|
{
|
|
if (this->_Buffer)
|
|
delete[] this->_Buffer;
|
|
this->_Buffer = nullptr;
|
|
this->_BufferSize = 0;
|
|
|
|
auto vLen = Rhs.size();
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, Rhs.data(), vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar>& StringBase<Tchar>::operator=(ImmutableStringBase<Tchar> Rhs)
|
|
{
|
|
if (this->_Buffer)
|
|
delete[] this->_Buffer;
|
|
this->_Buffer = nullptr;
|
|
this->_BufferSize = 0;
|
|
|
|
auto vLen = Rhs.Length();
|
|
this->EnsureCapacity((uint32_t)vLen);
|
|
|
|
std::memcpy(this->_Buffer, (Tchar*)Rhs, vLen * sizeof(Tchar));
|
|
|
|
return *this;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::operator==(const Tchar* Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
|
|
uint32_t RhsSize = 0;
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
RhsSize = (uint32_t)strlen(Rhs) * sizeof(Tchar);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
RhsSize = (uint32_t)wcslen(Rhs) * sizeof(Tchar);
|
|
|
|
if (LhsSize != RhsSize)
|
|
return false;
|
|
|
|
return (std::memcmp(this->_Buffer, Rhs, RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::operator==(const StringBase<Tchar>& Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs._StoreSize * sizeof(Tchar);
|
|
|
|
if (LhsSize != RhsSize)
|
|
return false;
|
|
|
|
return (std::memcmp(this->_Buffer, Rhs._Buffer, RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::operator==(std::basic_string_view<Tchar> Rhs) const
|
|
{
|
|
auto LhsSize = this->_StoreSize * sizeof(Tchar);
|
|
auto RhsSize = Rhs.size() * sizeof(Tchar);
|
|
|
|
if (LhsSize != RhsSize)
|
|
return false;
|
|
|
|
return (std::memcmp(this->_Buffer, Rhs.data(), RhsSize) == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::operator!=(const Tchar* Rhs) const
|
|
{
|
|
return !(*this == Rhs);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::operator!=(const StringBase<Tchar>& Rhs) const
|
|
{
|
|
return !(*this == Rhs);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::operator!=(std::basic_string_view<Tchar> Rhs) const
|
|
{
|
|
return !(*this == Rhs);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::IsNullOrEmpty()
|
|
{
|
|
return (_Buffer == nullptr || _StoreSize == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::IsNullOrEmpty(const StringBase<Tchar>& Rhs)
|
|
{
|
|
return (Rhs._Buffer == nullptr || Rhs._StoreSize == 0);
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::IsNullOrWhiteSpace()
|
|
{
|
|
if (_Buffer == nullptr)
|
|
return true;
|
|
|
|
for (uint32_t i = 0; i < _StoreSize; i++)
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
{
|
|
if (!::isspace(_Buffer[i]))
|
|
return false;
|
|
}
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
{
|
|
if (!::iswspace(_Buffer[i]))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr bool StringBase<Tchar>::IsNullOrWhiteSpace(const StringBase<Tchar>& Rhs)
|
|
{
|
|
if (Rhs._Buffer == nullptr)
|
|
return true;
|
|
|
|
for (uint32_t i = 0; i < Rhs._StoreSize; i++)
|
|
{
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
{
|
|
if (!::isspace(Rhs._Buffer[i]))
|
|
return false;
|
|
}
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
{
|
|
if (!::iswspace(Rhs._Buffer[i]))
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Format(const Tchar* Format, ...)
|
|
{
|
|
va_list vArgs;
|
|
va_start(vArgs, Format);
|
|
|
|
#pragma warning(suppress: 4996)
|
|
auto BufferSize = (sizeof(Tchar) == sizeof(char)) ? vsnprintf(nullptr, 0, Format, vArgs) : _vsnwprintf(nullptr, 0, (const wchar_t*)Format, vArgs);
|
|
auto Result = StringBase<Tchar>((uint32_t)BufferSize);
|
|
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vsnprintf(Result._Buffer, BufferSize + 1, Format, vArgs);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
_vsnwprintf(Result._Buffer, BufferSize + 1, (const wchar_t*)Format, vArgs);
|
|
|
|
va_end(vArgs);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
// this is for a specific use case. make sure that va_start and va_end are called externally when using this
|
|
template<class Tchar>
|
|
inline constexpr StringBase<Tchar> StringBase<Tchar>::Format(const Tchar* Format, va_list vArgs)
|
|
{
|
|
#pragma warning(suppress: 4996)
|
|
auto BufferSize = (sizeof(Tchar) == sizeof(char)) ? vsnprintf(nullptr, 0, Format, vArgs) : _vsnwprintf(nullptr, 0, (const wchar_t*)Format, vArgs);
|
|
auto Result = StringBase<Tchar>((uint32_t)BufferSize);
|
|
|
|
if constexpr (sizeof(Tchar) == sizeof(char))
|
|
vsnprintf(Result._Buffer, BufferSize + 1, Format, vArgs);
|
|
else if constexpr (sizeof(Tchar) == sizeof(wchar_t))
|
|
_vsnwprintf(Result._Buffer, BufferSize + 1, (const wchar_t*)Format, vArgs);
|
|
|
|
return std::move(Result);
|
|
}
|
|
|
|
template<class Tchar>
|
|
constexpr inline void StringBase<Tchar>::EnsureCapacity(uint32_t Capacity)
|
|
{
|
|
// Ensure that we have a proper buffer size for the string here, this is in units, NOT bytes...
|
|
// All StringBase<Tchar> classes are null-terminated, so we must make sure we set this up properly...
|
|
// Check to ensure we aren't wasting our time first...
|
|
if (Capacity < this->_BufferSize)
|
|
{
|
|
this->_StoreSize = Capacity;
|
|
return;
|
|
}
|
|
|
|
auto nCapacity = Capacity + 1;
|
|
if (nCapacity < 16)
|
|
nCapacity = 17;
|
|
|
|
if (nCapacity < (this->_BufferSize + (this->_BufferSize / 2)) + 1)
|
|
nCapacity = (this->_BufferSize + (this->_BufferSize / 2)) + 1;
|
|
|
|
auto nBuffer = new Tchar[nCapacity]();
|
|
|
|
if (this->_Buffer)
|
|
{
|
|
std::memcpy(nBuffer, this->_Buffer, this->_BufferSize * sizeof(Tchar));
|
|
delete[] this->_Buffer;
|
|
}
|
|
|
|
this->_Buffer = nBuffer;
|
|
|
|
this->_BufferSize = nCapacity - 1;
|
|
this->_StoreSize = Capacity;
|
|
}
|
|
|
|
//
|
|
// Predefiend string types
|
|
//
|
|
|
|
using String = StringBase<char>;
|
|
using WString = StringBase<wchar_t>; |