Compare commits

...

2 Commits

Author SHA1 Message Date
fe4c49d092 - Fixed several memory errors 2025-08-20 20:57:15 -04:00
037c62bf12 - Added missing functionality from C++ spec 2025-08-20 14:00:52 -04:00
25 changed files with 558 additions and 428 deletions

View File

@@ -208,6 +208,7 @@ add_library(fennec STATIC
# EXTRA SOURCES ======================================================================================================== # EXTRA SOURCES ========================================================================================================
${FENNEC_EXTRA_SOURCES} ${FENNEC_EXTRA_SOURCES}
include/fennec/containers/variant.h
) )
add_dependencies(fennec metaprogramming) add_dependencies(fennec metaprogramming)

View File

@@ -27,7 +27,7 @@ class CStringPrinter:
return 'string' return 'string'
def to_string(self): def to_string(self):
value = "\"" + self.val['_str'].string('', 'replace', self.val['_size'] - 1) + "\"" value = "\"" + self.val['_str'].string('', 'replace', self.val['_size']) + "\""
return value return value
def display_hint(self): def display_hint(self):

View File

@@ -60,8 +60,12 @@ namespace fennec
/// \tparam ValueT value type /// \tparam ValueT value type
/// \tparam ElemV number of elements /// \tparam ElemV number of elements
template<typename ValueT, size_t ElemV> template<typename ValueT, size_t ElemV>
struct array struct array {
{
// Definitions =========================================================================================================
public:
using value_t = ValueT; ///< Alias for `ValueT`
// Public Members ====================================================================================================== // Public Members ======================================================================================================
/// \name Public Members /// \name Public Members
@@ -69,7 +73,7 @@ struct array
/// ///
/// \brief backing c-style array handle /// \brief backing c-style array handle
ValueT elements[ElemV]; value_t data[ElemV];
/// @} /// @}
@@ -101,9 +105,9 @@ struct array
/// ///
/// \copydetails array::operator[](size_t) const /// \copydetails array::operator[](size_t) const
constexpr ValueT& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assertd(i < ElemV, "Array Out of Bounds"); assertd(i < ElemV, "Array Out of Bounds");
return elements[i]; return data[i];
} }
/// ///
@@ -117,9 +121,37 @@ struct array
/// ///
/// \par Space-Complexity /// \par Space-Complexity
/// Constant /// Constant
constexpr const ValueT& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assertd(i < ElemV, "Array Out of Bounds"); assertd(i < ElemV, "Array Out of Bounds");
return elements[i]; return data[i];
}
///
/// \brief Access the first element
/// \returns A reference to the element at `elements[0]`
constexpr value_t& front() {
return data[0];
}
///
/// \brief Const Access the first element
/// \returns A const-qualified reference to the element at `elements[0]`
constexpr const value_t& front() const {
return data[0];
}
///
/// \brief Access the first element
/// \returns A reference to the element at `elements[ElemV - 1]`
constexpr value_t& back() {
return data[ElemV - 1];
}
///
/// \brief Const Access the first element
/// \returns A const-qualified reference to the element at `elements[ElemV - 1]`
constexpr const value_t& back() const {
return data[ElemV - 1];
} }
/// @} /// @}
@@ -154,15 +186,15 @@ struct array
/// ///
/// \brief C++ Iterator Specification `begin()` /// \brief C++ Iterator Specification `begin()`
/// \returns A pointer to the first element of the array /// \returns A pointer to the first element of the array
constexpr ValueT* begin() { constexpr value_t* begin() {
return elements; return data;
} }
/// ///
/// \brief C++ Iterator Specification `end()` /// \brief C++ Iterator Specification `end()`
/// \returns A pointer to one after the end of the array /// \returns A pointer to one after the end of the array
constexpr ValueT* end() { constexpr value_t* end() {
return elements + ElemV; return data + ElemV;
} }
@@ -170,15 +202,15 @@ struct array
/// ///
/// \brief Const C++ Iterator Specification `begin()` /// \brief Const C++ Iterator Specification `begin()`
/// \returns A const-qualified pointer to the first element of the array /// \returns A const-qualified pointer to the first element of the array
constexpr const ValueT* begin() const { constexpr const value_t* begin() const {
return elements; return data;
} }
/// ///
/// \brief Const C++ Iterator Specification `end()` /// \brief Const C++ Iterator Specification `end()`
/// \returns A const-qualified pointer to one after the end of the array /// \returns A const-qualified pointer to one after the end of the array
constexpr const ValueT* end() const { constexpr const value_t* end() const {
return elements + ElemV; return data + ElemV;
} }
/// @} /// @}

View File

@@ -102,6 +102,16 @@ public:
, _size(0) { , _size(0) {
} }
///
/// \brief Alloc Constructor, initializes an empty deque with the specified allocator
/// \param alloc the allocator to copy
deque(const alloc_t& alloc)
: _alloc(alloc)
, _first(nullptr)
, _last(nullptr)
, _size(0) {
}
/// ///
/// \brief Copy Constructor /// \brief Copy Constructor
/// \param deque the deque to copy /// \param deque the deque to copy

