- Began outlining sdl implementation - Added some helper definitions to various classes - Added contains to string.h and wstring.h
452 lines
12 KiB
C++
452 lines
12 KiB
C++
// =====================================================================================================================
|
|
// fennec, a free and open source game engine
|
|
// Copyright © 2025 Medusa Slockbower
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
// =====================================================================================================================
|
|
|
|
#ifndef FENNEC_LANGPROC_wstringS_WSTRING_H
|
|
#define FENNEC_LANGPROC_wstringS_WSTRING_H
|
|
|
|
#include <fennec/langproc/strings/detail/_ctype.h>
|
|
#include <fennec/langproc/strings/wcstring.h>
|
|
|
|
#include <fennec/lang/assert.h>
|
|
|
|
#include <fennec/memory/allocator.h>
|
|
#include <fennec/memory/common.h>
|
|
|
|
#include <fennec/math/common.h>
|
|
|
|
namespace fennec
|
|
{
|
|
|
|
// Forward def
|
|
template<typename AllocT = allocator<wchar_t>> struct _wstring;
|
|
|
|
// Alias for default allocator
|
|
using wstring = _wstring<>;
|
|
|
|
///
|
|
/// \brief Struct for wrapping c-style strings
|
|
///
|
|
/// \details behaviour guarantees that the underlying string is null-terminated
|
|
template<typename AllocT>
|
|
struct _wstring
|
|
{
|
|
public:
|
|
static constexpr size_t npos = -1;
|
|
using char_t = wchar_t;
|
|
using alloc_t = allocation<wchar_t, AllocT>;
|
|
|
|
|
|
// Constructors ========================================================================================================
|
|
|
|
///
|
|
/// \brief Default Constructor, initializes empty string
|
|
constexpr _wstring()
|
|
: _str() {
|
|
}
|
|
|
|
///
|
|
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
|
|
/// \param n the number of wchar_tacters
|
|
/// \param c the wchar_tacter to fill with
|
|
///
|
|
/// \details adds additional wchar_tacter for null termination.
|
|
constexpr _wstring(size_t n, wchar_t c = '\0')
|
|
: _str(n + 1) {
|
|
fennec::wmemset(_str, c, n);
|
|
}
|
|
|
|
constexpr _wstring(const alloc_t& alloc)
|
|
: _str(alloc) {
|
|
}
|
|
|
|
constexpr _wstring(size_t n, wchar_t c, const alloc_t& alloc)
|
|
: _str(n + 1, alloc) {
|
|
fennec::wmemset(_str, c, n);
|
|
}
|
|
|
|
constexpr _wstring(const wcstring& cstr)
|
|
: _str(cstr, cstr.size() + 1) {
|
|
}
|
|
|
|
///
|
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
|
/// \param str the buffer to wrap
|
|
/// \tparam n the number of wchar_tacters in the buffer including the null-terminator, if present
|
|
template<size_t n>
|
|
explicit constexpr _wstring(const wchar_t (&str)[n])
|
|
: _str(str[n - 1] != '\0' ? n + 1 : n) {
|
|
fennec::wmemcpy(_str, str, n);
|
|
if (str[n - 1] != '\0') {
|
|
_str[n] = '\0';
|
|
}
|
|
}
|
|
|
|
///
|
|
/// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
|
|
/// \param str the buffer to wrap
|
|
/// \param n the number of wchar_tacters in the buffer including the null-terminator, if present
|
|
constexpr _wstring(const wchar_t* buf, size_t n)
|
|
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
|
|
fennec::wmemcpy(_str, buf, n);
|
|
if (buf[n - 1] != '\0') {
|
|
_str[n] = '\0';
|
|
}
|
|
}
|
|
|
|
///
|
|
/// \brief String Copy Constructor
|
|
/// \param str the string to copy
|
|
constexpr _wstring(const _wstring& str) = default;
|
|
|
|
///
|
|
/// \brief String Move Constructor
|
|
/// \param str the string to take ownership of
|
|
constexpr _wstring(_wstring&& str) noexcept = default;
|
|
|
|
///
|
|
/// \brief Destructor, cleans up underlying allocation
|
|
constexpr ~_wstring() = default;
|
|
|
|
// Assignment ==========================================================================================================
|
|
|
|
constexpr _wstring& operator=(const wcstring& cstr) {
|
|
_str.callocate(cstr.capacity());
|
|
fennec::wmemcpy(_str, cstr, cstr.capacity());
|
|
return *this;
|
|
}
|
|
|
|
constexpr _wstring& operator=(const _wstring& str) = default;
|
|
constexpr _wstring& operator=(_wstring&& str) noexcept = default;
|
|
|
|
// Properties ==========================================================================================================
|
|
|
|
///
|
|
/// \returns The size of the string excluding null terminator
|
|
constexpr size_t size() const {
|
|
return _str.capacity() > 0 ? _str.capacity() - 1 : 0;
|
|
}
|
|
|
|
///
|
|
/// \returns The size of the string including null terminator
|
|
constexpr size_t capacity() const {
|
|
return _str.capacity();
|
|
}
|
|
|
|
constexpr bool empty() const {
|
|
return size() == 0;
|
|
}
|
|
|
|
// Access ==============================================================================================================
|
|
|
|
///
|
|
/// \brief Array Access Operator
|
|
/// \param i the index to access
|
|
/// \returns a reference to the wchar_tacter
|
|
constexpr wchar_t& operator[](size_t i) {
|
|
return _str[i];
|
|
}
|
|
|
|
///
|
|
/// \brief Const-Array Access Operator
|
|
/// \param i the index to access
|
|
/// \returns a copy of the wchar_tacter
|
|
constexpr const wchar_t& operator[](size_t i) const {
|
|
return _str[i];
|
|
}
|
|
|
|
constexpr wchar_t* data() {
|
|
return _str;
|
|
}
|
|
|
|
constexpr const wchar_t* data() const {
|
|
return _str;
|
|
}
|
|
|
|
constexpr const wchar_t* cstr() const {
|
|
return _str;
|
|
}
|
|
|
|
// Examination =========================================================================================================
|
|
|
|
///
|
|
/// \returns The length of the string to the first null-terminator
|
|
constexpr size_t length() const {
|
|
return find('\0');
|
|
}
|
|
|
|
///
|
|
/// \brief String Comparison
|
|
/// \param ostr the string to compare against
|
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
|
/// current locale, otherwise a positive value.
|
|
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
|
if (i >= size()) { // bounds check
|
|
return -1;
|
|
}
|
|
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
|
|
|
return ::wcsncmp(_str + i, str, n);
|
|
}
|
|
|
|
///
|
|
/// \brief String Comparison
|
|
/// \param ostr the string to compare against
|
|
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
|
/// current locale, otherwise a positive value.
|
|
constexpr int compare(const _wstring& str, size_t i = 0, size_t n = npos) const {
|
|
if (i >= size()) { // bounds check
|
|
return -1;
|
|
}
|
|
n = min(n, max(size(), str.size()) + 1);
|
|
|
|
return ::wcsncmp(_str + i, str.data(), n);
|
|
}
|
|
|
|
constexpr bool operator==(const wcstring& str) const {
|
|
return compare(str) == 0;
|
|
}
|
|
|
|
constexpr bool operator==(const _wstring& str) const {
|
|
return compare(str) == 0;
|
|
}
|
|
|
|
///
|
|
/// \brief Check if the string contains a character
|
|
/// \param c
|
|
/// \param i
|
|
/// \return
|
|
constexpr bool contains(char c, size_t i = 0) const {
|
|
return find(c, i) != size();
|
|
}
|
|
|
|
///
|
|
/// \brief Finds the index of the first occurrence of `c` in the string
|
|
/// \param c the wchar_tacter to find
|
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
|
constexpr size_t find(wchar_t c, size_t i = 0) const {
|
|
if (i >= size()) { // bounds check
|
|
return size();
|
|
}
|
|
|
|
const wchar_t* loc = ::wcschr(_str + i, c); // get location using strchr
|
|
return loc ? loc - _str : size(); // return size if not found
|
|
}
|
|
|
|
///
|
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
|
/// \param str the string to find
|
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
|
constexpr size_t find(const _wstring& str, size_t i = 0) const { // bounds check
|
|
if (i >= size()) { // bounds check
|
|
return size();
|
|
}
|
|
|
|
const wchar_t* loc = ::wcsstr(_str, str);
|
|
return loc ? loc - _str : size();
|
|
}
|
|
|
|
///
|
|
/// \brief Finds the index of the first occurrence of `str` in the string.
|
|
/// \param str the string to find
|
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
|
constexpr size_t find(const wcstring& str, size_t i = 0) const {
|
|
if (i + str.size() > size()) { // bounds check
|
|
return size();
|
|
}
|
|
|
|
const wchar_t* loc = ::wcsstr(_str + i, str); // get location using strstr
|
|
return loc ? loc - _str : size(); // return size if not found
|
|
}
|
|
|
|
///
|
|
/// \brief Finds the index of the last occurrence of `c` in the string.
|
|
/// \param c the string to find
|
|
/// \param i the index to start at
|
|
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
|
constexpr size_t rfind(wchar_t c, size_t i = npos) const {
|
|
if (size() == 0) {
|
|
return size();
|
|
}
|
|
i = min(i, size() - 1); // clamp i to bounds
|
|
do {
|
|
if (_str[i] == c) { // loop backwards looking for c
|
|
return i;
|
|
}
|
|
} while (i--);
|
|
return size(); // base case
|
|
}
|
|
|
|
///
|
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
|
/// \param str the string to find
|
|
/// \param i the index to start at
|
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
|
constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
|
|
if (size() == 0) {
|
|
return size();
|
|
}
|
|
const wchar_t first = str[0];
|
|
i = min(i, size() - str.size());
|
|
do {
|
|
if(_str[i] == first) {
|
|
if (compare(str, i) == 0) {
|
|
return i;
|
|
}
|
|
}
|
|
} while (i--);
|
|
return size(); // base case
|
|
}
|
|
|
|
///
|
|
/// \brief Finds the index of the last occurrence of `str` in the string.
|
|
/// \param str the string to find
|
|
/// \param i the index to start at
|
|
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
|
constexpr size_t rfind(const string& str, size_t i = npos) const {
|
|
if (size() == 0) {
|
|
return size();
|
|
}
|
|
const wchar_t first = str[0];
|
|
i = min(i, size() - str.size());
|
|
do {
|
|
if(_str[i] == first) {
|
|
if (compare(str, i) == 0) { // loop backwards looking for str
|
|
return i;
|
|
}
|
|
}
|
|
} while (i--);
|
|
return size(); // base case
|
|
}
|
|
|
|
///
|
|
/// \brief Retrieve a substring of a string
|
|
/// \param i the start index
|
|
/// \param n the number of wchar_tacters
|
|
/// \return
|
|
constexpr _wstring substring(size_t i, size_t n = npos) const {
|
|
if (i >= size()) {
|
|
return _wstring("");
|
|
}
|
|
n = fennec::min(n, size() - i);
|
|
_wstring res;
|
|
res._str.callocate(n + 1);
|
|
fennec::wmemcpy(res.data(), _str + i, n);
|
|
return res;
|
|
}
|
|
|
|
|
|
|
|
// Modifiers ===========================================================================================================
|
|
|
|
constexpr void resize(size_t n) {
|
|
_str.creallocate(n + 1);
|
|
_str[size()] = '\0';
|
|
}
|
|
|
|
constexpr _wstring operator+(wchar_t c) const {
|
|
if (_str == nullptr) {
|
|
return _wstring(1, c);
|
|
}
|
|
_wstring res;
|
|
res._str.callocate(capacity() + 1);
|
|
fennec::wmemcpy(res.data(), _str, size());
|
|
res[size()] = c;
|
|
return res;
|
|
}
|
|
|
|
friend constexpr _wstring operator+(wchar_t c, const _wstring& str) {
|
|
_wstring res(1, c);
|
|
return res += str;
|
|
}
|
|
|
|
constexpr _wstring operator+(const wcstring& cstr) const {
|
|
if (_str == nullptr) {
|
|
return _wstring(cstr);
|
|
}
|
|
_wstring res;
|
|
res._str.callocate(size() + cstr.size() + 1);
|
|
fennec::wmemcpy(res.data(), _str, size());
|
|
fennec::wmemcpy(res.data() + size(), cstr, cstr.size());
|
|
return res;
|
|
}
|
|
|
|
constexpr _wstring operator+(const _wstring& str) const {
|
|
if (_str == nullptr) {
|
|
return _wstring(str);
|
|
}
|
|
if (str.data() == nullptr) {
|
|
return _wstring(*this);
|
|
}
|
|
_wstring res;
|
|
res._str.callocate(size() + str.size() + 1);
|
|
fennec::wmemcpy(res.data(), _str, size());
|
|
fennec::wmemcpy(res.data() + size(), str.data(), str.size());
|
|
return res;
|
|
}
|
|
|
|
constexpr _wstring& operator+=(wchar_t c) {
|
|
if (_str == nullptr) {
|
|
_str.callocate(2);
|
|
_str[0] = c;
|
|
return *this;
|
|
}
|
|
_str.creallocate(capacity() + 1);
|
|
_str[size() - 1] = c;
|
|
return *this;
|
|
}
|
|
|
|
constexpr _wstring& operator+=(const wcstring& cstr) {
|
|
if (_str == nullptr) {
|
|
return *this = cstr;
|
|
}
|
|
size_t middle = size();
|
|
_str.creallocate(middle + cstr.size() + 1);
|
|
fennec::wmemcpy(_str + middle, cstr, cstr.size());
|
|
return *this;
|
|
}
|
|
|
|
constexpr _wstring& operator+=(const _wstring& str) {
|
|
if (_str == nullptr) {
|
|
return *this = str;
|
|
}
|
|
if (str.data() == nullptr) {
|
|
return *this;
|
|
}
|
|
size_t middle = size();
|
|
_str.creallocate(middle + str.size() + 1);
|
|
fennec::wmemcpy(_str + middle, str.data(), str.size());
|
|
return *this;
|
|
}
|
|
|
|
|
|
private:
|
|
alloc_t _str;
|
|
};
|
|
|
|
template<>
|
|
struct hash<wstring> : hash<byte_array> {
|
|
constexpr size_t operator()(const string& str) const {
|
|
return hash<byte_array>::operator()(byte_array(str.data(), str.size()));
|
|
}
|
|
};
|
|
|
|
}
|
|
|
|
|
|
#endif // FENNEC_LANGPROC_wstringS_WSTRING_H
|