- Fixed several memory errors

This commit is contained in:
2025-08-20 20:57:15 -04:00
parent 037c62bf12
commit fe4c49d092
20 changed files with 463 additions and 387 deletions

View File

@@ -528,7 +528,7 @@ public:
};
private:
allocation<elem_t, alloc_t> _table;
allocation<node, alloc_t> _table;
dynarray<size_t> _freed;
size_t _root, _last, _size;

View File

@@ -141,7 +141,7 @@ public:
///
/// \brief Implicit Boolean Check, returns `true` when there is a value contained
constexpr explicit operator bool() const {
constexpr operator bool() const {
return _set;
}

View File

@@ -304,7 +304,7 @@ public:
///
/// \returns The next node id were `insert` or `emplace` to be called
constexpr size_t next_free() const {
constexpr size_t next_id() const {
size_t i = _size;
if (not _freed.empty()) {
i = _freed.front();
@@ -418,7 +418,10 @@ public:
OrderT order;
i = order(*this, i);
while (i != npos) {
uint8_t mode = visit(*_table[i].value, i);
uint8_t mode = traversal_control_continue;
if (_table[i].value) {
mode = visit(*_table[i].value, i);
}
if (mode == traversal_control_break) {
break;
}

View File

@@ -216,7 +216,7 @@ public:
// Check the first element;
if (_alloc[i].psl >= psl && _alloc[i].value) {
if (*_alloc[i].value == val) {
if (_equal(*_alloc[i].value, val)) {
return iterator(this, i);
}
}
@@ -230,13 +230,13 @@ public:
bool c0 = p0 >= 0 && _alloc[i0].psl >= p0, c1 = _alloc[i1].psl >= p1; // Check that we are in range
if (c0 && _alloc[i0].value) {
if (*_alloc[i0].value == val) {
if (_equal(*_alloc[i0].value, val)) {
return iterator(this, i0);
}
}
if (c1 && _alloc[i1].value) {
if (*_alloc[i1].value == val) {
if (_equal(*_alloc[i1].value, val)) {
return iterator(this, i1);
}
}

View File

@@ -0,0 +1,34 @@
// =====================================================================================================================
// 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/>.
// =====================================================================================================================
///
/// \file variant.h
/// \brief Contains the definition for a structure that holds a single value from multiple types
///
///
/// \details
/// \author Medusa Slockbower
///
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
///
///
#ifndef FENNEC_CONTAINERS_VARIANT_H
#define FENNEC_CONTAINERS_VARIANT_H
#endif // FENNEC_CONTAINERS_VARIANT_H

View File

@@ -248,7 +248,7 @@ public:
bool eof() const;
// Read Operations =====================================================================================================
// Binary Read Operations ==============================================================================================
char getc();
wchar_t getwc();
@@ -269,7 +269,7 @@ public:
wstring getwline();
// Write Operations ====================================================================================================
// Binary Write Operations =============================================================================================
bool putc(char c);
bool putwc(wchar_t c);

View File

@@ -145,6 +145,7 @@ public:
}
const string& str() const { return _str; }
const char* cstr() const { return _str.cstr(); }
bool empty() {
size_t size = _str.size();
@@ -195,7 +196,7 @@ public:
while (not parse.empty()) {
// Handle dots
while (parse._str[0] == '.') {
while (not parse.empty() && parse._str[0] == '.') {
// Check for ".."
if (parse._str[1] == '.') {
// ".."

View File

@@ -171,6 +171,10 @@ public:
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
constexpr size_t size() const { return _size; }
///
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
constexpr size_t capacity() const { return _size + 1; }
constexpr bool empty() const {
return _cstr == nullptr || _size == 0;
}
@@ -198,9 +202,16 @@ public:
}
///
/// \brief Dereference Operator
/// \brief Data Access
/// \returns A const qualified pointer to the underlying allocation
constexpr const char* operator*() const {
constexpr char* data() {
return _str;
}
///
/// \brief Data Access
/// \returns A const qualified pointer to the underlying allocation
constexpr const char* data() const {
return _cstr;
}
@@ -330,8 +341,8 @@ private:
template<>
struct hash<cstring> : hash<byte_array> {
constexpr size_t operator()(const cstring& str) {
return hash<byte_array>::operator()(byte_array(*str, str.size()));
constexpr size_t operator()(const cstring& str) const {
return hash<byte_array>::operator()(byte_array(str, str.size()));
}
};

View File

@@ -59,114 +59,104 @@ public:
}
///
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
/// \param n the number of characters
///
/// \details adds additional character for null termination.
constexpr _string(size_t n)
: _string('\0', n) {
}
///
/// \brief Sized Constructor, initializes a null-terminated string of size `n` filled with the character `c`
/// \param c the character to fill with
/// \param n the number of characters
///
/// \details adds additional character for null termination.
constexpr _string(char c, size_t n)
constexpr _string(size_t n, char c = '\0')
: _str(n + 1) {
fennec::memset(_str.data(), c, n);
_str[n] = '\0';
fennec::memset(_str, c, n);
}
constexpr _string(const alloc_t& alloc)
: _str(alloc) {
}
constexpr _string(size_t n, char c, const alloc_t& alloc)
: _str(n + 1, alloc) {
fennec::memset(_str, c, n);
}
constexpr _string(const cstring& cstr)
: _str(cstr, cstr.size() + 1) {
}
///
/// \brief Buffer Copy Constructor
/// \param str the buffer to copy
/// \param n number of characters in the buffer
///
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
/// This constructor makes the assumption that `n` is the intended number of characters.
constexpr _string(char* str, size_t n)
: _str(str[n - 1] == '\0' ? n : n + 1) {
fennec::memcpy(_str.data(), str, n);
if (str[n - 1] != '\0') _str[n] = '\0';
}
///
/// \brief Buffer Constructor, wraps the provided C-Style string
/// \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 characters in the buffer plus the null terminator
/// \tparam n the number of characters in the buffer including the null-terminator, if present
template<size_t n>
explicit constexpr _string(char(&str)[n])
: _str(str, n) {
assert(_str[n - 1] == '\0', "Invalid NTBS.");
explicit constexpr _string(const char (&str)[n])
: _str(str[n - 1] != '\0' ? n + 1 : n) {
fennec::memcpy(_str, str, n);
if (str[n - 1] != '\0') {
_str[n] = '\0';
}
}
///
/// \brief Buffer Copy Constructor
/// \param str the buffer to copy
/// \param n number of characters in the buffer
///
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
/// This constructor makes the assumption that `n` is the intended number of characters.
constexpr _string(const char* str, size_t n)
: _str(str[n - 1] == '\0' ? n : n + 1) {
fennec::memcpy(_str.data(), str, n);
if (str[n - 1] != '\0') _str[n] = '\0';
}
///
/// \brief Buffer Constructor, wraps the provided C-Style string
/// \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 characters in the buffer plus the null terminator
template<size_t n>
explicit constexpr _string(const char(&str)[n])
: _str(str, n) {
assert(_str[n - 1] == '\0', "Invalid NTBS.");
}
///
/// \brief Buffer Copy Constructor
/// \param str the buffer to copy
constexpr _string(const cstring& str)
: _str(str, str.size() + 1) {
/// \param n the number of characters in the buffer including the null-terminator, if present
constexpr _string(const char* buf, size_t n)
: _str(buf[n - 1] != '\0' ? n + 1 : n) {
fennec::memcpy(_str, buf, n);
if (buf[n - 1] != '\0') {
_str[n] = '\0';
}
}
///
/// \brief String Copy Constructor
/// \param str the string to copy
constexpr _string(const _string& str)
: _str(str._str) {
}
constexpr _string(_string&& str) noexcept
: _str(fennec::move(str._str)) {
}
constexpr _string(const _string& str) = default;
///
/// \brief String Destructor, cleans up the underlying allocation
constexpr ~_string() = default; // allocation cleans up itself
/// \brief String Move Constructor
/// \param str the string to take ownership of
constexpr _string(_string&& str) noexcept = default;
///
/// \brief Destructor, cleans up underlying allocation
constexpr ~_string() = default;
// Assignment ==========================================================================================================
constexpr _string& operator=(const cstring& cstr) {
_str.callocate(cstr.capacity());
fennec::memcpy(_str, cstr, cstr.capacity());
return *this;
}
constexpr _string& operator=(const _string& str) = default;
constexpr _string& operator=(_string&& str) noexcept = default;
// Properties ==========================================================================================================
///
/// \returns The size of the string excluding null terminator
constexpr size_t size() const {
return _str.capacity() - 1;
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 character
constexpr char& operator[](int i) {
constexpr char& operator[](size_t i) {
return _str[i];
}
@@ -174,24 +164,21 @@ public:
/// \brief Const-Array Access Operator
/// \param i the index to access
/// \returns a copy of the character
constexpr char operator[](int i) const {
assertd(i >= 0 && (size_t)i < size(), "Array Out of Bounds");
constexpr const char& operator[](size_t i) const {
return _str[i];
}
///
/// \brief Dereference Operator
/// \returns A const qualified pointer to the underlying allocation
constexpr const char* operator*() const {
return _str.data();
constexpr char* data() {
return _str;
}
///
/// \brief Implicit Dereference Cast
constexpr operator const char*() const {
return _str.data();
constexpr const char* data() const {
return _str;
}
constexpr const char* cstr() const {
return _str;
}
// Examination =========================================================================================================
@@ -212,7 +199,7 @@ public:
}
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
return ::strncmp(_str.data() + i, str, n);
return ::strncmp(_str + i, str, n);
}
///
@@ -226,7 +213,7 @@ public:
}
n = min(n, max(size(), str.size()) + 1);
return ::strncmp(_str.data() + i, str, n);
return ::strncmp(_str + i, str.data(), n);
}
constexpr bool operator==(const _string& str) const {
@@ -242,8 +229,8 @@ public:
return size();
}
const char* loc = ::strchr(_str.data() + i, c); // get location using strchr
return loc ? loc - _str.data() : size(); // return size if not found
const char* loc = ::strchr(_str + i, c); // get location using strchr
return loc ? loc - _str : size(); // return size if not found
}
///
@@ -332,63 +319,6 @@ public:
return size(); // base case
}
// Manipulation ========================================================================================================
///
/// \brief Resize the string, filling additional bytes with `'\0'`
/// \param n the new size of the string
constexpr void resize(size_t n) {
size_t i = size();
_str.reallocate(n + 1);
if (n > i) fennec::memset(_str.data() + i, '\0', n + 1 - i);
}
///
/// \brief Copy Assignment Operator
/// \param str the string to copy
/// \returns a reference to `this`
constexpr _string& operator=(const cstring& str) {
if (str.empty()) {
_str.deallocate();
return *this;
}
resize(str.size());
fennec::memcpy(_str.data(), str, str.size());
_str[str.size()] = '\0';
return *this;
}
///
/// \brief Copy Assignment Operator
/// \param str the string to copy
/// \returns a reference to `this`
constexpr _string& operator=(const string& str) {
resize(str.size());
fennec::memcpy(_str.data(), str, str.size());
_str[str.size()] = '\0';
return *this;
}
///
/// \brief Move Assignment Operator
/// \param str the string to move
/// \returns a reference to `this`
constexpr _string& operator=(string&& str) noexcept {
_str = move(str._str);
return *this;
}
///
/// \brief Replace all instances of `x` with `y`
/// \param x the character to search for
/// \param y the character to replace with
void replace(char x, char y) {
size_t i = 0;
while ((i = find(x, 0)) != size()) {
_str[i] = y;
}
}
///
/// \brief Retrieve a substring of a string
/// \param i the start index
@@ -398,60 +328,98 @@ public:
if (i >= size()) {
return _string("");
}
n = min(n, size() - i);
return _string(_str.data() + i, n);
}
///
/// \brief Returns a string with `c` appended to it
/// \param c
/// \returns
constexpr _string operator+(char c) const {
// Copy contents with one additional byte.
_string res(_str.data(), _str.size() + 1);
res[size()] = c; // Set the last character to c
n = fennec::min(n, size() - i);
_string res;
res._str.callocate(n + 1);
fennec::memcpy(res.data(), _str + i, n);
return res;
}
friend constexpr _string operator+(char c, _string& str) {
return _string(c, 1) + str;
// Modifiers ===========================================================================================================
constexpr void resize(size_t n) {
_str.creallocate(n + 1);
_str[size()] = '\0';
}
constexpr _string operator+(const cstring& str) const {
_string res(size() + str.size()); // Make a new string with the size of this + str
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str
constexpr _string operator+(char c) const {
if (_str == nullptr) {
return _string(1, c);
}
_string res;
res._str.callocate(capacity() + 1);
fennec::memcpy(res.data(), _str, size());
res[size()] = c;
return res;
}
friend constexpr _string operator+(char c, const _string& str) {
_string res(1, c);
return res += str;
}
constexpr _string operator+(const cstring& cstr) const {
if (_str == nullptr) {
return _string(cstr);
}
_string res;
res._str.callocate(size() + cstr.size() + 1);
fennec::memcpy(res.data(), _str, size());
fennec::memcpy(res.data() + size(), cstr, cstr.size());
return res;
}
constexpr _string operator+(const _string& str) const {
_string res(size() + str.size()); // Make a new string with the size of this + str
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str
if (_str == nullptr) {
return _string(str);
}
if (str.data() == nullptr) {
return _string(*this);
}
_string res;
res._str.callocate(size() + str.size() + 1);
fennec::memcpy(res.data(), _str, size());
fennec::memcpy(res.data() + size(), str.data(), str.size());
return res;
}
constexpr _string& operator+=(char c) {
size_t x = size();
resize(x + 1);
_str[x] = c;
if (_str == nullptr) {
_str.callocate(2);
_str[0] = c;
return *this;
}
_str.creallocate(capacity() + 1);
_str[size() - 1] = c;
return *this;
}
constexpr _string& operator+=(const cstring& str) {
size_t x = size();
resize(x + str.size());
fennec::memcpy(&_str[x], str, str.size());
constexpr _string& operator+=(const cstring& cstr) {
if (_str == nullptr) {
return *this = cstr;
}
size_t middle = size();
_str.creallocate(middle + cstr.size() + 1);
fennec::memcpy(_str + middle, cstr, cstr.size());
return *this;
}
constexpr _string& operator+=(const _string& str) {
size_t x = size();
resize(x + str.size());
fennec::memcpy(&_str[x], str, str.size());
if (_str == nullptr) {
return *this = str;
}
if (str.data() == nullptr) {
return *this;
}
size_t middle = size();
_str.creallocate(middle + str.size() + 1);
fennec::memcpy(_str + middle, str.data(), str.size());
return *this;
}
private:
alloc_t _str;
};
@@ -459,7 +427,7 @@ private:
template<>
struct hash<string> : hash<byte_array> {
constexpr size_t operator()(const string& str) const {
return hash<byte_array>::operator()(byte_array(*str, str.size()));
return hash<byte_array>::operator()(byte_array(str.data(), str.size()));
}
};

View File

@@ -66,9 +66,7 @@ public:
///
/// \brief Default Constructor, initializes with nullptr
constexpr wcstring()
: _str(nullptr)
, _size(0)
, _const(true) {
: _str(nullptr), _size(0), _const(true) {
}
///
@@ -93,7 +91,7 @@ public:
/// \param str the buffer to wrap
/// \tparam n the number of characters in the buffer plus the null terminator
template<size_t n>
constexpr wcstring(wchar_t(&str)[n])
constexpr wcstring(wchar_t (&str)[n])
: _str(str)
, _size(n - 1)
, _const(false) {
@@ -116,7 +114,7 @@ public:
/// \param str the buffer to wrap
/// \tparam n the number of characters in the buffer plus the null terminator
template<size_t n>
constexpr wcstring(const wchar_t(&str)[n])
constexpr wcstring(const wchar_t (&str)[n])
: _cstr(str)
, _size(n - 1)
, _const(true) {
@@ -148,7 +146,7 @@ public:
template<size_t n>
constexpr wcstring& operator=(wchar_t(&str)[n]) {
assert(_str[n - 1] == '\0', "Invalid NTBS.");
_str = str; _size = n - 1; _const = false;
_str = str, _size = n - 1, _const = false;
return *this;
}
@@ -175,6 +173,10 @@ public:
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
constexpr size_t size() const { return _size; }
///
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
constexpr size_t capacity() const { return _size + 1; }
constexpr bool empty() const {
return _cstr == nullptr || _size == 0;
}
@@ -196,15 +198,22 @@ public:
/// \brief Const-Array Access Operator
/// \param i the index to access
/// \returns a copy of the character
constexpr wchar_t operator[](size_t i) const {
constexpr const wchar_t& operator[](size_t i) const {
assertd(i < size(), "Array Out of Bounds");
return _cstr[i];
}
///
/// \brief Dereference Operator
/// \brief Data Access
/// \returns A const qualified pointer to the underlying allocation
constexpr const wchar_t* operator*() const {
constexpr wchar_t* data() {
return _str;
}
///
/// \brief Data Access
/// \returns A const qualified pointer to the underlying allocation
constexpr const wchar_t* data() const {
return _cstr;
}
@@ -220,12 +229,14 @@ public:
///
/// \returns The length of the string to the first null-terminator
constexpr size_t length() const {
return find(L'\0');
return find('\0');
}
///
/// \brief String Comparison
/// \param str the string to compare against
/// \param i the index to start at
/// \param n the number of characters to compare
/// \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 {
@@ -237,6 +248,15 @@ public:
return ::wcsncmp(_cstr + i, str, n);
}
///
/// \brief String Equality
/// \param str the string to compare against
/// \returns True if all characters are equal, false otherwise
template<size_t n>
constexpr bool operator==(const wchar_t (&str)[n]) const {
return compare(wcstring(str)) == 0;
}
///
/// \brief String Equality
/// \param str the string to compare against
@@ -278,7 +298,7 @@ public:
/// \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 {
constexpr size_t rfind(char c, size_t i = npos) const {
if (_size == 0) {
return _size;
}
@@ -300,7 +320,7 @@ public:
return _size;
}
const wchar_t first = str[0];
const char first = str[0];
i = min(i, _size - str._size);
do {
if(_cstr[i] == first) {
@@ -321,6 +341,13 @@ private:
bool _const;
};
template<>
struct hash<wcstring> : hash<byte_array> {
constexpr size_t operator()(const wcstring& str) const {
return hash<byte_array>::operator()(byte_array(str, str.size()));
}
};
}
#endif // FENNEC_LANGPROC_STRINGS_wcstring_H

View File

@@ -16,8 +16,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.
// =====================================================================================================================
#ifndef FENNEC_LANGPROC_wstringS_wstring_H
#define FENNEC_LANGPROC_wstringS_wstring_H
#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>
@@ -59,110 +59,126 @@ public:
}
///
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters
/// \param n the number of characters
/// \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 character for null termination.
constexpr _wstring(size_t n)
: _wstring('\0', n) {
}
///
/// \brief Sized Constructor, initializes a null-terminated string of size `n` filled with the character `c`
/// \param c the characters to fill with
/// \param n the number of characters
///
/// \details adds additional character for null termination.
constexpr _wstring(wchar_t c, size_t n)
/// \details adds additional wchar_tacter for null termination.
constexpr _wstring(size_t n, wchar_t c = '\0')
: _str(n + 1) {
fennec::wmemset(_str.data(), c, n); _str[n] = '\0';
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 Copy Constructor
/// \param str the buffer to copy
/// \param len number of characters in the buffer
///
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
/// This constructor makes the assumption that `len` is the intended number of characters.
constexpr _wstring(const wchar_t* str, size_t n)
: _str(str, n + 1) {
::wcsncpy(_str.data(), str, n);
_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
/// \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 Copy Constructor
/// \param str the buffer to copy
/// \param len number of characters in the buffer
///
/// \details adds additional character for null termination. Ignores whether str is null-terminated.
/// This constructor makes the assumption that `len` is the intended number of characters.
constexpr _wstring(const wcstring& str)
: _str(str, str.size() + 1) {
_str[str.size()] = '\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)
: _wstring(str, str.size() - 1) {
}
constexpr _wstring(_wstring&& str) noexcept
: _str(fennec::move(str._str)) {
}
constexpr _wstring(const _wstring& str) = default;
///
/// \brief String Destructor, cleans up the underlying allocation
constexpr ~_wstring() = default; // allocation cleans up itself
/// \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() - 1;
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 character
constexpr wchar_t& operator[](int i) {
/// \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 character
constexpr wchar_t operator[](int i) const {
assertd(i >= 0 && i < size(), "Array Out of Bounds");
/// \returns a copy of the wchar_tacter
constexpr const wchar_t& operator[](size_t i) const {
return _str[i];
}
///
/// \brief Dereference Operator
/// \returns A const qualified pointer to the underlying allocation
constexpr const wchar_t* operator*() const {
return _str.data();
constexpr wchar_t* data() {
return _str;
}
///
/// \brief Implicit Dereference Cast
constexpr operator const wchar_t*() const {
return _str.data();
constexpr const wchar_t* data() const {
return _str;
}
constexpr const wchar_t* cstr() const {
return _str;
}
// Examination =========================================================================================================
@@ -183,7 +199,7 @@ public:
}
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
return ::wcsncmp(_str.data() + i, str, n);
return ::wcsncmp(_str + i, str, n);
}
///
@@ -191,13 +207,13 @@ public:
/// \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 {
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.data() + i, str, n);
return ::wcsncmp(_str + i, str.data(), n);
}
constexpr bool operator==(const _wstring& str) const {
@@ -206,22 +222,22 @@ public:
///
/// \brief Finds the index of the first occurrence of `c` in the string
/// \param c the character to find
/// \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.data() + i, c); // get location using strchr
return loc ? loc - _str.data() : size(); // return size if not found
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
constexpr size_t find(const _wstring& str, size_t i = 0) const { // bounds check
if (i >= size()) { // bounds check
return size();
}
@@ -287,7 +303,7 @@ public:
/// \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 wstring& str, size_t i = npos) const {
constexpr size_t rfind(const string& str, size_t i = npos) const {
if (size() == 0) {
return size();
}
@@ -303,116 +319,119 @@ public:
return size(); // base case
}
// Manipulation ========================================================================================================
///
/// \brief Resize the string, filling additional bytes with `'\0'`
/// \param n the new size of the string
constexpr void resize(size_t n) {
size_t i = size();
_str.reallocate(n + 1);
if (n > i) fennec::wmemset(_str.data() + i, L'\0', n - i);
}
///
/// \brief Copy Assignment Operator
/// \param str the string to copy
/// \returns a reference to `this`
constexpr wstring& operator=(const wcstring& str) {
if (str.empty()) {
_str.deallocate();
return *this;
}
if (str.size() > size()) resize(str.size());
fennec::wmemcpy(_str.data(), str, str.size());
_str[str.size()] = L'\0';
return *this;
}
///
/// \brief Copy Assignment Operator
/// \param str the string to copy
/// \returns a reference to `this`
constexpr wstring& operator=(const wstring& str) {
if (str.size() > size()) resize(str.size());
fennec::wmemcpy(_str.data(), str, str.size());
_str[str.size()] = '\0';
return *this;
}
///
/// \brief Move Assignment Operator
/// \param str the string to move
/// \returns a reference to `this`
constexpr wstring& operator=(wstring&& str) noexcept {
_str = fennec::move(str._str);
return *this;
}
///
/// \brief Retrieve a substring of a string
/// \param i the start index
/// \param n the number of characters
/// \param n the number of wchar_tacters
/// \return
constexpr wstring substring(size_t i, size_t n = npos) const {
constexpr _wstring substring(size_t i, size_t n = npos) const {
if (i >= size()) {
return wstring("");
return _wstring("");
}
n = min(n, size() - i);
return wstring(_str.data() + i, n);
}
///
/// \brief Returns a string with `c` appended to it
/// \param c
/// \returns
constexpr wstring operator+(wchar_t c) const {
// Copy contents with one additional byte.
wstring res(_str, _str.size());
res[size()] = c; // Set the last character to c
n = fennec::min(n, size() - i);
_wstring res;
res._str.callocate(n + 1);
fennec::wmemcpy(res.data(), _str + i, n);
return res;
}
constexpr wstring operator+(const wcstring& str) const {
wstring res(size() + str.size()); // Make a new string with the size of this + str
fennec::wmemcpy(&res[0], _str.data(), size()); // Copy the contents of this
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
// 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;
}
constexpr wstring operator+(const wstring& str) const {
wstring res(size() + str.size()); // Make a new string with the size of this + str
fennec::wmemcpy(&res[0], _str.data(), size()); // Copy the contents of this
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
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+=(wchar_t c) {
size_t x = size();
resize(x + 1);
_str[x] = c;
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& str) {
size_t x = size();
resize(x + str.size());
fennec::wmemcpy(&_str[x], str, str.size());
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) {
size_t x = size();
resize(x + str.size());
fennec::wmemcpy(&_str[x], str, str.size());
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
#endif // FENNEC_LANGPROC_wstringS_WSTRING_H

View File

@@ -491,13 +491,7 @@ public:
/// If there is already an allocated block of memory, the previous allocation is released.
/// \param n The number of elements of type `T` to allocate for
constexpr void callocate(size_t n, align_t align = zero<align_t>()) noexcept {
deallocate();
if (align != zero<align_t>()) {
_data = _alloc.allocate(_capacity = n, _alignment = align);
} else {
_data = _alloc.allocate(_capacity = n);
}
allocate(n, align);
fennec::memset(static_cast<void*>(_data), 0, _capacity * sizeof(T));
}
@@ -523,12 +517,15 @@ public:
constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) {
allocate(n, align);
return;
}
value_t* old = _data;
value_t* old = _data; size_t old_cap = _capacity;
_data = nullptr;
allocate(n, align);
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, old_cap) * sizeof(T));
_alloc.deallocate(old);
_capacity = n;
}
@@ -539,12 +536,19 @@ public:
constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) {
callocate(n, align);
return;
}
value_t* old = _data;
value_t* old = _data; size_t old_cap = _capacity;
_data = nullptr;
callocate(n, align);
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, n) * sizeof(T));
allocate(n, align);
fennec::memmove(static_cast<void*>(_data), old, min(_capacity, old_cap) * sizeof(T));
if (_capacity > old_cap) {
fennec::memset(static_cast<void*>(_data + old_cap), 0, _capacity - old_cap);
}
_alloc.deallocate(old);
_capacity = n;
}
@@ -557,14 +561,17 @@ public:
return _data[i];
}
constexpr value_t operator[](size_t i) const requires is_fundamental_v<value_t> {
constexpr const value_t& operator[](size_t i) const {
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];
}
constexpr const value_t& operator[](size_t i) const {
assertd(i < capacity(), "Array Out of Bounds");
return _data[i];
constexpr operator value_t*() {
return _data;
}
constexpr operator const value_t*() const {
return _data;
}
value_t* begin() {