View File

@@ -29,9 +29,12 @@ template <std::size_t I, typename T>
struct _tuple_leaf struct _tuple_leaf
{ {
template <typename ArgT> template <typename ArgT>
_tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {} constexpr _tuple_leaf(ArgT&& arg) : value(fennec::forward<ArgT>(arg)) {}
~_tuple_leaf() = default; constexpr ~_tuple_leaf() = default;
constexpr _tuple_leaf& operator=(const _tuple_leaf&) = default;
constexpr _tuple_leaf& operator=(_tuple_leaf&&) noexcept = default;
T value; T value;
}; };
@@ -43,9 +46,14 @@ template <size_t...IndicesV, typename...TypesT>
struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>... struct _tuple<const_index_sequence<IndicesV...>, TypesT...> : _tuple_leaf<IndicesV, TypesT>...
{ {
template <typename...ArgsT> template <typename...ArgsT>
_tuple(ArgsT&&... args) : _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {} constexpr _tuple(ArgsT&&... args)
: _tuple_leaf<IndicesV, TypesT>(fennec::forward<ArgsT>(args))... {
}
~_tuple() = default; constexpr _tuple& operator=(const _tuple&) = default;
constexpr _tuple& operator=(_tuple&&) noexcept = default;
constexpr ~_tuple() = default;
}; };
} }

View File

@@ -72,16 +72,15 @@ private:
struct node; struct node;
public: public:
///< Alias for the allocator type, rebound to list nodes /// \brief Alias for the allocator type, rebound to list nodes
using alloc_t = typename allocator_traits<Alloc>::template rebind<node>; using alloc_t = typename allocator_traits<Alloc>::template rebind<node>;
using value_t = TypeT; using value_t = TypeT; ///< Alias for the value type
using elem_t = node;
static constexpr size_t npos = -1; static constexpr size_t npos = -1; ///< Constant representing a non-existant position
class iterator; class iterator; ///< Iterator type for forward iteration over the list
class const_iterator; class const_iterator; ///< Iterator type for forward iteration over a constant list
// Constructors & Destructor =========================================================================================== // Constructors & Destructor ===========================================================================================
@@ -529,7 +528,7 @@ public:
}; };
private: private:
allocation<elem_t, alloc_t> _table; allocation<node, alloc_t> _table;
dynarray<size_t> _freed; dynarray<size_t> _freed;
size_t _root, _last, _size; size_t _root, _last, _size;

View File

@@ -81,15 +81,15 @@ struct map {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
struct key_hash; struct key_hash; ///< Hash for node keys
struct node_equals; struct key_equals; ///< Comparison for node keys
using key_t = KeyT; using key_t = KeyT; ///< The key type
using value_t = ValueT; using value_t = ValueT; ///< The value type
using elem_t = pair<KeyT, ValueT>; using elem_t = pair<KeyT, ValueT>; ///< then node type
using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>; using alloc_t = typename allocator_traits<Alloc>::template rebind<elem_t>; ///< Rebinds the allocator type to nodes
using hash_t = Hash; using hash_t = Hash; ///< The hash type
using set_t = set<elem_t, key_hash, node_equals, alloc_t>; using set_t = set<elem_t, key_hash, key_equals, alloc_t>; ///< The underlying set
using iterator = set_t::iterator; using iterator = set_t::iterator; ///< Iterator type
// We only want to hash the key // We only want to hash the key
struct key_hash : hash_t { struct key_hash : hash_t {
@@ -99,7 +99,7 @@ public:
}; };
// We only want to compare the keys // We only want to compare the keys
struct node_equals : equality<KeyT> { struct key_equals : equality<KeyT> {
constexpr bool operator()(const elem_t& a, const elem_t& b) const { constexpr bool operator()(const elem_t& a, const elem_t& b) const {
return equality<KeyT>::operator()(a.first, b.first); return equality<KeyT>::operator()(a.first, b.first);
} }
@@ -248,7 +248,7 @@ public:
} }
/// ///
/// \brief Clears the set, destructing all elements /// \brief Clears the map destructing all elements
void clear() { void clear() {
_set.clear(); _set.clear();
} }

View File

@@ -550,7 +550,7 @@ private:
template<typename...ArgsT> template<typename...ArgsT>
constexpr void _insert(ArgsT&&...args) { constexpr void _insert(ArgsT&&...args) {
if (_size == 0 or static_cast<double>(_size) / capacity() >= _load) { // expand when full if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
_expand(); _expand();
} }
@@ -578,7 +578,7 @@ private:
equal_t _equal; equal_t _equal;
size_t _size; size_t _size;
size_t _sumpsl; size_t _sumpsl;
double _load; float _load;
}; };
} }

View File

