- Started interface for renderers
- Renamed fproc -> langproc (I'll probably never settle on a naming convention for this) - Refactored set to use median psl
This commit is contained in:
24
include/fennec/langproc/filesystem/detail/_stdio.h
Normal file
24
include/fennec/langproc/filesystem/detail/_stdio.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
304
include/fennec/langproc/filesystem/file.h
Normal file
304
include/fennec/langproc/filesystem/file.h
Normal file
@@ -0,0 +1,304 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_IO_FILE_H
|
||||
#define FENNEC_LANGPROC_IO_FILE_H
|
||||
|
||||
#include <fennec/langproc/filesystem/path.h>
|
||||
|
||||
#include <fennec/langproc/strings/cstring.h>
|
||||
#include <fennec/langproc/strings/string.h>
|
||||
#include <fennec/langproc/strings/wstring.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief Mode flags for opening a file
|
||||
///
|
||||
/// fmode_binary and fmode_wide are independent of the other modes
|
||||
///
|
||||
/// \details Valid Flag Combinations
|
||||
/// <table width="100%" class="fieldtable" id="table_fennec_LANGPROC_io_fmode">
|
||||
/// <tr><th style="vertical-align: top">Flags
|
||||
/// <th style="vertical-align: top">Description
|
||||
///
|
||||
/// <tr><td style="vertical-align: top">`read`
|
||||
/// <td style="vertical-align: top">Opens file as read-only, reading from start
|
||||
///
|
||||
/// <tr><td style="vertical-align: top">`write`
|
||||
/// <td style="vertical-align: top">Opens file as write-only, writing to end
|
||||
///
|
||||
/// <tr><td style="vertical-align: top">`read | write`
|
||||
/// <td style="vertical-align: top">Opens file as read-write, reading from start
|
||||
///
|
||||
/// <tr><td style="vertical-align: top">`write | trunc`
|
||||
/// <td style="vertical-align: top">Opens file as write-only, destroying contents
|
||||
///
|
||||
/// <tr><td style="vertical-align: top">`read | write | trunc`
|
||||
/// <td style="vertical-align: top">Opens file as read-write, destroying contents
|
||||
/// </table>
|
||||
enum fmode_ : uint8_t
|
||||
{
|
||||
fmode_read = 0b00000001 ///< Opens file for reading
|
||||
, fmode_write = 0b00000010 ///< Opens file for writing
|
||||
, fmode_trunc = 0b00000100 ///< Contents of the file will be destroyed, only compatible with write enabled modes
|
||||
, fmode_exclusive = 0b00001000 ///< Generates an error if the opened file is not empty
|
||||
, fmode_binary = 0b00010000 ///< Open in binary mode
|
||||
, fmode_wide = 0b00100000 ///< Opens a file in wide mode
|
||||
};
|
||||
|
||||
///
|
||||
/// \brief Structure for handling streams of data
|
||||
///
|
||||
/// \details operations, when errored, will return a corresponding error.
|
||||
/// Use file::get_error() to check if an error is present and return a corresponding string.
|
||||
/// Use file::clear_error() to clear the errored state.
|
||||
/// Some operations, specifically file::rename() and file::copy().
|
||||
class file
|
||||
{
|
||||
public:
|
||||
/// \brief value of an invalid position
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
///
|
||||
/// \brief Check if the provided mode bitflags are a valid combination
|
||||
/// \param mode the bitfield
|
||||
/// \returns true if the combination of flags is valid, false otherwise
|
||||
static constexpr bool is_valid(uint8_t mode) {
|
||||
const bool t = mode & fmode_trunc;
|
||||
const bool x = mode & fmode_exclusive;
|
||||
const bool w = mode & fmode_write;
|
||||
|
||||
// when x is true, t must be true
|
||||
// when t is true, w must be true
|
||||
return (t && x && w)
|
||||
|| (t && w)
|
||||
|| !(t || x);
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns the c stdout
|
||||
static file& cout();
|
||||
|
||||
///
|
||||
/// \returns the c stdin
|
||||
static file& cin();
|
||||
|
||||
///
|
||||
/// \returns the c stderr
|
||||
static file& cerr();
|
||||
|
||||
///
|
||||
/// \brief default constructor, initializes an empty stream
|
||||
file();
|
||||
|
||||
///
|
||||
/// \brief default destructor, cleans up an open stream
|
||||
~file();
|
||||
|
||||
///
|
||||
/// \brief move constructor
|
||||
/// \param file the stream to take ownership of
|
||||
file(file&& file) noexcept;
|
||||
|
||||
file& operator=(file&& file) noexcept;
|
||||
|
||||
// don't allow copying streams
|
||||
file(const file&) = delete;
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns the path the stream
|
||||
const path& get_path() const {
|
||||
return _path;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns the mode of the stream
|
||||
uint8_t mode() const {
|
||||
return _mode;
|
||||
}
|
||||
|
||||
///
|
||||
/// \returns true if there is a valid, open stream.
|
||||
bool is_open() const {
|
||||
return _handle != nullptr;
|
||||
}
|
||||
|
||||
|
||||
// File Access =========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief open a file
|
||||
/// \param path the path to the file
|
||||
/// \param mode the mode flags to open the file with
|
||||
/// \returns false on success, true on error
|
||||
bool open(const cstring& path, uint8_t mode);
|
||||
|
||||
///
|
||||
/// \brief open a file
|
||||
/// \param path the path to the file
|
||||
/// \param mode the mode flags to open the file with
|
||||
/// \returns false on success, true on error
|
||||
bool open(const string& path, uint8_t mode);
|
||||
|
||||
///
|
||||
/// \brief open a file
|
||||
/// \param path the path to the file
|
||||
/// \param mode the mode flags to open the file with
|
||||
/// \returns false on success, true on error
|
||||
bool open(const path& path, uint8_t mode);
|
||||
|
||||
///
|
||||
/// \brief close a stream
|
||||
/// \returns false on success, true on error
|
||||
bool close();
|
||||
|
||||
///
|
||||
/// \brief commit the streams buffer to the file
|
||||
/// \returns false on success, true on error
|
||||
bool commit();
|
||||
|
||||
|
||||
// File Operations =====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief closes the stream and erases the file
|
||||
/// \returns false on success, true on error
|
||||
bool erase();
|
||||
|
||||
///
|
||||
/// \brief rebinds the stream, copying contents to path, and erasing the old file
|
||||
/// \param path the new path
|
||||
/// \returns false on success, true on error
|
||||
///
|
||||
/// \details attempts to open a write-only stream at path,
|
||||
/// attempts to reopen this file as read-only,
|
||||
/// copies the contents of this file to the new stream,
|
||||
/// reopen the new stream with the flags of this file and binds to it,
|
||||
/// closes the old file.
|
||||
bool rename(const cstring& path);
|
||||
|
||||
///
|
||||
/// \brief rebinds the stream, copying contents to path, and erasing the old file
|
||||
/// \param path the new path
|
||||
/// \returns false on success, true on error
|
||||
///
|
||||
/// \details attempts to open a write-only stream at path,
|
||||
/// attempts to reopen this file as read-only,
|
||||
/// copies the contents of this file to the new stream,
|
||||
/// reopen the new stream with the flags of this file and binds to it,
|
||||
/// closes the old file.
|
||||
bool rename(const string& path);
|
||||
|
||||
///
|
||||
/// \brief rebinds the stream, copying contents to path, and erasing the old file
|
||||
/// \param path the new path
|
||||
/// \returns false on success, true on error
|
||||
///
|
||||
/// \details attempts to open a write-only stream at path,
|
||||
/// attempts to reopen this file as read-only,
|
||||
/// copies the contents of this file to the new stream,
|
||||
/// reopen the new stream with the flags of this file and binds to it,
|
||||
/// closes the old file.
|
||||
bool rename(const path& path);
|
||||
|
||||
///
|
||||
/// \brief copies the contents of this file to path.
|
||||
/// \param path the path to copy to
|
||||
/// \returns a file at the new path with the copied contents
|
||||
file copy(const cstring& path);
|
||||
|
||||
///
|
||||
/// \brief copies the contents of this file to path.
|
||||
/// \param path the path to copy to
|
||||
/// \returns a file at the new path with the copied contents
|
||||
file copy(const string& path);
|
||||
|
||||
///
|
||||
/// \brief copies the contents of this file to path.
|
||||
/// \param path the path to copy to
|
||||
/// \returns a file at the new path with the copied contents
|
||||
file copy(const path& path);
|
||||
|
||||
|
||||
// File Positioning ====================================================================================================
|
||||
|
||||
size_t get_pos() const;
|
||||
bool set_pos(size_t i);
|
||||
bool rewind();
|
||||
bool eof() const;
|
||||
|
||||
|
||||
// Read Operations =====================================================================================================
|
||||
|
||||
char getc();
|
||||
wchar_t getwc();
|
||||
|
||||
size_t read(void* data, size_t size, size_t n);
|
||||
|
||||
template<typename T>
|
||||
size_t read(T* data, size_t n) {
|
||||
return read(static_cast<void*>(data), sizeof(T), n);
|
||||
}
|
||||
|
||||
template<typename T, size_t n>
|
||||
size_t read(T (&data)[n]) {
|
||||
return read(static_cast<void*>(data), sizeof(T), n);
|
||||
}
|
||||
|
||||
string getline();
|
||||
wstring getwline();
|
||||
|
||||
|
||||
// Write Operations ====================================================================================================
|
||||
|
||||
bool putc(char c);
|
||||
bool putwc(wchar_t c);
|
||||
|
||||
size_t write(const void* data, size_t size, size_t n);
|
||||
|
||||
template<typename T>
|
||||
size_t write(const T* data, size_t n) {
|
||||
return write(static_cast<const void*>(data), sizeof(T), n);
|
||||
}
|
||||
|
||||
template<typename T, size_t n>
|
||||
size_t write(const T (&data)[n]) {
|
||||
return write(static_cast<const void*>(data), sizeof(T), n);
|
||||
}
|
||||
|
||||
|
||||
// Error Handling ======================================================================================================
|
||||
|
||||
const char* get_error() const { return _error; }
|
||||
void clear_error() { _error = nullptr; }
|
||||
|
||||
private:
|
||||
FILE* _handle;
|
||||
path _path;
|
||||
uint8_t _mode;
|
||||
char* _error;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_LANGPROC_IO_FILE_H
|
||||
236
include/fennec/langproc/filesystem/path.h
Normal file
236
include/fennec/langproc/filesystem/path.h
Normal file
@@ -0,0 +1,236 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_IO_PATH_H
|
||||
#define FENNEC_LANGPROC_IO_PATH_H
|
||||
|
||||
#include <fennec/langproc/strings/string.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
///
|
||||
/// \brief struct for handling file paths
|
||||
///
|
||||
/// \details This structure makes no guarantees about the validity of a path.
|
||||
/// Operations do not examine the system's file structure.
|
||||
struct path
|
||||
{
|
||||
public:
|
||||
// Static Functions ====================================================================================================
|
||||
|
||||
/// \brief Get the current working directory
|
||||
/// \returns a path containing the absolute path to the working directory
|
||||
static path current();
|
||||
|
||||
/// \brief Set the current working directory
|
||||
/// \param path the path to the new working directory
|
||||
/// \returns a path containing the absolute path to the working directory
|
||||
static path current(const path& path);
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, returns the root of the current working directory
|
||||
path() : _str("/") { }
|
||||
|
||||
///
|
||||
/// \brief C-String Conversion Constructor
|
||||
/// \param str the cstring to convert
|
||||
path(const cstring& str)
|
||||
: _str(str) {
|
||||
while (not _str.empty() && _str[_str.size() - 1] == '/') {
|
||||
_str = _str.substring(0, str.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Conversion Constructor
|
||||
/// \param str the string to convert
|
||||
path(const string& str)
|
||||
: _str(str) {
|
||||
while (_str[_str.size() - 1] == '/') {
|
||||
_str = _str.substring(0, str.size() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Path Copy Constructor
|
||||
/// \param p the path to copy
|
||||
path(const path& p)
|
||||
: _str(p._str) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Path Move Constructor
|
||||
/// \param p the path to take ownership of
|
||||
path(path&& p) noexcept : _str(move(p._str)) { }
|
||||
|
||||
|
||||
// Assignment Operators ================================================================================================
|
||||
|
||||
///
|
||||
/// \brief C-String Assignment Operator
|
||||
/// \param p the cstring to assign
|
||||
/// \returns a reference to `this` after assigning `p`
|
||||
path& operator=(const cstring& p) {
|
||||
_str = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Assignment Operator
|
||||
/// \param p the cstring to assign
|
||||
/// \returns a reference to `this` after assigning `p`
|
||||
path& operator=(const string& p) {
|
||||
_str = p;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Path Copy Assignment Operator
|
||||
/// \param p the path to copy
|
||||
/// \returns a reference to `this` after copying `p`
|
||||
path& operator=(const path& p) {
|
||||
_str = p._str;
|
||||
return *this;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Path Move Assignment Operator
|
||||
/// \param p the path to take ownership of
|
||||
/// \returns a reference to `this` after taking ownership of `p`
|
||||
path& operator=(path&& p) noexcept {
|
||||
_str = move(p._str);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Append Operators ====================================================================================================
|
||||
|
||||
///
|
||||
/// \brief
|
||||
/// \param str
|
||||
/// \return
|
||||
path operator/(const cstring& str) const {
|
||||
return path(_str + '/' + str);
|
||||
}
|
||||
|
||||
path operator/(const string& str) const {
|
||||
return path(_str + '/' + str);
|
||||
}
|
||||
|
||||
path operator/(const path& p) const {
|
||||
return path(_str + '/' + p._str);
|
||||
}
|
||||
|
||||
bool operator==(const path& p) const {
|
||||
return _str == p._str;
|
||||
}
|
||||
|
||||
const string& str() const { return _str; }
|
||||
|
||||
bool empty() {
|
||||
size_t size = _str.size();
|
||||
if (size == 0) return true;
|
||||
#if FENNEC_PLATFORM_WINDOWS
|
||||
return (_str[1] == ':' && size == 3);
|
||||
#else
|
||||
return (_str[0] == '/' && size == 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
path parent() const {
|
||||
#ifdef FENNEC_PLATFORM_WINDOWS
|
||||
size_t start = _str.size() - 1;
|
||||
start = _str[start] == '/' || _str[start] == '\\' ? start - 1 : start;
|
||||
|
||||
size_t r = _str.rfind('/', start);
|
||||
size_t l = _str.rfind('\\', start);
|
||||
if (r == _str.size()) {
|
||||
start = l;
|
||||
}
|
||||
else if (l == _str.size()) {
|
||||
start = r;
|
||||
}
|
||||
else {
|
||||
start = max(r, l);
|
||||
}
|
||||
return _str.substring(0, start);
|
||||
#else
|
||||
size_t start = _str.size() - 1;
|
||||
start = _str[start] == '/' ? start - 1 : start;
|
||||
return _str.substring(0, _str.rfind('/', start));
|
||||
#endif
|
||||
}
|
||||
|
||||
path absolute() const {
|
||||
path parse = *this;
|
||||
path working; working._str.resize(0);
|
||||
|
||||
// Check if this is a rooted path;
|
||||
#ifdef FENNEC_PLATFORM_WINDOWS
|
||||
if (_str[1] != ':') {
|
||||
#else
|
||||
if (_str[0] != '/') {
|
||||
#endif
|
||||
working = current();
|
||||
}
|
||||
|
||||
while (not parse.empty()) {
|
||||
// Handle dots
|
||||
while (parse._str[0] == '.') {
|
||||
// Check for ".."
|
||||
if (parse._str[1] == '.') {
|
||||
// ".."
|
||||
if (parse._str.size() == 2) {
|
||||
parse = path();
|
||||
working = working.parent();
|
||||
}
|
||||
// "../"
|
||||
else if (parse._str[2] == '/') {
|
||||
working = working.parent();
|
||||
parse._str = parse._str.substring(3);
|
||||
}
|
||||
}
|
||||
// "./"
|
||||
else if (parse._str[1] == '/') {
|
||||
parse._str = parse._str.substring(2);
|
||||
}
|
||||
}
|
||||
|
||||
if (parse.empty()) break;
|
||||
|
||||
// Push the path
|
||||
const size_t loc = parse._str.find('/');
|
||||
working._str += '/';
|
||||
working._str += parse._str.substring(0, loc);
|
||||
parse._str = parse._str.substring(loc + 1);
|
||||
}
|
||||
|
||||
return working;
|
||||
}
|
||||
|
||||
private:
|
||||
string _str;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_LANGPROC_IO_PATH_H
|
||||
340
include/fennec/langproc/strings/cstring.h
Normal file
340
include/fennec/langproc/strings/cstring.h
Normal file
@@ -0,0 +1,340 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||
#define FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||
|
||||
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||
#include <fennec/memory/detail/_string.h>
|
||||
|
||||
#include <fennec/lang/assert.h>
|
||||
|
||||
#include <fennec/math/common.h>
|
||||
#include <fennec/memory/bytes.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
// TODO: Document
|
||||
|
||||
using ::isalnum;
|
||||
using ::isalpha;
|
||||
using ::islower;
|
||||
using ::isupper;
|
||||
using ::isdigit;
|
||||
using ::isxdigit;
|
||||
using ::iscntrl;
|
||||
using ::isgraph;
|
||||
using ::isspace;
|
||||
using ::isblank;
|
||||
using ::isprint;
|
||||
using ::ispunct;
|
||||
|
||||
using ::tolower;
|
||||
using ::toupper;
|
||||
|
||||
///
|
||||
/// \brief This struct wraps c-style strings
|
||||
///
|
||||
/// \details Requires that the string is null-terminated.
|
||||
/// Prevents const qualified memory blocks from being manipulated.
|
||||
/// This struct should be used when fennec::string would make unnecessary dynamic buffers.
|
||||
struct cstring
|
||||
{
|
||||
public:
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes with nullptr
|
||||
constexpr cstring()
|
||||
: _str(nullptr), _size(0), _const(true) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes with nullptr
|
||||
constexpr cstring(nullptr_t)
|
||||
: _str(nullptr), _size(0), _const(true) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||
/// \param str the buffer to wrap
|
||||
/// \param n the number of characters in the buffer plus the null terminator
|
||||
constexpr cstring(char* str, size_t n)
|
||||
: _str(str)
|
||||
, _size(n - 1)
|
||||
, _const(false) {
|
||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr cstring(char(&str)[n])
|
||||
: _str(str)
|
||||
, _size(n - 1)
|
||||
, _const(false) {
|
||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const Buffer Constructor, wraps the provided C-Style string
|
||||
/// \param str the buffer to wrap
|
||||
/// \param n the number of characters in the buffer plus the null terminator
|
||||
constexpr cstring(const char* str, size_t n)
|
||||
: _cstr(str)
|
||||
, _size(n - 1)
|
||||
, _const(true) {
|
||||
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr cstring(const char(&str)[n])
|
||||
: _cstr(str)
|
||||
, _size(n - 1)
|
||||
, _const(true) {
|
||||
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Constructor
|
||||
/// \param str object to move
|
||||
constexpr cstring(cstring&& str) noexcept
|
||||
: _cstr(str._cstr)
|
||||
, _size(str._size)
|
||||
, _const(str._const) {
|
||||
str._cstr = nullptr;
|
||||
str._size = 0;
|
||||
str._const = true;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
constexpr cstring(const cstring&) = delete;
|
||||
constexpr ~cstring() = default;
|
||||
|
||||
constexpr cstring& operator=(nullptr_t) {
|
||||
_str = nullptr, _size = 0, _const = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
template<size_t n>
|
||||
constexpr cstring& operator=(char(&str)[n]) {
|
||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||
_str = str, _size = n - 1, _const = false;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
template<size_t n>
|
||||
constexpr cstring& operator=(const char(&str)[n]) {
|
||||
assert(str[n - 1] == '\0', "Invalid NTBS.");
|
||||
_cstr = str; _size = n - 1; _const = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
constexpr cstring& operator=(cstring&& str) noexcept {
|
||||
_cstr = str._cstr; str._cstr = nullptr;
|
||||
_size = str._size; str._size = 0;
|
||||
_const = str._const; str._const = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||
constexpr size_t size() const { return _size; }
|
||||
|
||||
constexpr bool empty() const {
|
||||
return _cstr == nullptr || _size == 0;
|
||||
}
|
||||
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a reference to the character
|
||||
constexpr char& operator[](size_t i) {
|
||||
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
|
||||
assertd(i < size(), "Array Out of Bounds");
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const-Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a copy of the character
|
||||
constexpr char operator[](size_t i) const {
|
||||
assertd(i < size(), "Array Out of Bounds");
|
||||
return _cstr[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \returns A const qualified pointer to the underlying allocation
|
||||
constexpr const char* operator*() const {
|
||||
return _cstr;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Implicit Dereference Cast
|
||||
constexpr operator const char*() const {
|
||||
return _cstr;
|
||||
}
|
||||
|
||||
|
||||
// Examination =========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The length of the string to the first null-terminator
|
||||
constexpr size_t length() const {
|
||||
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 cstring& str, size_t i = 0, size_t n = npos) const {
|
||||
if (i >= _size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = min(n, max(_size, str._size) + 1);
|
||||
return ::strncmp(_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 char (&str)[n]) const {
|
||||
return compare(cstring(str)) == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Equality
|
||||
/// \param str the string to compare against
|
||||
/// \returns True if all characters are equal, false otherwise
|
||||
constexpr bool operator==(const cstring& str) const {
|
||||
return compare(str) == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||
/// \param c the character 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 find(char c, size_t i = 0) const {
|
||||
if (i >= _size) { // bounds check
|
||||
return _size;
|
||||
}
|
||||
|
||||
const char* loc = ::strchr(_cstr + i, c); // get location using strchr
|
||||
return loc ? loc - _cstr : _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
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t find(const cstring& str, size_t i = 0) const {
|
||||
if (i + str._size > _size) { // bounds check
|
||||
return _size;
|
||||
}
|
||||
|
||||
const char* loc = ::strstr(_cstr + i, str); // get location using strstr
|
||||
return loc ? loc - _cstr : _size; // return size if not found
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||
/// \param c the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(char c, size_t i = npos) const {
|
||||
if (_size == 0) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
i = min(i, _size - 1); // clamp i to bounds
|
||||
do {
|
||||
if (_cstr[i] == c) return i; // loop backwards looking for c
|
||||
} while (i--);
|
||||
return _size; // base case
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(const cstring& str, size_t i = npos) const {
|
||||
if (_size == 0) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
const char first = str[0];
|
||||
i = min(i, _size - str._size);
|
||||
do {
|
||||
if(_cstr[i] == first) {
|
||||
if (compare(str, i, str._size - 1) == 0) {
|
||||
return i;
|
||||
}
|
||||
} // loop backwards looking for str
|
||||
} while (i--);
|
||||
return _size; // base case
|
||||
}
|
||||
|
||||
private:
|
||||
union { // hack to allow both const qualified and non-const strings
|
||||
char* _str;
|
||||
const char* _cstr;
|
||||
};
|
||||
size_t _size;
|
||||
bool _const;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct hash<cstring> : hash<byte_array> {
|
||||
constexpr size_t operator()(const cstring& str) {
|
||||
return hash<byte_array>::operator()(byte_array(*str, str.size()));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_CSTRING_H
|
||||
25
include/fennec/langproc/strings/detail/_ctype.h
Normal file
25
include/fennec/langproc/strings/detail/_ctype.h
Normal file
@@ -0,0 +1,25 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
|
||||
#include <ctype.h>
|
||||
#include <wctype.h>
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
24
include/fennec/langproc/strings/detail/_locale.h
Normal file
24
include/fennec/langproc/strings/detail/_locale.h
Normal file
@@ -0,0 +1,24 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
#define FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
|
||||
#include <locale.h>
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_DETAIL_CTYPE_H
|
||||
44
include/fennec/langproc/strings/locale.h
Normal file
44
include/fennec/langproc/strings/locale.h
Normal file
@@ -0,0 +1,44 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||
#define FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||
|
||||
#include <fennec/langproc/strings/detail/_locale.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
enum locale : int
|
||||
{
|
||||
lc_all = LC_ALL
|
||||
, lc_collate = LC_COLLATE
|
||||
, lc_ctype = LC_CTYPE
|
||||
, lc_monetary = LC_MONETARY
|
||||
, lc_numeric = LC_NUMERIC
|
||||
, lc_time = LC_TIME
|
||||
};
|
||||
|
||||
using ::lconv;
|
||||
|
||||
using ::setlocale;
|
||||
using ::localeconv;
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_LOCALE_H
|
||||
436
include/fennec/langproc/strings/string.h
Normal file
436
include/fennec/langproc/strings/string.h
Normal file
@@ -0,0 +1,436 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_STRING_H
|
||||
#define FENNEC_LANGPROC_STRINGS_STRING_H
|
||||
|
||||
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||
#include <fennec/langproc/strings/cstring.h>
|
||||
|
||||
#include <fennec/lang/assert.h>
|
||||
|
||||
#include <fennec/memory/allocator.h>
|
||||
#include <fennec/memory/common.h>
|
||||
|
||||
#include <fennec/math/common.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
// Forward def
|
||||
template<typename AllocT = allocator<char>> struct _string;
|
||||
|
||||
// Alias for default allocator
|
||||
using string = _string<>;
|
||||
|
||||
///
|
||||
/// \brief Struct for wrapping c-style strings
|
||||
///
|
||||
/// \details behaviour guarantees that the underlying string is null-terminated
|
||||
template<typename AllocT>
|
||||
struct _string
|
||||
{
|
||||
public:
|
||||
static constexpr size_t npos = -1;
|
||||
using alloc_t = allocation<char, AllocT>;
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes empty string
|
||||
constexpr _string()
|
||||
: _str() {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null 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 n the number of characters
|
||||
///
|
||||
/// \details adds additional character for null termination.
|
||||
constexpr _string(char c, size_t n)
|
||||
: _str(n + 1) {
|
||||
fennec::memset(_str.data(), c, n);
|
||||
_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(n + 1) {
|
||||
fennec::memcpy(_str.data(), str, n);
|
||||
_str[n] = '\0';
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Buffer Copy Constructor
|
||||
/// \param str the buffer to copy
|
||||
constexpr _string(const cstring& str)
|
||||
: _str(str, str.size() + 1) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \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)) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Destructor, cleans up the underlying allocation
|
||||
constexpr ~_string() = default; // allocation cleans up itself
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The size of the string excluding null terminator
|
||||
constexpr size_t size() const {
|
||||
return _str.capacity() - 1;
|
||||
}
|
||||
|
||||
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) {
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \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");
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \returns A const qualified pointer to the underlying allocation
|
||||
constexpr const char* operator*() const {
|
||||
return _str.data();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Implicit Dereference Cast
|
||||
constexpr operator const char*() const {
|
||||
return _str.data();
|
||||
}
|
||||
|
||||
|
||||
// Examination =========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The length of the string to the first null-terminator
|
||||
constexpr size_t length() const {
|
||||
return find('\0');
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Comparison
|
||||
/// \param ostr the string to compare against
|
||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||
/// current locale, otherwise a positive value.
|
||||
constexpr int compare(const cstring& str, size_t i = 0, size_t n = npos) const {
|
||||
if (i >= size()) { // bounds check
|
||||
return -1;
|
||||
}
|
||||
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
||||
|
||||
return ::strncmp(_str.data() + i, str, n);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Comparison
|
||||
/// \param ostr the string to compare against
|
||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||
/// current locale, otherwise a positive value.
|
||||
constexpr int compare(const string& 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 ::strncmp(_str.data() + i, str, n);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const _string& str) const {
|
||||
return compare(str) == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||
/// \param c the character to find
|
||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t find(char c, size_t i = 0) const {
|
||||
if (i >= size()) { // bounds check
|
||||
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
|
||||
}
|
||||
|
||||
///
|
||||
/// \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 string& str, size_t i = 0) const { // bounds check
|
||||
if (i >= size()) { // bounds check
|
||||
return size();
|
||||
}
|
||||
|
||||
const char* loc = ::strstr(_str, str);
|
||||
return loc ? loc - _str : size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t find(const cstring& str, size_t i = 0) const {
|
||||
if (i + str.size() > size()) { // bounds check
|
||||
return size();
|
||||
}
|
||||
|
||||
const char* loc = ::strstr(_str + i, str); // get location using strstr
|
||||
return loc ? loc - _str : size(); // return size if not found
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||
/// \param c the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(char c, size_t i = npos) const {
|
||||
if (size() == 0) {
|
||||
return size();
|
||||
}
|
||||
i = min(i, size() - 1); // clamp i to bounds
|
||||
do {
|
||||
if (_str[i] == c) { // loop backwards looking for c
|
||||
return i;
|
||||
}
|
||||
} while (i--);
|
||||
return size(); // base case
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(const cstring& str, size_t i = npos) const {
|
||||
if (size() == 0) {
|
||||
return size();
|
||||
}
|
||||
const char first = str[0];
|
||||
i = min(i, size() - str.size());
|
||||
do {
|
||||
if(_str[i] == first) {
|
||||
if (compare(str, i) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} while (i--);
|
||||
return size(); // base case
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(const string& str, size_t i = npos) const {
|
||||
if (size() == 0) {
|
||||
return size();
|
||||
}
|
||||
const char first = str[0];
|
||||
i = min(i, size() - str.size());
|
||||
do {
|
||||
if(_str[i] == first) {
|
||||
if (compare(str, i) == 0) { // loop backwards looking for str
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} while (i--);
|
||||
return size(); // base case
|
||||
}
|
||||
|
||||
// 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
|
||||
/// \param n the number of characters
|
||||
/// \return
|
||||
constexpr _string substring(size_t i, size_t n = npos) const {
|
||||
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());
|
||||
res[size()] = c; // Set the last character to c
|
||||
return res;
|
||||
}
|
||||
|
||||
friend constexpr _string operator+(char c, _string& str) {
|
||||
return _string(c, 1) + str;
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
return res;
|
||||
}
|
||||
|
||||
constexpr _string& operator+=(char c) {
|
||||
size_t x = size();
|
||||
resize(x + 1);
|
||||
_str[x] = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr _string& operator+=(const cstring& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::memcpy(&_str[x], str, str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr _string& operator+=(const _string& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::memcpy(&_str[x], str, str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
alloc_t _str;
|
||||
};
|
||||
|
||||
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()));
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_STRING_H
|
||||
326
include/fennec/langproc/strings/wcstring.h
Normal file
326
include/fennec/langproc/strings/wcstring.h
Normal file
@@ -0,0 +1,326 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||
#define FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||
|
||||
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||
#include <fennec/memory/detail/_string.h>
|
||||
|
||||
#include <fennec/lang/assert.h>
|
||||
|
||||
#include <fennec/math/common.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
// TODO: Document
|
||||
|
||||
using ::iswalnum;
|
||||
using ::iswalpha;
|
||||
using ::iswlower;
|
||||
using ::iswupper;
|
||||
using ::iswdigit;
|
||||
using ::iswxdigit;
|
||||
using ::iswcntrl;
|
||||
using ::iswgraph;
|
||||
using ::iswspace;
|
||||
using ::iswblank;
|
||||
using ::iswprint;
|
||||
using ::iswpunct;
|
||||
|
||||
using ::towlower;
|
||||
using ::towupper;
|
||||
|
||||
using ::towctrans;
|
||||
using ::wctrans;
|
||||
|
||||
///
|
||||
/// \brief This struct wraps c-style strings
|
||||
///
|
||||
/// \details Requires that the string is null-terminated.
|
||||
/// Prevents const qualified memory blocks from being manipulated.
|
||||
/// This struct should be used when fennec::string would make unnecessary dynamic buffers.
|
||||
struct wcstring
|
||||
{
|
||||
public:
|
||||
static constexpr size_t npos = -1;
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes with nullptr
|
||||
constexpr wcstring()
|
||||
: _str(nullptr)
|
||||
, _size(0)
|
||||
, _const(true) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes with nullptr
|
||||
constexpr wcstring(nullptr_t)
|
||||
: _str(nullptr), _size(0), _const(true) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Buffer Constructor, wraps the provided C-Style string
|
||||
/// \param str the buffer to wrap
|
||||
/// \param n the number of characters in the buffer plus the null terminator
|
||||
constexpr wcstring(wchar_t* str, size_t n)
|
||||
: _str(str)
|
||||
, _size(n - 1)
|
||||
, _const(false) {
|
||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr wcstring(wchar_t(&str)[n])
|
||||
: _str(str)
|
||||
, _size(n - 1)
|
||||
, _const(false) {
|
||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Const Buffer Constructor, wraps the provided C-Style string
|
||||
/// \param str the buffer to wrap
|
||||
/// \param n the number of characters in the buffer plus the null terminator
|
||||
constexpr wcstring(const wchar_t* str, size_t n)
|
||||
: _cstr(str)
|
||||
, _size(n - 1)
|
||||
, _const(true) {
|
||||
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \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>
|
||||
constexpr wcstring(const wchar_t(&str)[n])
|
||||
: _cstr(str)
|
||||
, _size(n - 1)
|
||||
, _const(true) {
|
||||
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Move Constructor
|
||||
/// \param str object to move
|
||||
constexpr wcstring(wcstring&& str) noexcept
|
||||
: _cstr(str._cstr)
|
||||
, _size(str._size)
|
||||
, _const(str._const) {
|
||||
str._cstr = nullptr;
|
||||
str._size = 0;
|
||||
str._const = true;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
constexpr wcstring(const wcstring&) = delete;
|
||||
constexpr ~wcstring() = default;
|
||||
|
||||
constexpr wcstring& operator=(nullptr_t) {
|
||||
_str = nullptr, _size = 0, _const = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
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;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
template<size_t n>
|
||||
constexpr wcstring& operator=(const wchar_t(&str)[n]) {
|
||||
assert(str[n - 1] == '\0', "Invalid NTBS.");
|
||||
_cstr = str; _size = n - 1; _const = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// TODO: Document
|
||||
constexpr wcstring& operator=(wcstring&& str) noexcept {
|
||||
_cstr = str._cstr; str._cstr = nullptr;
|
||||
_size = str._size; str._size = 0;
|
||||
_const = str._const; str._const = true;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||
constexpr size_t size() const { return _size; }
|
||||
|
||||
constexpr bool empty() const {
|
||||
return _cstr == nullptr || _size == 0;
|
||||
}
|
||||
|
||||
|
||||
// Access ==============================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Array Access Operator
|
||||
/// \param i the index to access
|
||||
/// \returns a reference to the character
|
||||
constexpr wchar_t& operator[](size_t i) {
|
||||
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
|
||||
assertd(i < size(), "Array Out of Bounds");
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \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 {
|
||||
assertd(i < size(), "Array Out of Bounds");
|
||||
return _cstr[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \returns A const qualified pointer to the underlying allocation
|
||||
constexpr const wchar_t* operator*() const {
|
||||
return _cstr;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Implicit Dereference Cast
|
||||
constexpr operator const wchar_t*() const {
|
||||
return _cstr;
|
||||
}
|
||||
|
||||
|
||||
// Examination =========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The length of the string to the first null-terminator
|
||||
constexpr size_t length() const {
|
||||
return find(L'\0');
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Comparison
|
||||
/// \param str the string to compare against
|
||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||
/// current locale, otherwise a positive value.
|
||||
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
||||
if (i >= _size) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
n = min(n, max(_size, str._size) + 1);
|
||||
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
|
||||
constexpr bool operator==(const wcstring& str) const {
|
||||
return compare(str) == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||
/// \param c the character 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 find(wchar_t c, size_t i = 0) const {
|
||||
if (i >= _size) { // bounds check
|
||||
return _size;
|
||||
}
|
||||
|
||||
const wchar_t* loc = ::wcschr(_cstr + i, c); // get location using strchr
|
||||
return loc ? loc - _cstr : _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
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t find(const wcstring& str, size_t i = 0) const {
|
||||
if (i + str._size > _size) { // bounds check
|
||||
return _size;
|
||||
}
|
||||
|
||||
const wchar_t* loc = ::wcsstr(_cstr + i, str); // get location using strstr
|
||||
return loc ? loc - _cstr : _size; // return size if not found
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||
/// \param c the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(wchar_t c, size_t i = npos) const {
|
||||
if (_size == 0) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
i = min(i, _size - 1); // clamp i to bounds
|
||||
do {
|
||||
if (_cstr[i] == c) return i; // loop backwards looking for c
|
||||
} while (i--);
|
||||
return _size; // base case
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
|
||||
if (_size == 0) {
|
||||
return _size;
|
||||
}
|
||||
|
||||
const wchar_t first = str[0];
|
||||
i = min(i, _size - str._size);
|
||||
do {
|
||||
if(_cstr[i] == first) {
|
||||
if (compare(str, i, str._size - 1) == 0) {
|
||||
return i;
|
||||
}
|
||||
} // loop backwards looking for str
|
||||
} while (i--);
|
||||
return _size; // base case
|
||||
}
|
||||
|
||||
private:
|
||||
union { // hack to allow both const qualified and non-const strings
|
||||
wchar_t* _str;
|
||||
const wchar_t* _cstr;
|
||||
};
|
||||
size_t _size;
|
||||
bool _const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // FENNEC_LANGPROC_STRINGS_wcstring_H
|
||||
418
include/fennec/langproc/strings/wstring.h
Normal file
418
include/fennec/langproc/strings/wstring.h
Normal file
@@ -0,0 +1,418 @@
|
||||
// =====================================================================================================================
|
||||
// fennec, a free and open source game engine
|
||||
// Copyright © 2025 Medusa Slockbower
|
||||
//
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
// =====================================================================================================================
|
||||
|
||||
#ifndef FENNEC_LANGPROC_wstringS_wstring_H
|
||||
#define FENNEC_LANGPROC_wstringS_wstring_H
|
||||
|
||||
#include <fennec/langproc/strings/detail/_ctype.h>
|
||||
#include <fennec/langproc/strings/wcstring.h>
|
||||
|
||||
#include <fennec/lang/assert.h>
|
||||
|
||||
#include <fennec/memory/allocator.h>
|
||||
#include <fennec/memory/common.h>
|
||||
|
||||
#include <fennec/math/common.h>
|
||||
|
||||
namespace fennec
|
||||
{
|
||||
|
||||
// Forward def
|
||||
template<typename AllocT = allocator<wchar_t>> struct _wstring;
|
||||
|
||||
// Alias for default allocator
|
||||
using wstring = _wstring<>;
|
||||
|
||||
///
|
||||
/// \brief Struct for wrapping c-style strings
|
||||
///
|
||||
/// \details behaviour guarantees that the underlying string is null-terminated
|
||||
template<typename AllocT>
|
||||
struct _wstring
|
||||
{
|
||||
public:
|
||||
static constexpr size_t npos = -1;
|
||||
using alloc_t = allocation<wchar_t, AllocT>;
|
||||
|
||||
|
||||
// Constructors ========================================================================================================
|
||||
|
||||
///
|
||||
/// \brief Default Constructor, initializes empty string
|
||||
constexpr _wstring()
|
||||
: _str() {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with null characters
|
||||
/// \param n the number of characters
|
||||
///
|
||||
/// \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)
|
||||
: _str(n + 1) {
|
||||
fennec::wmemset(_str.data(), c, n); _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 wchar_t* str, size_t n)
|
||||
: _str(str, n + 1) {
|
||||
::wcsncpy(_str.data(), str, n);
|
||||
_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 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)) {
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Destructor, cleans up the underlying allocation
|
||||
constexpr ~_wstring() = default; // allocation cleans up itself
|
||||
|
||||
// Properties ==========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The size of the string excluding null terminator
|
||||
constexpr size_t size() const {
|
||||
return _str.capacity() - 1;
|
||||
}
|
||||
|
||||
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) {
|
||||
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");
|
||||
return _str[i];
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Dereference Operator
|
||||
/// \returns A const qualified pointer to the underlying allocation
|
||||
constexpr const wchar_t* operator*() const {
|
||||
return _str.data();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Implicit Dereference Cast
|
||||
constexpr operator const wchar_t*() const {
|
||||
return _str.data();
|
||||
}
|
||||
|
||||
|
||||
// Examination =========================================================================================================
|
||||
|
||||
///
|
||||
/// \returns The length of the string to the first null-terminator
|
||||
constexpr size_t length() const {
|
||||
return find('\0');
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Comparison
|
||||
/// \param ostr the string to compare against
|
||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||
/// current locale, otherwise a positive value.
|
||||
constexpr int compare(const wcstring& str, size_t i = 0, size_t n = npos) const {
|
||||
if (i >= size()) { // bounds check
|
||||
return -1;
|
||||
}
|
||||
n = fennec::min(n, fennec::max(_str, str.size()) + 1);
|
||||
|
||||
return ::wcsncmp(_str.data() + i, str, n);
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief String Comparison
|
||||
/// \param ostr the string to compare against
|
||||
/// \returns Zero if both strings are equal, otherwise a negative value if lhs appears before rhs according to the
|
||||
/// current locale, otherwise a positive value.
|
||||
constexpr int compare(const wstring& str, size_t i = 0, size_t n = npos) const {
|
||||
if (i >= size()) { // bounds check
|
||||
return -1;
|
||||
}
|
||||
n = min(n, max(size(), str.size()) + 1);
|
||||
|
||||
return ::wcsncmp(_str.data() + i, str, n);
|
||||
}
|
||||
|
||||
constexpr bool operator==(const _wstring& str) const {
|
||||
return compare(str) == 0;
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `c` in the string
|
||||
/// \param c the character 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
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t find(const wstring& str, size_t i = 0) const { // bounds check
|
||||
if (i >= size()) { // bounds check
|
||||
return size();
|
||||
}
|
||||
|
||||
const wchar_t* loc = ::wcsstr(_str, str);
|
||||
return loc ? loc - _str : size();
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the first occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t find(const wcstring& str, size_t i = 0) const {
|
||||
if (i + str.size() > size()) { // bounds check
|
||||
return size();
|
||||
}
|
||||
|
||||
const wchar_t* loc = ::wcsstr(_str + i, str); // get location using strstr
|
||||
return loc ? loc - _str : size(); // return size if not found
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `c` in the string.
|
||||
/// \param c the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(wchar_t c, size_t i = npos) const {
|
||||
if (size() == 0) {
|
||||
return size();
|
||||
}
|
||||
i = min(i, size() - 1); // clamp i to bounds
|
||||
do {
|
||||
if (_str[i] == c) { // loop backwards looking for c
|
||||
return i;
|
||||
}
|
||||
} while (i--);
|
||||
return size(); // base case
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
|
||||
if (size() == 0) {
|
||||
return size();
|
||||
}
|
||||
const wchar_t first = str[0];
|
||||
i = min(i, size() - str.size());
|
||||
do {
|
||||
if(_str[i] == first) {
|
||||
if (compare(str, i) == 0) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} while (i--);
|
||||
return size(); // base case
|
||||
}
|
||||
|
||||
///
|
||||
/// \brief Finds the index of the last occurrence of `str` in the string.
|
||||
/// \param str the string to find
|
||||
/// \param i the index to start at
|
||||
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()`
|
||||
constexpr size_t rfind(const wstring& str, size_t i = npos) const {
|
||||
if (size() == 0) {
|
||||
return size();
|
||||
}
|
||||
const wchar_t first = str[0];
|
||||
i = min(i, size() - str.size());
|
||||
do {
|
||||
if(_str[i] == first) {
|
||||
if (compare(str, i) == 0) { // loop backwards looking for str
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} while (i--);
|
||||
return size(); // base case
|
||||
}
|
||||
|
||||
// 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
|
||||
/// \return
|
||||
constexpr wstring substring(size_t i, size_t n = npos) const {
|
||||
if (i >= size()) {
|
||||
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
|
||||
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
|
||||
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
|
||||
return res;
|
||||
}
|
||||
|
||||
constexpr wstring& operator+=(wchar_t c) {
|
||||
size_t x = size();
|
||||
resize(x + 1);
|
||||
_str[x] = c;
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr wstring& operator+=(const wcstring& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::wmemcpy(&_str[x], str, str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
constexpr wstring& operator+=(const wstring& str) {
|
||||
size_t x = size();
|
||||
resize(x + str.size());
|
||||
fennec::wmemcpy(&_str[x], str, str.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
alloc_t _str;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif // FENNEC_LANGPROC_wstringS_wstring_H
|
||||
Reference in New Issue
Block a user