@@ -159,20 +159,25 @@ public:
/// ///
/// \brief Move Insertion, inserts a copy of `x` into the pool /// \brief Emplacement, constructs a new object using `args...`
/// \param x the object to copy /// \param args The arguments to construct the new object with
/// \returns An integer corresponding to the id of the node /// \returns An integer corresponding to the id of the node
template<typename...ArgsT> template<typename...ArgsT>
constexpr size_t emplace(ArgsT&&...args) { constexpr size_t emplace(ArgsT&&...args) {
return this->_insert(fennec::forward<ArgsT>(args)...); return this->_insert(fennec::forward<ArgsT>(args)...);
} }
///
/// \brief Erase an object from the pool
/// \param i The id of the object
constexpr void erase(size_t i) { constexpr void erase(size_t i) {
_table[i] = nullopt; _table[i] = nullopt;
_freed.push_back(i); _freed.push_back(i);
--_size; --_size;
} }
/// @}
private: private:
dynarray<elem_t, AllocT> _table; dynarray<elem_t, AllocT> _table;
list<size_t> _freed; list<size_t> _freed;

View File

@@ -304,7 +304,7 @@ public:
/// ///
/// \returns The next node id were `insert` or `emplace` to be called /// \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; size_t i = _size;
if (not _freed.empty()) { if (not _freed.empty()) {
i = _freed.front(); i = _freed.front();
@@ -418,7 +418,10 @@ public:
OrderT order; OrderT order;
i = order(*this, i); i = order(*this, i);
while (i != npos) { 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) { if (mode == traversal_control_break) {
break; break;
} }

View File

@@ -216,7 +216,7 @@ public:
// Check the first element; // Check the first element;
if (_alloc[i].psl >= psl && _alloc[i].value) { if (_alloc[i].psl >= psl && _alloc[i].value) {
if (*_alloc[i].value == val) { if (_equal(*_alloc[i].value, val)) {
return iterator(this, i); 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 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 (c0 && _alloc[i0].value) {
if (*_alloc[i0].value == val) { if (_equal(*_alloc[i0].value, val)) {
return iterator(this, i0); return iterator(this, i0);
} }
} }
if (c1 && _alloc[i1].value) { if (c1 && _alloc[i1].value) {
if (*_alloc[i1].value == val) { if (_equal(*_alloc[i1].value, val)) {
return iterator(this, i1); return iterator(this, i1);
} }
} }
@@ -455,7 +455,7 @@ private:
template<typename...ArgsT> template<typename...ArgsT>
constexpr iterator _insert(ArgsT&&...args) { constexpr iterator _insert(ArgsT&&...args) {
if (_size == 0 or double(_size) / capacity() >= _load) { // expand when full if (_size == 0 or static_cast<float>(_size) / capacity() >= _load) { // expand when full
_expand(); _expand();
} }
@@ -484,7 +484,7 @@ private:
equal_t _equal; equal_t _equal;
size_t _size; size_t _size;
size_t _sumpsl; size_t _sumpsl;
double _load; float _load;
}; };
} }

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

View File

@@ -145,6 +145,7 @@ public:
} }
const string& str() const { return _str; } const string& str() const { return _str; }
const char* cstr() const { return _str.cstr(); }
bool empty() { bool empty() {
size_t size = _str.size(); size_t size = _str.size();
@@ -195,7 +196,7 @@ public:
while (not parse.empty()) { while (not parse.empty()) {
// Handle dots // Handle dots
while (parse._str[0] == '.') { while (not parse.empty() && parse._str[0] == '.') {
// Check for ".." // Check for ".."
if (parse._str[1] == '.') { 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'` /// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
constexpr size_t size() const { return _size; } 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 { constexpr bool empty() const {
return _cstr == nullptr || _size == 0; 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 /// \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; return _cstr;
} }
@@ -330,8 +341,8 @@ private:
template<> template<>
struct hash<cstring> : hash<byte_array> { struct hash<cstring> : hash<byte_array> {
constexpr size_t operator()(const cstring& str) { constexpr size_t operator()(const cstring& str) const {
return hash<byte_array>::operator()(byte_array(*str, str.size())); 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 /// \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 c the character to fill with
/// \param n the number of characters
/// ///
/// \details adds additional character for null termination. /// \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) { : _str(n + 1) {
fennec::memset(_str.data(), c, n); fennec::memset(_str, c, n);
_str[n] = '\0'; }
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 /// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
/// \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
/// \param str the buffer to wrap /// \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.");
}
///
/// \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
/// \param str the buffer to wrap
/// \tparam n the number of characters in the buffer plus the null terminator
template<size_t n> template<size_t n>
explicit constexpr _string(const char (&str)[n]) explicit constexpr _string(const char (&str)[n])
: _str(str, n) { : _str(str[n - 1] != '\0' ? n + 1 : n) {
assert(_str[n - 1] == '\0', "Invalid NTBS."); fennec::memcpy(_str, str, n);
if (str[n - 1] != '\0') {
_str[n] = '\0';
}
} }
/// ///
/// \brief Buffer Copy Constructor /// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
/// \param str the buffer to copy /// \param str the buffer to wrap
constexpr _string(const cstring& str) /// \param n the number of characters in the buffer including the null-terminator, if present
: _str(str, str.size() + 1) { 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 /// \brief String Copy Constructor
/// \param str the string to copy /// \param str the string to copy
constexpr _string(const _string& str) constexpr _string(const _string& str) = default;
: _str(str._str) {
}
constexpr _string(_string&& str) noexcept
: _str(fennec::move(str._str)) {
}
/// ///
/// \brief String Destructor, cleans up the underlying allocation /// \brief String Move Constructor
constexpr ~_string() = default; // allocation cleans up itself /// \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 ========================================================================================================== // Properties ==========================================================================================================
/// ///
/// \returns The size of the string excluding null terminator /// \returns The size of the string excluding null terminator
constexpr size_t size() const { 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 { constexpr bool empty() const {
return size() == 0; return size() == 0;
} }
// Access ============================================================================================================== // Access ==============================================================================================================
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a reference to the character /// \returns a reference to the character
constexpr char& operator[](int i) { constexpr char& operator[](size_t i) {
return _str[i]; return _str[i];
} }
@@ -174,24 +164,21 @@ public:
/// \brief Const-Array Access Operator /// \brief Const-Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a copy of the character /// \returns a copy of the character
constexpr char operator[](int i) const { constexpr const char& operator[](size_t i) const {
assertd(i >= 0 && (size_t)i < size(), "Array Out of Bounds");
return _str[i]; return _str[i];
} }
/// constexpr char* data() {
/// \brief Dereference Operator return _str;
/// \returns A const qualified pointer to the underlying allocation
constexpr const char* operator*() const {
return _str.data();
} }
/// constexpr const char* data() const {
/// \brief Implicit Dereference Cast return _str;
constexpr operator const char*() const {
return _str.data();
} }
constexpr const char* cstr() const {
return _str;
}
// Examination ========================================================================================================= // Examination =========================================================================================================
@@ -212,7 +199,7 @@ public:
} }
n = fennec::min(n, fennec::max(_str, str.size()) + 1); 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); 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 { constexpr bool operator==(const _string& str) const {
@@ -242,8 +229,8 @@ public:
return size(); return size();
} }
const char* loc = ::strchr(_str.data() + i, c); // get location using strchr const char* loc = ::strchr(_str + i, c); // get location using strchr
return loc ? loc - _str.data() : size(); // return size if not found return loc ? loc - _str : size(); // return size if not found
} }
/// ///
@@ -332,63 +319,6 @@ public:
return size(); // base case 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 /// \brief Retrieve a substring of a string
/// \param i the start index /// \param i the start index
@@ -398,59 +328,97 @@ public:
if (i >= size()) { if (i >= size()) {
return _string(""); return _string("");
} }
n = min(n, size() - i); n = fennec::min(n, size() - i);
return _string(_str.data() + i, n); _string res;
} res._str.callocate(n + 1);
fennec::memcpy(res.data(), _str + 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
return res; 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 { constexpr _string operator+(char c) const {
_string res(size() + str.size()); // Make a new string with the size of this + str if (_str == nullptr) {
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this return _string(1, c);
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of str }
_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; return res;
} }
constexpr _string operator+(const _string& str) const { constexpr _string operator+(const _string& str) const {
_string res(size() + str.size()); // Make a new string with the size of this + str if (_str == nullptr) {
fennec::memcpy(&res[0], _str.data(), size()); // Copy the contents of this return _string(str);
fennec::memcpy(&res[size()], str, str.size()); // Append the contents of 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; return res;
} }
constexpr _string& operator+=(char c) { constexpr _string& operator+=(char c) {
size_t x = size(); if (_str == nullptr) {
resize(x + 1); _str.callocate(2);
_str[x] = c; _str[0] = c;
return *this;
}
_str.creallocate(capacity() + 1);
_str[size() - 1] = c;
return *this; return *this;
} }
constexpr _string& operator+=(const cstring& str) { constexpr _string& operator+=(const cstring& cstr) {
size_t x = size(); if (_str == nullptr) {
resize(x + str.size()); return *this = cstr;
fennec::memcpy(&_str[x], str, str.size()); }
size_t middle = size();
_str.creallocate(middle + cstr.size() + 1);
fennec::memcpy(_str + middle, cstr, cstr.size());
return *this; return *this;
} }
constexpr _string& operator+=(const _string& str) { constexpr _string& operator+=(const _string& str) {
size_t x = size(); if (_str == nullptr) {
resize(x + str.size()); return *this = str;
fennec::memcpy(&_str[x], str, str.size()); }
if (str.data() == nullptr) {
return *this; return *this;
} }
size_t middle = size();
_str.creallocate(middle + str.size() + 1);
fennec::memcpy(_str + middle, str.data(), str.size());
return *this;
}
private: private:
alloc_t _str; alloc_t _str;
@@ -459,7 +427,7 @@ private:
template<> template<>
struct hash<string> : hash<byte_array> { struct hash<string> : hash<byte_array> {
constexpr size_t operator()(const string& str) const { 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 /// \brief Default Constructor, initializes with nullptr
constexpr wcstring() constexpr wcstring()
: _str(nullptr) : _str(nullptr), _size(0), _const(true) {
, _size(0)
, _const(true) {
} }
/// ///
@@ -148,7 +146,7 @@ public:
template<size_t n> template<size_t n>
constexpr wcstring& operator=(wchar_t(&str)[n]) { constexpr wcstring& operator=(wchar_t(&str)[n]) {
assert(_str[n - 1] == '\0', "Invalid NTBS."); assert(_str[n - 1] == '\0', "Invalid NTBS.");
_str = str; _size = n - 1; _const = false; _str = str, _size = n - 1, _const = false;
return *this; return *this;
} }
@@ -175,6 +173,10 @@ public:
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'` /// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
constexpr size_t size() const { return _size; } 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 { constexpr bool empty() const {
return _cstr == nullptr || _size == 0; return _cstr == nullptr || _size == 0;
} }
@@ -196,15 +198,22 @@ public:
/// \brief Const-Array Access Operator /// \brief Const-Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a copy of the character /// \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"); assertd(i < size(), "Array Out of Bounds");
return _cstr[i]; return _cstr[i];
} }
/// ///
/// \brief Dereference Operator /// \brief Data Access
/// \returns A const qualified pointer to the underlying allocation /// \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; return _cstr;
} }
@@ -220,12 +229,14 @@ public:
/// ///
/// \returns The length of the string to the first null-terminator /// \returns The length of the string to the first null-terminator
constexpr size_t length() const { constexpr size_t length() const {
return find(L'\0'); return find('\0');
} }
/// ///
/// \brief String Comparison /// \brief String Comparison
/// \param str the string to compare against /// \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 /// \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. /// current locale, otherwise a positive value.
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const { 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); 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 /// \brief String Equality
/// \param str the string to compare against /// \param str the string to compare against
@@ -278,7 +298,7 @@ public:
/// \param c the string to find /// \param c the string to find
/// \param i the index to start at /// \param i the index to start at
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()` /// \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) { if (_size == 0) {
return _size; return _size;
} }
@@ -300,7 +320,7 @@ public:
return _size; return _size;
} }
const wchar_t first = str[0]; const char first = str[0];
i = min(i, _size - str._size); i = min(i, _size - str._size);
do { do {
if(_cstr[i] == first) { if(_cstr[i] == first) {
@@ -321,6 +341,13 @@ private:
bool _const; 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 #endif // FENNEC_LANGPROC_STRINGS_wcstring_H

View File

@@ -16,8 +16,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>. // along with this program. If not, see <https://www.gnu.org/licenses/>.
// ===================================================================================================================== // =====================================================================================================================
#ifndef FENNEC_LANGPROC_wstringS_wstring_H #ifndef FENNEC_LANGPROC_wstringS_WSTRING_H
#define FENNEC_LANGPROC_wstringS_wstring_H #define FENNEC_LANGPROC_wstringS_WSTRING_H
#include <fennec/langproc/strings/detail/_ctype.h> #include <fennec/langproc/strings/detail/_ctype.h>
#include <fennec/langproc/strings/wcstring.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 /// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...`
/// \param n the number of characters /// \param n the number of wchar_tacters
/// \param c the wchar_tacter to fill with
/// ///
/// \details adds additional character for null termination. /// \details adds additional wchar_tacter for null termination.
constexpr _wstring(size_t n) constexpr _wstring(size_t n, wchar_t c = '\0')
: _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)
: _str(n + 1) { : _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 /// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
/// \param str the buffer to copy /// \param str the buffer to wrap
/// \param len number of characters in the buffer /// \tparam n the number of wchar_tacters in the buffer including the null-terminator, if present
/// template<size_t n>
/// \details adds additional character for null termination. Ignores whether str is null-terminated. explicit constexpr _wstring(const wchar_t (&str)[n])
/// This constructor makes the assumption that `len` is the intended number of characters. : _str(str[n - 1] != '\0' ? n + 1 : n) {
constexpr _wstring(const wchar_t* str, size_t n) fennec::wmemcpy(_str, str, n);
: _str(str, n + 1) { if (str[n - 1] != '\0') {
::wcsncpy(_str.data(), str, n);
_str[n] = '\0'; _str[n] = '\0';
} }
}
/// ///
/// \brief Buffer Copy Constructor /// \brief Buffer Constructor, wraps the provided C-Style string, appending a null-terminator if not present
/// \param str the buffer to copy /// \param str the buffer to wrap
/// \param len number of characters in the buffer /// \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)
/// \details adds additional character for null termination. Ignores whether str is null-terminated. : _str(buf[n - 1] != '\0' ? n + 1 : n) {
/// This constructor makes the assumption that `len` is the intended number of characters. fennec::wmemcpy(_str, buf, n);
constexpr _wstring(const wcstring& str) if (buf[n - 1] != '\0') {
: _str(str, str.size() + 1) { _str[n] = '\0';
_str[str.size()] = '\0'; }
} }
/// ///
/// \brief String Copy Constructor /// \brief String Copy Constructor
/// \param str the string to copy /// \param str the string to copy
constexpr _wstring(const wstring& str) constexpr _wstring(const _wstring& str) = default;
: _wstring(str, str.size() - 1) {
}
constexpr _wstring(_wstring&& str) noexcept
: _str(fennec::move(str._str)) {
}
/// ///
/// \brief String Destructor, cleans up the underlying allocation /// \brief String Move Constructor
constexpr ~_wstring() = default; // allocation cleans up itself /// \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 ========================================================================================================== // Properties ==========================================================================================================
/// ///
/// \returns The size of the string excluding null terminator /// \returns The size of the string excluding null terminator
constexpr size_t size() const { 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 { constexpr bool empty() const {
return size() == 0; return size() == 0;
} }
// Access ============================================================================================================== // Access ==============================================================================================================
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a reference to the character /// \returns a reference to the wchar_tacter
constexpr wchar_t& operator[](int i) { constexpr wchar_t& operator[](size_t i) {
return _str[i]; return _str[i];
} }
/// ///
/// \brief Const-Array Access Operator /// \brief Const-Array Access Operator
/// \param i the index to access /// \param i the index to access
/// \returns a copy of the character /// \returns a copy of the wchar_tacter
constexpr wchar_t operator[](int i) const { constexpr const wchar_t& operator[](size_t i) const {
assertd(i >= 0 && i < size(), "Array Out of Bounds");
return _str[i]; return _str[i];
} }
/// constexpr wchar_t* data() {
/// \brief Dereference Operator return _str;
/// \returns A const qualified pointer to the underlying allocation
constexpr const wchar_t* operator*() const {
return _str.data();
} }
/// constexpr const wchar_t* data() const {
/// \brief Implicit Dereference Cast return _str;
constexpr operator const wchar_t*() const {
return _str.data();
} }
constexpr const wchar_t* cstr() const {
return _str;
}
// Examination ========================================================================================================= // Examination =========================================================================================================
@@ -183,7 +199,7 @@ public:
} }
n = fennec::min(n, fennec::max(_str, str.size()) + 1); 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 /// \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 /// \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. /// 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 if (i >= size()) { // bounds check
return -1; return -1;
} }
n = min(n, max(size(), str.size()) + 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 { 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 /// \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()` /// \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 { constexpr size_t find(wchar_t c, size_t i = 0) const {
if (i >= size()) { // bounds check if (i >= size()) { // bounds check
return size(); return size();
} }
const wchar_t* loc = ::wcschr(_str.data() + i, c); // get location using strchr const wchar_t* loc = ::wcschr(_str + i, c); // get location using strchr
return loc ? loc - _str.data() : size(); // return size if not found return loc ? loc - _str : size(); // return size if not found
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of `str` in the string.
/// \param str the string to find /// \param str the string to find
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \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 if (i >= size()) { // bounds check
return size(); return size();
} }
@@ -287,7 +303,7 @@ public:
/// \param str the string to find /// \param str the string to find
/// \param i the index to start at /// \param i the index to start at
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \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) { if (size() == 0) {
return size(); return size();
} }
@@ -303,116 +319,119 @@ public:
return size(); // base case 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 /// \brief Retrieve a substring of a string
/// \param i the start index /// \param i the start index
/// \param n the number of characters /// \param n the number of wchar_tacters
/// \return /// \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()) { if (i >= size()) {
return wstring(""); return _wstring("");
} }
n = min(n, size() - i); n = fennec::min(n, size() - i);
return wstring(_str.data() + i, n); _wstring res;
} res._str.callocate(n + 1);
fennec::wmemcpy(res.data(), _str + 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
return res; 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 // Modifiers ===========================================================================================================
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of str
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; return res;
} }
constexpr wstring operator+(const wstring& str) const { friend constexpr _wstring operator+(wchar_t c, const _wstring& str) {
wstring res(size() + str.size()); // Make a new string with the size of this + str _wstring res(1, c);
fennec::wmemcpy(&res[0], _str.data(), size()); // Copy the contents of this return res += str;
fennec::wmemcpy(&res[size()], str, str.size()); // Append the contents of 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; return res;
} }
constexpr wstring& operator+=(wchar_t c) { constexpr _wstring operator+(const _wstring& str) const {
size_t x = size(); if (_str == nullptr) {
resize(x + 1); return _wstring(str);
_str[x] = c; }
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; return *this;
} }
constexpr wstring& operator+=(const wcstring& str) { constexpr _wstring& operator+=(const wcstring& cstr) {
size_t x = size(); if (_str == nullptr) {
resize(x + str.size()); return *this = cstr;
fennec::wmemcpy(&_str[x], str, str.size()); }
size_t middle = size();
_str.creallocate(middle + cstr.size() + 1);
fennec::wmemcpy(_str + middle, cstr, cstr.size());
return *this; return *this;
} }
constexpr wstring& operator+=(const wstring& str) { constexpr _wstring& operator+=(const _wstring& str) {
size_t x = size(); if (_str == nullptr) {
resize(x + str.size()); return *this = str;
fennec::wmemcpy(&_str[x], str, str.size()); }
if (str.data() == nullptr) {
return *this; return *this;
} }
size_t middle = size();
_str.creallocate(middle + str.size() + 1);
fennec::wmemcpy(_str + middle, str.data(), str.size());
return *this;
}
private: private:
alloc_t _str; 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. /// 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 /// \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 { constexpr void callocate(size_t n, align_t align = zero<align_t>()) noexcept {
deallocate(); allocate(n, align);
if (align != zero<align_t>()) {
_data = _alloc.allocate(_capacity = n, _alignment = align);
} else {
_data = _alloc.allocate(_capacity = n);
}
fennec::memset(static_cast<void*>(_data), 0, _capacity * sizeof(T)); 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 { constexpr void reallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) { if (_data == nullptr) {
allocate(n, align); allocate(n, align);
return;
} }
value_t* old = _data; value_t* old = _data; size_t old_cap = _capacity;
_data = nullptr; _data = nullptr;
allocate(n, align); 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); _alloc.deallocate(old);
_capacity = n; _capacity = n;
} }
@@ -539,12 +536,19 @@ public:
constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept { constexpr void creallocate(size_t n, align_t align = zero<align_t>()) noexcept {
if (_data == nullptr) { if (_data == nullptr) {
callocate(n, align); callocate(n, align);
return;
} }
value_t* old = _data; value_t* old = _data; size_t old_cap = _capacity;
_data = nullptr; _data = nullptr;
callocate(n, align); 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));
if (_capacity > old_cap) {
fennec::memset(static_cast<void*>(_data + old_cap), 0, _capacity - old_cap);
}
_alloc.deallocate(old); _alloc.deallocate(old);
_capacity = n; _capacity = n;
} }
@@ -557,14 +561,17 @@ public:
return _data[i]; 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"); assertd(i < capacity(), "Array Out of Bounds");
return _data[i]; return _data[i];
} }
constexpr const value_t& operator[](size_t i) const { constexpr operator value_t*() {
assertd(i < capacity(), "Array Out of Bounds"); return _data;
return _data[i]; }
constexpr operator const value_t*() const {
return _data;
} }
value_t* begin() { value_t* begin() {

View File

@@ -193,7 +193,7 @@ bool file::open(const string& p, uint8_t mode) {
} }
// Attempt to open the file // Attempt to open the file
_handle = fopen(p, fmode_translate(mode)); _handle = fopen(p.cstr(), fmode_translate(mode));
// Validate the file // Validate the file
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -233,7 +233,7 @@ bool file::open(const path& p, uint8_t mode) {
} }
// Attempt to open the file // Attempt to open the file
_handle = fopen(p.str(), fmode_translate(mode)); _handle = fopen(p.cstr(), fmode_translate(mode));
// Validate the file // Validate the file
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -313,7 +313,7 @@ bool file::erase() {
} }
// Erase the file // Erase the file
remove(path.str()); remove(path.cstr());
return false; return false;
} }
@@ -335,7 +335,7 @@ bool file::rename(const cstring& str) {
} }
// Attempt to open the new file // Attempt to open the new file
FILE* fnew = fopen(fpath.str(), "wx"); FILE* fnew = fopen(fpath.cstr(), "wx");
// Check for open failure // Check for open failure
if (fnew == nullptr) { if (fnew == nullptr) {
@@ -395,7 +395,7 @@ bool file::rename(const cstring& str) {
fclose(_handle); fclose(_handle);
// Reopen the new file // Reopen the new file
_handle = freopen(fpath.str(), fmode_translate(_mode), fnew); _handle = freopen(fpath.cstr(), fmode_translate(_mode), fnew);
// Check for open failure // Check for open failure
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -404,7 +404,7 @@ bool file::rename(const cstring& str) {
} }
// Erase the old file // Erase the old file
remove(_path.str()); remove(_path.cstr());
// Set the new path // Set the new path
_path = fpath; _path = fpath;
@@ -429,7 +429,7 @@ bool file::rename(const string& str) {
} }
// Attempt to open the new file // Attempt to open the new file
FILE* fnew = fopen(fpath.str(), "wx"); FILE* fnew = fopen(fpath.cstr(), "wx");
// Check for open failure // Check for open failure
if (fnew == nullptr) { if (fnew == nullptr) {
@@ -488,7 +488,7 @@ bool file::rename(const string& str) {
fclose(_handle); fclose(_handle);
// Reopen the new file // Reopen the new file
_handle = freopen(_path.str(), fmode_translate(_mode), fnew); _handle = freopen(_path.cstr(), fmode_translate(_mode), fnew);
// Check for open failure // Check for open failure
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -518,7 +518,7 @@ bool file::rename(const path& p) {
} }
// Attempt to open the new file // Attempt to open the new file
FILE* fnew = fopen(fpath.str(), "wx"); FILE* fnew = fopen(fpath.cstr(), "wx");
// Check for open failure // Check for open failure
if (fnew == nullptr) { if (fnew == nullptr) {
@@ -577,7 +577,7 @@ bool file::rename(const path& p) {
fclose(_handle); fclose(_handle);
// Reopen the new file // Reopen the new file
_handle = freopen(_path.str(), fmode_translate(_mode), fnew); _handle = freopen(_path.cstr(), fmode_translate(_mode), fnew);
// Check for open failure // Check for open failure
if (_handle == nullptr) { if (_handle == nullptr) {
@@ -608,7 +608,7 @@ file file::copy(const cstring& str) {
} }
// Attempt to open the new file // Attempt to open the new file
FILE* fnew = fopen(fpath.str(), "wx"); FILE* fnew = fopen(fpath.cstr(), "wx");
// Check for open failure // Check for open failure
if (fnew == nullptr) { if (fnew == nullptr) {
@@ -698,7 +698,7 @@ file file::copy(const string& str) {
} }
// Attempt to open the new file // Attempt to open the new file
FILE* fnew = fopen(fpath.str(), "wx"); FILE* fnew = fopen(fpath.cstr(), "wx");
// Check for open failure // Check for open failure
if (fnew == nullptr) { if (fnew == nullptr) {
@@ -789,7 +789,7 @@ file file::copy(const path& p) {
} }
// Attempt to open the new file // Attempt to open the new file
FILE* fnew = fopen(fpath.str(), "wx"); FILE* fnew = fopen(fpath.cstr(), "wx");
// Check for open failure // Check for open failure
if (fnew == nullptr) { if (fnew == nullptr) {
@@ -989,7 +989,7 @@ wstring file::getwline() {
// Check if there is a file // Check if there is a file
if (_handle == nullptr) { if (_handle == nullptr) {
return 0; return _wstring{ L"" };
} }
// Read the next line; // Read the next line;

View File

@@ -46,7 +46,7 @@ path path::current() {
} }
path path::current(const path& path) { path path::current(const path& path) {
if (chdir(path._str)) { if (chdir(path._str.cstr())) {
return fennec::path(""); return fennec::path("");
} }
return current(); return current();

View File

@@ -29,7 +29,7 @@ static constexpr void insert_driver(list<platform::driver<CtorT>>& drvrs, CtorT
iter_t it = drvrs.begin(); iter_t it = drvrs.begin();
while (it != drvrs.end()) { while (it != drvrs.end()) {
if (priority > it->priority) { if (priority >= it->priority) {
break; break;
} }
} }

View File

@@ -38,10 +38,10 @@ void unix_platform::unload_object(shared_object* obj) {
platform::symbol unix_platform::find_symbol(shared_object* obj, const cstring& name) { platform::symbol unix_platform::find_symbol(shared_object* obj, const cstring& name) {
string _name = name; string _name = name;
void* symbol = dlsym(obj, _name); void* symbol = dlsym(obj, _name.cstr());
if (symbol == nullptr) { if (symbol == nullptr) {
_name = '_' + _name; _name = '_' + _name;
symbol = dlsym(obj, _name); symbol = dlsym(obj, _name.cstr());
} }
return symbol; return symbol;
} }

View File

@@ -60,12 +60,12 @@ inline std::ostream& operator<<(std::ostream& os, const quaternion<ScalarT>& q)
// Helper for printing strings // Helper for printing strings
inline std::ostream& operator<<(std::ostream& os, const cstring& str) { inline std::ostream& operator<<(std::ostream& os, const cstring& str) {
return os << *str; return os << str.data();
} }
// Helper for printing strings // Helper for printing strings
inline std::ostream& operator<<(std::ostream& os, const string& str) { inline std::ostream& operator<<(std::ostream& os, const string& str) {
return os << *str; return os << str.cstr();
} }
// Helper for printing strings // Helper for printing strings

View File

@@ -55,6 +55,11 @@ inline void fennec_test_containers_rdtree() {
fennec_test_spacer(1); fennec_test_spacer(1);
test.traverse<tree_t::pre_order>([](size_t i, size_t n) -> uint8_t {
assertf(i + 1 == n, "Tree Traverse Test Failed");
return traversal_control_continue;
});
test.erase(0); test.erase(0);
fennec_test_run(test.empty(), true); fennec_test_run(test.empty(), true);