- Documentation of containers, core, and format

This commit is contained in:
2025-12-18 00:00:36 -05:00
parent e7503ed92f
commit 9e6f00eb60
57 changed files with 2007 additions and 805 deletions

View File

@@ -260,7 +260,7 @@ INHERIT_DOCS = YES
# of the file/class/namespace that contains it. # of the file/class/namespace that contains it.
# The default value is: NO. # The default value is: NO.
SEPARATE_MEMBER_PAGES = NO SEPARATE_MEMBER_PAGES = YES
# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen # The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
# uses this value to replace tabs by spaces in code fragments. # uses this value to replace tabs by spaces in code fragments.
@@ -944,7 +944,6 @@ WARN_LOGFILE =
# Note: If this tag is empty the current directory is searched. # Note: If this tag is empty the current directory is searched.
INPUT = "@PROJECT_SOURCE_DIR@/include" \ INPUT = "@PROJECT_SOURCE_DIR@/include" \
"@PROJECT_SOURCE_DIR@/source" \
"@PROJECT_SOURCE_DIR@/README.md" "@PROJECT_SOURCE_DIR@/README.md"
# This tag can be used to specify the character encoding of the source files # This tag can be used to specify the character encoding of the source files
@@ -1050,6 +1049,7 @@ RECURSIVE = YES
# run. # run.
EXCLUDE = "@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/wayland/lib" \ EXCLUDE = "@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/wayland/lib" \
"@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/wayland/libdecor" \
"@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/xkb/lib" "@PROJECT_SOURCE_DIR@/include/fennec/platform/linux/xkb/lib"
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
@@ -2511,7 +2511,7 @@ EXTERNAL_PAGES = YES
# and usage relations if the target is undocumented or is not a class. # and usage relations if the target is undocumented or is not a class.
# The default value is: YES. # The default value is: YES.
HIDE_UNDOC_RELATIONS = YES HIDE_UNDOC_RELATIONS = NO
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
# available from the path. This tool is part of Graphviz (see: # available from the path. This tool is part of Graphviz (see:

View File

@@ -44,17 +44,17 @@ namespace fennec
/// \brief Data Structure that defines a compile-time allocated array /// \brief Data Structure that defines a compile-time allocated array
/// ///
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:----------:|:----------:| /// |:----------:|:-----------:|
/// | stable | ✅ | /// | stable | ✅ |
/// | dynamic | ⛔ | /// | dynamic | ⛔ |
/// | homogenous | ✅ | /// | homogenous | ✅ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | space | \f$O(N)\f$ |
/// | linear | ✅ | /// | linear | ✅ |
/// | access | \f$O(1)\f$ | /// | access | \f$O(1)\f$ |
/// | find | \f$O(N)\f$ | /// | find | \f$O(N)\f$ |
/// | insertion | ⛔ | /// | insertion | ⛔ |
/// | deletion | ⛔ | /// | deletion | ⛔ |
/// ///
@@ -65,7 +65,7 @@ struct array {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
using value_t = ValueT; ///< Alias for `ValueT` using value_t = ValueT; ///< Alias for \f$ValueT\f$
// Public Members ====================================================================================================== // Public Members ======================================================================================================
@@ -105,7 +105,15 @@ public:
/// @{ /// @{
/// ///
/// \copydetails array::operator[](size_t) const /// \details Returns a reference to the element at \c i
/// \param i index of the element to return
/// \return reference to the requested element
///
/// \par Time-Complexity
/// Constant
///
/// \par Space-Complexity
/// Constant
constexpr value_t& 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 data[i]; return data[i];
@@ -219,7 +227,7 @@ public:
private: private:
template<size_t...i> template<size_t...i>
static bool _compare(const array& lhs, const array& rhs, index_metasequence<i...>) { static bool _compare(const array& lhs, const array& rhs, index_metasequence<i...>) {
return ((lhs[i] == rhs[i]) && ...); return ((lhs[i] == rhs[i]) and ...);
} }
}; };

View File

@@ -48,18 +48,18 @@ template<typename TypeT, class AllocT = allocator<TypeT>>
struct bintree { struct bintree {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
protected: private:
struct node; struct node;
public: public:
using value_t = TypeT; using value_t = TypeT; //!< The element type
using alloc_t = allocator_traits<AllocT>::template rebind<node>; using alloc_t = allocator_traits<AllocT>::template rebind<node>; //!< The allocator type
static constexpr size_t npos = -1; static constexpr size_t npos = -1; //!< null position constant
friend class iterator; friend class iterator;
friend class const_iterator; friend class const_iterator;
protected: private:
struct node { struct node {
value_t value; value_t value;
size_t parent; size_t parent;
@@ -144,7 +144,7 @@ public:
} }
/// ///
/// \returns `true` when there are no elements in the tree, `false` otherwise. /// \returns \f$true\f$ when there are no elements in the tree, \f$false\f$ otherwise.
constexpr bool empty() const { constexpr bool empty() const {
return _size == 0; return _size == 0;
} }
@@ -156,7 +156,7 @@ public:
} }
/// ///
/// \returns The next id to be returned by `insert` or `emplace`. /// \returns The next id to be returned by \f$insert\f$ or \f$emplace\f$.
constexpr size_t next_id() const { constexpr size_t next_id() const {
size_t i = _size; size_t i = _size;
if (not _freed.empty()) { if (not _freed.empty()) {
@@ -166,7 +166,7 @@ public:
} }
/// ///
/// \returns The next id to be returned by `insert` or `emplace`. /// \returns The next id to be returned by \f$insert\f$ or \f$emplace\f$.
constexpr size_t root() const { constexpr size_t root() const {
return _root; return _root;
} }
@@ -182,7 +182,7 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns The parent of node `i` /// \returns The parent of node \f$i\f$
constexpr size_t parent(size_t i) const { constexpr size_t parent(size_t i) const {
return i == npos ? npos : _table[i].parent; return i == npos ? npos : _table[i].parent;
} }
@@ -190,7 +190,7 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns The grandparent of node `i` /// \returns The grandparent of node \f$i\f$
constexpr size_t grandparent(size_t i) const { constexpr size_t grandparent(size_t i) const {
return parent(parent(i)); return parent(parent(i));
} }
@@ -198,7 +198,7 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns The left child of node `i` /// \returns The left child of node \f$i\f$
constexpr size_t left(size_t i) const { constexpr size_t left(size_t i) const {
return i == npos ? npos : _table[i].child[false]; return i == npos ? npos : _table[i].child[false];
} }
@@ -206,7 +206,7 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns The right child of node `i` /// \returns The right child of node \f$i\f$
constexpr size_t right(size_t i) const { constexpr size_t right(size_t i) const {
return i == npos ? npos : _table[i].child[true]; return i == npos ? npos : _table[i].child[true];
} }
@@ -214,8 +214,8 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \param dir The direction to go `true` for right, `false` for left /// \param dir The direction to go \f$true\f$ for right, \f$false\f$ for left
/// \returns The child in the direction specified by `dir` /// \returns The child in the direction specified by \f$dir\f$
constexpr size_t child(size_t i, bool dir) const { constexpr size_t child(size_t i, bool dir) const {
return i == npos ? npos : _table[i].child[dir]; return i == npos ? npos : _table[i].child[dir];
} }
@@ -223,7 +223,7 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns `true` if `i` is the right node of `parent(i)`, `false` otherwise /// \returns \f$true\f$ if \f$i\f$ is the right node of `parent(i)`, \f$false\f$ otherwise
constexpr bool direction(size_t i) const { constexpr bool direction(size_t i) const {
return i == npos ? false : i == right(_parent(i)); return i == npos ? false : i == right(_parent(i));
} }
@@ -231,7 +231,7 @@ public:
/// ///
/// \brief \f$O(1)\f$ /// \brief \f$O(1)\f$
/// \param i The id of the node /// \param i The id of the node
/// \returns The id of the sibling of `i` /// \returns The id of the sibling of \f$i\f$
constexpr size_t sibling(size_t i) const { constexpr size_t sibling(size_t i) const {
if (i == npos) { if (i == npos) {
return npos; return npos;
@@ -247,7 +247,7 @@ public:
/// ///
/// \details \f$O(\log n)\f$ /// \details \f$O(\log n)\f$
/// \param i The node id /// \param i The node id
/// \returns The depth of node `i` /// \returns The depth of node \f$i\f$
constexpr size_t depth(size_t i) const { constexpr size_t depth(size_t i) const {
size_t d = 0; size_t d = 0;
while (i != npos) { while (i != npos) {
@@ -260,7 +260,7 @@ public:
/// ///
/// \brief \f$O(\log n)\f$ /// \brief \f$O(\log n)\f$
/// \param i The node id /// \param i The node id
/// \returns The id of the left-most node of `i` /// \returns The id of the left-most node of \f$i\f$
constexpr size_t left_most(size_t i) const { constexpr size_t left_most(size_t i) const {
if (i >= _table.size()) { if (i >= _table.size()) {
return npos; return npos;
@@ -274,7 +274,7 @@ public:
/// ///
/// \brief \f$O(\log n)\f$ /// \brief \f$O(\log n)\f$
/// \param i The node id /// \param i The node id
/// \returns The id of the right-most node of `i` /// \returns The id of the right-most node of \f$i\f$
constexpr size_t right_most(size_t i) const { constexpr size_t right_most(size_t i) const {
if (i >= _table.size()) { if (i >= _table.size()) {
return npos; return npos;
@@ -297,7 +297,7 @@ public:
/// ///
/// \details \f$O(1)\f$ /// \details \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i` /// \returns \f$nullptr\f$ if node \f$i\f$ does not exist, otherwise, a pointer to the value of node \f$i\f$
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assertd(i < _table.size(), "Index out of bounds."); assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value; return _table[i].value;
@@ -306,7 +306,7 @@ public:
/// ///
/// \details Const Access, \f$O(1)\f$ /// \details Const Access, \f$O(1)\f$
/// \param i The node id /// \param i The node id
/// \returns `nullptr` if node `i` does not exist, otherwise, a pointer to the value of node `i` /// \returns \f$nullptr\f$ if node \f$i\f$ does not exist, otherwise, a pointer to the value of node \f$i\f$
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assertd(i < _table.size(), "Index out of bounds."); assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value; return _table[i].value;
@@ -320,8 +320,8 @@ public:
/// @{ /// @{
/// ///
/// \brief Move Left Insertion, constructs a new node as the left child of `p` /// \brief Move Left Insertion, constructs a new node as the left child of \f$p\f$
/// \details If the left node of `p` already exists, the move assignment operator is used instead /// \details If the left node of \f$p\f$ already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to move into the new node /// \param val The object to move into the new node
/// \returns The id of the new node /// \returns The id of the new node
@@ -330,8 +330,8 @@ public:
} }
/// ///
/// \brief Copy Left Insertion, constructs a new node as the left child of `p` /// \brief Copy Left Insertion, constructs a new node as the left child of \f$p\f$
/// \details If the left node of `p` already exists, the copy assignment operator is used instead /// \details If the left node of \f$p\f$ already exists, the copy assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to copy to the new node /// \param val The object to copy to the new node
/// \returns The id of the new node /// \returns The id of the new node
@@ -340,8 +340,8 @@ public:
} }
/// ///
/// \brief Emplace Left Insertion, constructs a new node as the left child of `p` /// \brief Emplace Left Insertion, constructs a new node as the left child of \f$p\f$
/// \details If the left node of `p` already exists, the move assignment operator is used instead /// \details If the left node of \f$p\f$ already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param args The arguments to construct the new node with /// \param args The arguments to construct the new node with
/// \returns The id of the new node /// \returns The id of the new node
@@ -351,8 +351,8 @@ public:
} }
/// ///
/// \brief Move Right Insertion, constructs a new node as the right child of `p` /// \brief Move Right Insertion, constructs a new node as the right child of \f$p\f$
/// \details If the right node of `p` already exists, the move assignment operator is used instead /// \details If the right node of \f$p\f$ already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to move into the new node /// \param val The object to move into the new node
/// \returns The id of the new node /// \returns The id of the new node
@@ -361,8 +361,8 @@ public:
} }
/// ///
/// \brief Copy Right Insertion, constructs a new node as the right child of `p` /// \brief Copy Right Insertion, constructs a new node as the right child of \f$p\f$
/// \details If the right node of `p` already exists, the copy assignment operator is used instead /// \details If the right node of \f$p\f$ already exists, the copy assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param val The object to copy to the new node /// \param val The object to copy to the new node
/// \returns The id of the new node /// \returns The id of the new node
@@ -371,8 +371,8 @@ public:
} }
/// ///
/// \brief Emplace Right Insertion, constructs a new node as the right child of `p` /// \brief Emplace Right Insertion, constructs a new node as the right child of \f$p\f$
/// \details If the right node of `p` already exists, the move assignment operator is used instead /// \details If the right node of \f$p\f$ already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param args The arguments to construct the new node with /// \param args The arguments to construct the new node with
/// \returns The id of the new node /// \returns The id of the new node
@@ -384,9 +384,9 @@ public:
/// ///
/// \brief Perform a Tree Rotation at `i` in the specified direction /// \brief Perform a Tree Rotation at \f$i\f$ in the specified direction
/// \param sub The root node for the rotation /// \param sub The root node for the rotation
/// \param dir The direction to rotate, `true` for right, `false` for left /// \param dir The direction to rotate, \f$true\f$ for right, \f$false\f$ for left
/// \returns the new root /// \returns the new root
constexpr size_t rotate(size_t sub, bool dir) { constexpr size_t rotate(size_t sub, bool dir) {
if (sub == npos) { if (sub == npos) {
@@ -413,8 +413,8 @@ public:
} }
/// ///
/// \brief Move Insertion, bool d, constructs a new node as the child of `p` /// \brief Move Insertion, bool d, constructs a new node as the child of \f$p\f$
/// \details If the child of `p` already exists, the move assignment operator is used instead /// \details If the child of \f$p\f$ already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param d The direction to insert /// \param d The direction to insert
/// \param val The object to move into the new node /// \param val The object to move into the new node
@@ -424,8 +424,8 @@ public:
} }
/// ///
/// \brief Copy Insertion, bool d, constructs a new node as the child of `p` /// \brief Copy Insertion, bool d, constructs a new node as the child of \f$p\f$
/// \details If the child of `p` already exists, the copy assignment operator is used instead /// \details If the child of \f$p\f$ already exists, the copy assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param d The direction to insert /// \param d The direction to insert
/// \param val The object to copy to the new node /// \param val The object to copy to the new node
@@ -435,8 +435,8 @@ public:
} }
/// ///
/// \brief Emplace Insertion, constructs a new node as the child of `p` /// \brief Emplace Insertion, constructs a new node as the child of \f$p\f$
/// \details If the child of `p` already exists, the move assignment operator is used instead /// \details If the child of \f$p\f$ already exists, the move assignment operator is used instead
/// \param p The parent node /// \param p The parent node
/// \param d The direction to insert /// \param d The direction to insert
/// \param args The arguments to construct the new node with /// \param args The arguments to construct the new node with
@@ -482,7 +482,7 @@ public:
/// \brief Traverse the tree using a specified order and visiting functor /// \brief Traverse the tree using a specified order and visiting functor
/// ///
/// \details /// \details
/// The visitor should accept a reference to a value of type `TypeT` and a `size_t` which contains the node's id. /// The visitor should accept a reference to a value of type \f$TypeT\f$ and a `size_t` which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum /// The visitor should return one of the following values in the `fennec::traversal_control_` enum
/// ///
/// \tparam OrderT The order with which to traverse the tree. /// \tparam OrderT The order with which to traverse the tree.
@@ -508,13 +508,21 @@ public:
/// ///
/// \brief Traverser pattern for breadth-first traversal /// \brief Traverser pattern for breadth-first traversal
struct breadth_first { struct breadth_first {
list<size_t> visit;
size_t head;
///
/// \brief Traversal Init
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
size_t operator()(const bintree&, size_t start) { size_t operator()(const bintree&, size_t start) {
return head = start; return head = start;
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \param mode The mode specifying branch conditions
/// \returns The next index according to the traversal order
size_t operator[](const bintree& tree, size_t node, uint8_t mode) { size_t operator[](const bintree& tree, size_t node, uint8_t mode) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -541,19 +549,31 @@ public:
return node; return node;
} }
private:
list<size_t> visit;
size_t head;
}; };
/// ///
/// \brief Traverser pattern for pre-order traversal /// \brief Traverser pattern for pre-order traversal
struct pre_order { struct pre_order {
list<size_t> visit;
size_t head;
///
/// \brief Traversal Init
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const bintree&, size_t start) { constexpr size_t operator()(const bintree&, size_t start) {
head = start; head = start;
return start; return start;
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \param mode The mode specifying branch conditions
/// \returns The next index according to the traversal order
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t mode) { constexpr size_t operator[](const bintree& tree, size_t node, uint8_t mode) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -580,19 +600,31 @@ public:
return node; return node;
} }
private:
list<size_t> visit;
size_t head;
}; };
/// ///
/// \brief Traverser pattern for in-order traversal /// \brief Traverser pattern for in-order traversal
struct in_order { struct in_order {
list<size_t> visit;
size_t head;
///
/// \brief Traversal Init
/// \param tree The tree we are operating on
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const bintree& tree, size_t start) { constexpr size_t operator()(const bintree& tree, size_t start) {
head = start; head = start;
return tree.left_most(start); return tree.left_most(start);
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \returns The next index according to the traversal order
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) { constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -619,33 +651,31 @@ public:
return node; return node;
} }
private:
list<size_t> visit;
size_t head;
}; };
/// ///
/// \brief Traverser pattern for post-order traversal /// \brief Traverser pattern for post-order traversal
struct post_order { struct post_order {
list<size_t> visit;
size_t head;
constexpr size_t successor(const bintree& tree, size_t n) {
size_t s = tree.left_most(n);
while (n == s) {
size_t r = tree.right(n);
if (r != npos) {
n = r;
s = tree.left_most(n);
} else {
break;
}
}
return s == npos ? n : s;
}
///
/// \brief Traversal Init
/// \param tree The tree we are operating on
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const bintree& tree, size_t start) { constexpr size_t operator()(const bintree& tree, size_t start) {
head = start; head = start;
return this->successor(tree, start); return this->_successor(tree, start);
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \returns The next index according to the traversal order
constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) { constexpr size_t operator[](const bintree& tree, size_t node, uint8_t) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -659,7 +689,7 @@ public:
visit.push_front(parent); visit.push_front(parent);
} }
} else if (pright != npos) { } else if (pright != npos) {
visit.push_front(this->successor(tree, pright)); visit.push_front(this->_successor(tree, pright));
} }
if (not visit.empty()) { if (not visit.empty()) {
@@ -672,23 +702,50 @@ public:
return node; return node;
} }
private:
list<size_t> visit;
size_t head;
constexpr size_t _successor(const bintree& tree, size_t n) {
size_t s = tree.left_most(n);
while (n == s) {
size_t r = tree.right(n);
if (r != npos) {
n = r;
s = tree.left_most(n);
} else {
break;
}
}
return s == npos ? n : s;
}
}; };
// Iterator ============================================================================================================ // Iterator ============================================================================================================
///
/// \brief C++ Iterator Specification `iterator`
/// \details Performs pre-order traversal
class iterator { class iterator {
protected:
bintree* _tree;
in_order _order;
size_t _n;
public: public:
///
/// \brief bintree iterator constructor
/// \param tree A reference to the tree
/// \param root The root node for iteration
constexpr iterator(bintree* tree, size_t root) constexpr iterator(bintree* tree, size_t root)
: _tree(tree) : _tree(tree)
, _order() , _order()
, _n(_order(*tree, root)) { , _n(_order(*tree, root)) {
} }
///
/// \brief bintree iterator constructor
/// \param tree A reference to the tree
/// \param root The root node for iteration
/// \param node The node to jump to
constexpr iterator(bintree* tree, size_t root, size_t node) constexpr iterator(bintree* tree, size_t root, size_t node)
: _tree(tree) : _tree(tree)
, _order() , _order()
@@ -696,42 +753,171 @@ public:
_order.head = root; _order.head = root;
} }
///
/// \returns The index of the current node
size_t index() const { size_t index() const {
return _n; return _n;
} }
///
/// \brief iterator pre-increment operator
/// \returns A reference to self after having stepped to the next node
iterator& operator++() { iterator& operator++() {
return _n = _order[*_tree, _n, traversal_control_continue], *this; return _n = _order[*_tree, _n, traversal_control_continue], *this;
} }
///
/// \brief dereference operator
/// \returns the value held in the current node
value_t& operator*() { value_t& operator*() {
return (*_tree)[_n]; return (*_tree)[_n];
} }
value_t* operator->() { ///
return &(*_tree)[_n]; /// \returns the value held in the current node
}
const value_t& operator*() const { const value_t& operator*() const {
return (*_tree)[_n]; return (*_tree)[_n];
} }
///
/// \brief pointer access operator
/// \returns a reference to the value held in the current node
value_t* operator->() {
return &(*_tree)[_n];
}
///
/// \returns a reference to the value held in the current node
const value_t* operator->() const { const value_t* operator->() const {
return &(*_tree)[_n]; return &(*_tree)[_n];
} }
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are identical, \f$false\f$ otherwise
constexpr bool operator==(const iterator& it) { constexpr bool operator==(const iterator& it) {
return _tree == it._tree and _n == it._n; return _tree == it._tree and _n == it._n;
} }
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are different, \f$false\f$ otherwise
constexpr bool operator!=(const iterator& it) { constexpr bool operator!=(const iterator& it) {
return _tree != it._tree or _n != it._n; return _tree != it._tree or _n != it._n;
} }
private:
bintree* _tree;
in_order _order;
size_t _n;
}; };
///
/// \brief C++ Iterator Specification `iterator`
/// \details Performs pre-order traversal
class const_iterator {
public:
///
/// \brief bintree iterator constructor
/// \param tree A reference to the tree
/// \param root The root node for iteration
constexpr const_iterator(bintree* tree, size_t root)
: _tree(tree)
, _order()
, _n(_order(*tree, root)) {
}
///
/// \brief bintree iterator constructor
/// \param tree A reference to the tree
/// \param root The root node for iteration
/// \param node The node to jump to
constexpr const_iterator(bintree* tree, size_t root, size_t node)
: _tree(tree)
, _order()
, _n(node) {
_order.head = root;
}
///
/// \returns The index of the current node
size_t index() const {
return _n;
}
///
/// \brief iterator pre-increment operator
/// \returns A reference to self after having stepped to the next node
const_iterator& operator++() {
return _n = _order[*_tree, _n, traversal_control_continue], *this;
}
///
/// \returns the value held in the current node
const value_t& operator*() const {
return (*_tree)[_n];
}
///
/// \returns a reference to the value held in the current node
const value_t* operator->() const {
return &(*_tree)[_n];
}
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are identical, \f$false\f$ otherwise
constexpr bool operator==(const iterator& it) {
return _tree == it._tree and _n == it._n;
}
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if iterators are different, \f$false\f$ otherwise
constexpr bool operator!=(const iterator& it) {
return _tree != it._tree or _n != it._n;
}
private:
bintree* _tree;
in_order _order;
size_t _n;
};
///
/// \returns an iterator at the first element in pre-order traversal
iterator begin() {
return iterator(this, _root);
}
///
/// \brief C++ Iterator Specification `begin()`
/// \returns an iterator at the first element in pre-order traversal
const_iterator begin() const {
return iterator(this, _root);
}
///
/// \returns an iterator at the first element in pre-order traversal
iterator end() {
return iterator(this, _root, nullid);
}
///
/// \brief C++ Iterator Specification `begin()`
/// \returns an iterator at the first element in pre-order traversal
const_iterator end() const {
return iterator(this, _root, nullid);
}
// Fields ============================================================================================================== // Fields ==============================================================================================================
protected: private:
table_t _table; table_t _table;
freed_t _freed; freed_t _freed;
size_t _root, _size; size_t _root, _size;

View File

@@ -43,14 +43,24 @@ namespace fennec
/// \tparam N The number of bits in the bitfield /// \tparam N The number of bits in the bitfield
template<size_t N> template<size_t N>
struct bitfield { struct bitfield {
static constexpr size_t bits = N;
static constexpr size_t bytes = (N + 7) / 8;
// Constants ===========================================================================================================
public: public:
static constexpr size_t bits = N; //!< The number of bits in the bitfield
static constexpr size_t bytes = (N + 7) / 8; //!< The number of bytes that hold the bitfield
// Constructors ========================================================================================================
public:
///
/// \brief default constructor, initializes with \f$0\f$
constexpr bitfield() constexpr bitfield()
: _bytes() { : _bytes() {
} }
///
/// \brief boolean array constructor
/// \param arr An array of boolean values resembling each bit.
explicit constexpr bitfield(const bool (&arr)[N]) explicit constexpr bitfield(const bool (&arr)[N])
: _bytes() { : _bytes() {
for (size_t i = 0; i < arr; ++i) { for (size_t i = 0; i < arr; ++i) {
@@ -58,6 +68,9 @@ public:
} }
} }
///
/// \brief index array constructor
/// \param arr An array of indices values resembling which bits to set.
template<size_t I> template<size_t I>
explicit constexpr bitfield(const size_t (&arr)[I]) explicit constexpr bitfield(const size_t (&arr)[I])
: _bytes() { : _bytes() {
@@ -66,12 +79,17 @@ public:
} }
} }
///
/// \brief variadic array constructor
/// \param args A set of indices values resembling which bits to set.
template<typename...ArgsT> template<typename...ArgsT>
constexpr bitfield(ArgsT&&...args) constexpr bitfield(ArgsT&&...args)
: _bytes() { : _bytes() {
(this->store(fennec::forward<ArgsT>(args), true), ...); (this->store(fennec::forward<ArgsT>(args), true), ...);
} }
///
/// \param args A set of boolean values resembling each bit.
template<typename...ArgsT> requires((is_bool_v<ArgsT> or is_convertible_v<ArgsT, bool>) and ...) template<typename...ArgsT> requires((is_bool_v<ArgsT> or is_convertible_v<ArgsT, bool>) and ...)
constexpr bitfield(ArgsT&&...args) constexpr bitfield(ArgsT&&...args)
: _bytes() { : _bytes() {
@@ -79,19 +97,40 @@ public:
(this->store(i++, fennec::forward<ArgsT>(args)), ...); (this->store(i++, fennec::forward<ArgsT>(args)), ...);
} }
///
/// \brief copy constructor
/// \param bf bitfield to copy
bitfield(const bitfield& bf) bitfield(const bitfield& bf)
: _bytes(bf._bytes) { : _bytes(bf._bytes) {
} }
///
/// \brief move constructor
/// \param bf bitfield to move
bitfield(bitfield&& bf) noexcept bitfield(bitfield&& bf) noexcept
: _bytes(bf._bytes) { : _bytes(bf._bytes) {
} }
///
/// \brief destructor
constexpr ~bitfield() = default; constexpr ~bitfield() = default;
///
/// \brief copy assignment
/// \param bf bitfield to copy
/// \returns a reference to self
bitfield& operator=(const bitfield& bf) = default; bitfield& operator=(const bitfield& bf) = default;
///
/// \brief move assignment
/// \param bf bitfield to move
/// \returns a reference to self
bitfield& operator=(bitfield&& bf) noexcept = default; bitfield& operator=(bitfield&& bf) noexcept = default;
///
/// \brief test a bit
/// \param i the index of the bit
/// \returns the value stored in the bit as a boolean
bool test(size_t i) const { bool test(size_t i) const {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
@@ -99,6 +138,9 @@ public:
return _bytes[b] & (1 << o); return _bytes[b] & (1 << o);
} }
///
/// \brief set a bit
/// \param i the index of the bit
void set(size_t i) { void set(size_t i) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
@@ -106,6 +148,9 @@ public:
_bytes[b] |= (1 << o); _bytes[b] |= (1 << o);
} }
///
/// \brief clear a bit
/// \param i the index of the bit
void clear(size_t i) { void clear(size_t i) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
@@ -113,6 +158,9 @@ public:
_bytes[b] &= ~(1 << o); _bytes[b] &= ~(1 << o);
} }
///
/// \brief toggle a bit
/// \param i the index of the bit
void toggle(size_t i) { void toggle(size_t i) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
@@ -120,6 +168,10 @@ public:
_bytes[b] ^= (1 << o); _bytes[b] ^= (1 << o);
} }
///
/// \brief store \f$v\f$ in bit \f$i\f$
/// \param i
/// \param v
void store(size_t i, bool v) { void store(size_t i, bool v) {
assertd(i < bits, "Index out of Bounds!"); assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8; size_t b = i / 8;
@@ -127,6 +179,9 @@ public:
(_bytes[b] &= ~((1 << o))) |= ((v << o)); (_bytes[b] &= ~((1 << o))) |= ((v << o));
} }
///
/// \brief not operator
/// \returns a bitfield containing the bit-wise inverse
bitfield operator~() const { bitfield operator~() const {
bitfield res = *this; bitfield res = *this;
res._inv_helper(make_index_metasequence_t<bytes>{}); res._inv_helper(make_index_metasequence_t<bytes>{});

View File

@@ -84,8 +84,8 @@ private:
}; };
public: public:
using alloc_t = allocator_traits<AllocT>::template rebind<node>; using alloc_t = allocator_traits<AllocT>::template rebind<node>; //!< The underlying allocator type
using elem_t = node*; using elem_t = node*; //!< The underlying element type
// Constructors ======================================================================================================== // Constructors ========================================================================================================
@@ -153,7 +153,7 @@ public:
/// @{ /// @{
/// ///
/// \returns `true` when the deque is empty, `false` otherwise /// \returns \f$true\f$ when the deque is empty, \f$false\f$ otherwise
constexpr bool empty() const { constexpr bool empty() const {
return _size == 0; return _size == 0;
} }

View File

@@ -101,7 +101,7 @@ public:
} }
/// ///
/// \brief Sized Allocation, initializes a dynarray with `n` elements using the default constructor. /// \brief Sized Allocation, initializes a dynarray with \f$n\f$ elements using the default constructor.
/// \param n The number of elements. /// \param n The number of elements.
explicit constexpr dynarray(size_t n) explicit constexpr dynarray(size_t n)
: _alloc(n) : _alloc(n)
@@ -114,7 +114,7 @@ public:
} }
/// ///
/// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator `alloc` and `n` elements /// \brief Sized Allocation Alloc Constructor, initializes a dynarray with allocator \f$alloc\f$ and \f$n\f$ elements
/// using the default constructor. /// using the default constructor.
/// \param n The number of elements /// \param n The number of elements
/// \param alloc The allocator object to copy /// \param alloc The allocator object to copy
@@ -128,7 +128,7 @@ public:
} }
/// ///
/// \brief Sized Allocation Alloc Move Constructor, initializes a dynarray with allocator `alloc` and `n` elements /// \brief Sized Allocation Alloc Move Constructor, initializes a dynarray with allocator \f$alloc\f$ and \f$n\f$ elements
/// using the default constructor. /// using the default constructor.
/// \param n The number of elements /// \param n The number of elements
/// \param alloc The allocator object to copy /// \param alloc The allocator object to copy
@@ -142,7 +142,7 @@ public:
} }
/// ///
/// \brief Sized Allocation Copy Constructor, Create an allocation of size `n` elements, with each element /// \brief Sized Allocation Copy Constructor, Create an allocation of size \f$n\f$ elements, with each element
/// constructed using the copy constructor /// constructed using the copy constructor
/// \param n the number of elements /// \param n the number of elements
/// \param val the value to copy /// \param val the value to copy
@@ -267,7 +267,7 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param arr the array to copy /// \param arr the array to copy
/// \returns A dynarray after having copied each element of `arr` /// \returns A dynarray after having copied each element of \f$arr\f$
constexpr dynarray& operator=(const dynarray& arr) { constexpr dynarray& operator=(const dynarray& arr) {
this->clear(); this->clear();
_alloc.creallocate(_size = arr._size); _alloc.creallocate(_size = arr._size);
@@ -280,7 +280,7 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param arr the array to move /// \param arr the array to move
/// \returns A dynarray after having taken ownership of the contents of `arr` /// \returns A dynarray after having taken ownership of the contents of \f$arr\f$
constexpr dynarray& operator=(dynarray&& arr) noexcept { constexpr dynarray& operator=(dynarray&& arr) noexcept {
this->clear(); this->clear();
_alloc = fennec::move(arr._alloc); _alloc = fennec::move(arr._alloc);
@@ -293,7 +293,7 @@ public:
/// \brief Array Copy Assignment Operator /// \brief Array Copy Assignment Operator
/// \tparam N the length of the array /// \tparam N the length of the array
/// \param arr the array to copy /// \param arr the array to copy
/// \returns A dynarray after having copied each element of `arr` /// \returns A dynarray after having copied each element of \f$arr\f$
template<size_t N> template<size_t N>
constexpr dynarray& operator=(const TypeT (&arr)[N]) { constexpr dynarray& operator=(const TypeT (&arr)[N]) {
this->clear(); this->clear();
@@ -308,7 +308,7 @@ public:
/// \brief Array Copy Assignment Operator /// \brief Array Copy Assignment Operator
/// \tparam N the length of the array /// \tparam N the length of the array
/// \param arr the array to copy /// \param arr the array to copy
/// \returns A dynarray after having moved each element of `arr` /// \returns A dynarray after having moved each element of \f$arr\f$
template<size_t N> template<size_t N>
constexpr dynarray& operator=(TypeT (&&arr)[N]) { constexpr dynarray& operator=(TypeT (&&arr)[N]) {
this->clear(); this->clear();
@@ -355,7 +355,7 @@ public:
/// ///
/// \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 element at index `i` /// \returns A reference to the element at index \f$i\f$
constexpr TypeT& operator[](size_t i) { constexpr TypeT& operator[](size_t i) {
assertd(i < _size, "Array Out of Bounds"); assertd(i < _size, "Array Out of Bounds");
return _alloc.data()[i]; return _alloc.data()[i];
@@ -364,7 +364,7 @@ public:
/// ///
/// \brief Array Access Operator (const) /// \brief Array Access Operator (const)
/// \param i The index to access /// \param i The index to access
/// \returns A const qualified reference to the element at index `i` /// \returns A const qualified reference to the element at index \f$i\f$
constexpr const TypeT& operator[](size_t i) const { constexpr const TypeT& operator[](size_t i) const {
assertd(i < _size, "Array Out of Bounds"); assertd(i < _size, "Array Out of Bounds");
return _alloc.data()[i]; return _alloc.data()[i];
@@ -547,22 +547,21 @@ public:
/// @{ /// @{
/// ///
/// \brief "Iterator" Begin Function
/// \returns A pointer to the first element in the dynarray /// \returns A pointer to the first element in the dynarray
constexpr TypeT* begin() { return _alloc.data(); } constexpr TypeT* begin() { return _alloc.data(); }
/// ///
/// \brief "Iterator" End Function /// \brief C++ Iterator Specification `begin()`
/// \returns A const qualified pointer to the first element in the dynarray
constexpr const TypeT* begin() const { return _alloc; }
///
/// \return A pointer to the address after the last element in the dynarray /// \return A pointer to the address after the last element in the dynarray
constexpr TypeT* end() { return begin() + _size; } constexpr TypeT* end() { return begin() + _size; }
/// ///
/// \brief Const "Iterator" Begin Function /// \brief C++ Iterator Specification `end()`
/// \returns A const qualified pointer to the first element in the dynarray
constexpr const TypeT* begin() const { return _alloc; }
///
/// \brief Const "Iterator" End Function
/// \return A const qualified pointer to the address after the last element in the dynarray /// \return A const qualified pointer to the address after the last element in the dynarray
constexpr const TypeT* end() const { return begin() + _size; } constexpr const TypeT* end() const { return begin() + _size; }

View File

@@ -115,10 +115,15 @@ public:
// Properties ========================================================================================================== // Properties ==========================================================================================================
///
/// \brief runtime type acquisition
/// \returns a runtime type struct referencing the held type
type type() const { type type() const {
return *static_cast<fennec::type*>(_manage(op_type, nullptr)); return *static_cast<fennec::type*>(_manage(op_type, nullptr));
} }
///
/// \returns \f$true\f$ if there is a held value, \f$false\f$ otherwise
bool has_value() const { bool has_value() const {
return _handle != nullptr; return _handle != nullptr;
} }
@@ -126,6 +131,10 @@ public:
// Assignment ========================================================================================================== // Assignment ==========================================================================================================
///
/// \brief copy assignment
/// \param gen the generic to copy
/// \returns a reference to self after copying the contents of \f$gen\f$
generic& operator=(const generic& gen) { generic& operator=(const generic& gen) {
if (this == &gen) { // self-assignment case if (this == &gen) { // self-assignment case
return *this; return *this;
@@ -137,14 +146,20 @@ public:
return *this; return *this;
} }
///
/// \brief move assignment
/// \param gen the generic to move
/// \returns a reference to self after swapping contents with \f$gen\f$
generic& operator=(generic&& gen) noexcept { generic& operator=(generic&& gen) noexcept {
swap(gen); swap(gen);
return *this; return *this;
} }
///
// Utility ============================================================================================================= /// \brief value assignment
/// \tparam T the type of the value
/// \param x the value to assign
/// \returns a reference to self after having assigned \f$x\f$
template<typename T> template<typename T>
generic& operator=(T&& x) { generic& operator=(T&& x) {
reset(); reset();
@@ -153,6 +168,16 @@ public:
return *this; return *this;
} }
// Utility =============================================================================================================
///
/// \brief emplace value
///
/// \details constructs a new value of type \f$T\f$ using \f$args...\f$
/// \tparam T the type to construct
/// \tparam ArgsT the argument types
/// \param args the argument values
template<typename T, typename...ArgsT> template<typename T, typename...ArgsT>
void emplace(ArgsT&&...args) { void emplace(ArgsT&&...args) {
reset(); reset();
@@ -160,6 +185,9 @@ public:
_manage = _manage_impl<T>; _manage = _manage_impl<T>;
} }
///
/// \brief reset value
/// \details clears the held value using the appropriate destructor
void reset() { void reset() {
if (_manage) { if (_manage) {
_handle = _manage(op_destroy, _handle); _handle = _manage(op_destroy, _handle);
@@ -167,19 +195,32 @@ public:
} }
} }
///
/// \brief C++ 11 Swap Specification
/// \param gen the generic to swap with
void swap(generic& gen) noexcept { void swap(generic& gen) noexcept {
fennec::swap(_handle, gen._handle); fennec::swap(_handle, gen._handle);
fennec::swap(_manage, gen._manage); fennec::swap(_manage, gen._manage);
} }
template<typename T> ///
T& cast() { /// \brief cast value
return *static_cast<T*>(_handle); ///
/// \details equivalent to `reinterpret_cast`
/// \tparam T The type to cast to
/// \returns The contents of generic after having cast to \f$T\f$
template<typename T, typename U = remove_cvref_t<T>>
T cast() {
return static_cast<T>(*static_cast<U*>(_handle));
} }
template<typename T> ///
const T& cast() const { /// \details equivalent to `reinterpret_cast`
return *static_cast<T*>(_handle); /// \tparam T The type to cast to
/// \returns The contents of generic after having cast to \f$T\f$
template<typename T, typename U = remove_cvref_t<T>>
T cast() const {
return static_cast<T>(*static_cast<U*>(_handle));
} }
private: private:

View File

@@ -79,10 +79,10 @@ namespace fennec
/// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would /// A directed graph is weakly connected if replacing all of its directed edges with undirected edges would
/// produce a connected graph. We will call this "disjointed" /// produce a connected graph. We will call this "disjointed"
/// ///
/// A directed graph is semi-connected if there is a directed path p for `u` &rarr; `v` *or* `v` &rarr; `u` for every /// A directed graph is semi-connected if there is a directed path p for \f$u\f$ &rarr; \f$v\f$ *or* \f$v\f$ &rarr; \f$u\f$ for every
/// pair of vertices `u, v`. We will call this "unilateral" /// pair of vertices `u, v`. We will call this "unilateral"
/// ///
/// A directed graph is strongly-connected if there is a directed path p for `u` &rarr; `v` *and* `v` &rarr; `u` for every pair /// A directed graph is strongly-connected if there is a directed path p for \f$u\f$ &rarr; \f$v\f$ *and* \f$v\f$ &rarr; \f$u\f$ for every pair
/// of vertices `u, v`. We will call this "connected" /// of vertices `u, v`. We will call this "connected"
/// ///
/// \tparam VertexT The type associated with each vertex /// \tparam VertexT The type associated with each vertex
@@ -159,35 +159,35 @@ public:
} }
/// ///
/// \returns `true` when there are no vertices in the graph, `false` otherwise /// \returns \f$true\f$ when there are no vertices in the graph, \f$false\f$ otherwise
constexpr bool empty() const { constexpr bool empty() const {
return num_vertices() == 0; return num_vertices() == 0;
} }
/// ///
/// \brief Checks if there exists an edge `e` that starts from `a` and ends at `b` /// \brief Checks if there exists an edge \f$e\f$ that starts from \f$a\f$ and ends at \f$b\f$
/// \param a The first vertex /// \param a The first vertex
/// \param b The second vertex /// \param b The second vertex
/// \returns `true` if the edge exists, `false` otherwise /// \returns \f$true\f$ if the edge exists, \f$false\f$ otherwise
constexpr bool exists(size_t a, size_t b) const { constexpr bool exists(size_t a, size_t b) const {
return _edge_map[a][b] != nullptr; return _edge_map[a][b] != nullptr;
} }
/// ///
/// \brief Checks if there exists an edge `e0` that starts from `a` and ends at `b` and `e1` that starts from `b` /// \brief Checks if there exists an edge \f$e0\f$ that starts from \f$a\f$ and ends at \f$b\f$ and \f$e1\f$ that starts from \f$b\f$
/// and ends at `a` /// and ends at \f$a\f$
/// \param a The first vertex /// \param a The first vertex
/// \param b The second vertex /// \param b The second vertex
/// \returns `true` if both edges exist, `false` otherwise /// \returns \f$true\f$ if both edges exist, \f$false\f$ otherwise
constexpr bool is_symmetric(size_t a, size_t b) const { constexpr bool is_symmetric(size_t a, size_t b) const {
return exists(a, b) and exists(b, a); return exists(a, b) and exists(b, a);
} }
/// ///
/// \brief Checks if there exists an edge `e` between `a` and `b` /// \brief Checks if there exists an edge \f$e\f$ between \f$a\f$ and \f$b\f$
/// \param a The first vertex /// \param a The first vertex
/// \param b The second vertex /// \param b The second vertex
/// \returns `true` if both edges exist, `false` otherwise /// \returns \f$true\f$ if both edges exist, \f$false\f$ otherwise
constexpr bool is_undirected(size_t a, size_t b) const { constexpr bool is_undirected(size_t a, size_t b) const {
const auto* e0 = _edge_map[a][b]; const auto* e0 = _edge_map[a][b];
const auto* e1 = _edge_map[b][a]; const auto* e1 = _edge_map[b][a];
@@ -227,7 +227,7 @@ public:
/// \brief edge Access Operator /// \brief edge Access Operator
/// \param a The id of the first vertex /// \param a The id of the first vertex
/// \param b The id of the second vertex /// \param b The id of the second vertex
/// \returns A pointer to the value stored in the edge, `nullptr` if not found /// \returns A pointer to the value stored in the edge, \f$nullptr\f$ if not found
constexpr edge_t* operator[](size_t a, size_t b) { constexpr edge_t* operator[](size_t a, size_t b) {
if (empty()) { if (empty()) {
return nullptr; return nullptr;
@@ -243,7 +243,7 @@ public:
/// \brief edge Const Access Operator /// \brief edge Const Access Operator
/// \param a The id of the first vertex /// \param a The id of the first vertex
/// \param b The id of the second vertex /// \param b The id of the second vertex
/// \returns A const-qualified pointer to the value stored in the edge, `nullptr` if not found /// \returns A const-qualified pointer to the value stored in the edge, \f$nullptr\f$ if not found
constexpr const edge_t* operator[](size_t a, size_t b) const { constexpr const edge_t* operator[](size_t a, size_t b) const {
if (empty()) { if (empty()) {
return nullptr; return nullptr;
@@ -256,9 +256,9 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to `x...` /// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge to `x...`
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices `x` with edges from `vertex` to `x...` /// \returns A list containing all vertices \f$x\f$ with edges from \f$vertex\f$ to `x...`
list<size_t> outgoing(size_t vertex) { list<size_t> outgoing(size_t vertex) {
list<size_t> res; list<size_t> res;
if (empty() || vertex >= _edge_map.size()) { if (empty() || vertex >= _edge_map.size()) {
@@ -271,9 +271,9 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices `x` that `vertex` has an edge from `x...` /// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge from `x...`
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices `x` with edges from `x...` to `vertex` /// \returns A list containing all vertices \f$x\f$ with edges from `x...` to \f$vertex\f$
list<size_t> incoming(size_t vertex) { list<size_t> incoming(size_t vertex) {
list<size_t> res; list<size_t> res;
if (empty() || vertex >= _edge_map.size()) { if (empty() || vertex >= _edge_map.size()) {
@@ -288,9 +288,9 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...` /// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge to and from `x...`
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex` /// \returns A list containing all vertices \f$x\f$ that have symmetric edges with \f$vertex\f$
list<size_t> symmetric(size_t vertex) { list<size_t> symmetric(size_t vertex) {
list<size_t> res; list<size_t> res;
if (empty() || vertex >= _edge_map.size()) { if (empty() || vertex >= _edge_map.size()) {
@@ -305,13 +305,13 @@ public:
} }
/// ///
/// \brief Getter for a list of vertices `x` that `vertex` has an edge to and from `x...` and share the same value /// \brief Getter for a list of vertices \f$x\f$ that \f$vertex\f$ has an edge to and from `x...` and share the same value
/// \details /// \details
/// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be /// "Joined" edges may also be referred to as "undirected." A joined, or undirected, edge may be
/// turned into a directed edge by changing the weight object associated with the edge, or by /// turned into a directed edge by changing the weight object associated with the edge, or by
/// removing one of the sub-edges. /// removing one of the sub-edges.
/// \param vertex The id of the vertex /// \param vertex The id of the vertex
/// \returns A list containing all vertices `x` that have symmetric edges with `vertex` /// \returns A list containing all vertices \f$x\f$ that have symmetric edges with \f$vertex\f$
list<size_t> undirected(size_t vertex) { list<size_t> undirected(size_t vertex) {
list<size_t> res; list<size_t> res;
if (empty() || vertex >= _edge_map.size()) { if (empty() || vertex >= _edge_map.size()) {
@@ -381,7 +381,7 @@ public:
} }
/// ///
/// \brief Form an edge from vertex `a` to vertex `b` /// \brief Form an edge from vertex \f$a\f$ to vertex \f$b\f$
/// \tparam ArgsT The argument types /// \tparam ArgsT The argument types
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
@@ -408,7 +408,7 @@ public:
} }
/// ///
/// \brief Form an undirected edge between vertex `a` and vertex `b` /// \brief Form an undirected edge between vertex \f$a\f$ and vertex \f$b\f$
/// \tparam ArgsT The argument types /// \tparam ArgsT The argument types
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
@@ -437,7 +437,7 @@ public:
} }
/// ///
/// \brief Disconnect an edge from vertex `a` to vertex `b` /// \brief Disconnect an edge from vertex \f$a\f$ to vertex \f$b\f$
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
constexpr void cut_edge(size_t a, size_t b) { constexpr void cut_edge(size_t a, size_t b) {
@@ -460,7 +460,7 @@ public:
} }
/// ///
/// \brief Disconnect both directed edges between vertices `a` and `b` /// \brief Disconnect both directed edges between vertices \f$a\f$ and \f$b\f$
/// \param a The first vertex id /// \param a The first vertex id
/// \param b The second vertex id /// \param b The second vertex id
constexpr void cut_edge2(size_t a, size_t b) { constexpr void cut_edge2(size_t a, size_t b) {
@@ -476,7 +476,7 @@ public:
} }
/// ///
/// \brief Break *all* edges to and from `n` /// \brief Break *all* edges to and from \f$n\f$
/// \param n The vertex id /// \param n The vertex id
void cut(size_t n) { void cut(size_t n) {
for (const auto it : outgoing(n)) { for (const auto it : outgoing(n)) {

View File

@@ -42,11 +42,17 @@ namespace fennec
using std::initializer_list; using std::initializer_list;
///
/// \param inls the initializer list
/// \returns A const qualified pointer to the first element in \f$inls\f$
template<typename T> template<typename T>
constexpr const T* begin(initializer_list<T> inls) noexcept { constexpr const T* begin(initializer_list<T> inls) noexcept {
return inls.begin(); return inls.begin();
} }
///
/// \param inls the initializer list
/// \returns A const qualified pointer to one past the last element in \f$inls\f$
template<typename T> template<typename T>
constexpr const T* end(initializer_list<T> inls) noexcept { constexpr const T* end(initializer_list<T> inls) noexcept {
return inls.end(); return inls.end();

View File

@@ -95,7 +95,7 @@ public:
} }
/// ///
/// \brief Copy Constructor, copies all elements in `l` with optimized layout /// \brief Copy Constructor, copies all elements in \f$l\f$ with optimized layout
/// \param l The list to copy /// \param l The list to copy
constexpr list(const list& l) constexpr list(const list& l)
: list() { : list() {
@@ -134,7 +134,7 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param l the list to copy /// \param l the list to copy
/// \returns `this` after having copied all elements of `l` /// \returns \f$this\f$ after having copied all elements of \f$l\f$
constexpr list& operator=(const list& l) { constexpr list& operator=(const list& l) {
this->clear(); this->clear();
for (const value_t& it : l) { for (const value_t& it : l) {
@@ -146,7 +146,7 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param l the list to copy /// \param l the list to copy
/// \returns `this` after having taken ownership over the contents of `l` /// \returns \f$this\f$ after having taken ownership over the contents of \f$l\f$
constexpr list& operator=(list&& l) noexcept { constexpr list& operator=(list&& l) noexcept {
this->clear(); this->clear();
_table = fennec::move(l._table); _table = fennec::move(l._table);
@@ -177,7 +177,7 @@ public:
} }
/// ///
/// \returns `true` when the list is empty, `false` otherwise. /// \returns \f$true\f$ when the list is empty, \f$false\f$ otherwise.
constexpr bool empty() const { constexpr bool empty() const {
return _root == npos; return _root == npos;
} }
@@ -193,7 +193,7 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i Index to access /// \param i Index to access
/// \returns A reference to the element at `i` /// \returns A reference to the element at \f$i\f$
/// ///
/// \details \f$O(N)\f$ /// \details \f$O(N)\f$
constexpr value_t& operator[](int i) { constexpr value_t& operator[](int i) {
@@ -206,7 +206,7 @@ public:
/// ///
/// \brief Const Array Access Operator /// \brief Const Array Access Operator
/// \param i Index to access /// \param i Index to access
/// \returns A const-qualified reference to the element at `i` /// \returns A const-qualified reference to the element at \f$i\f$
/// ///
/// \details \f$O(N)\f$ /// \details \f$O(N)\f$
constexpr const value_t& operator[](int i) const { constexpr const value_t& operator[](int i) const {
@@ -417,7 +417,6 @@ public:
/// @{ /// @{
/// ///
/// \brief C++ Iterator Specification `begin()`
/// \returns An iterator for the first element in the list /// \returns An iterator for the first element in the list
constexpr iterator begin() { constexpr iterator begin() {
return iterator(this, _root); return iterator(this, _root);
@@ -431,7 +430,6 @@ public:
} }
/// ///
/// \brief Const C++ Iterator Specification `begin()`
/// \returns A const iterator for the first element in the list /// \returns A const iterator for the first element in the list
constexpr const_iterator begin() const { constexpr const_iterator begin() const {
return const_iterator(this, _root); return const_iterator(this, _root);
@@ -447,37 +445,60 @@ public:
/// @} /// @}
/// ///
/// \brief Iterator Class /// \brief C++ Iterator Specification `iterator`
class iterator { class iterator {
public: public:
///
/// \brief destructor
~iterator() { ~iterator() {
_list = nullptr; _list = nullptr;
} }
// prefix operator ///
/// \brief prefix increment operator
/// \param rhs the iterator to increment
/// \returns \f$rhs\f$ after having moved to the next element in the list
constexpr friend iterator& operator++(iterator& rhs) { constexpr friend iterator& operator++(iterator& rhs) {
rhs._n = rhs._list->_next(rhs._n); rhs._n = rhs._list->_next(rhs._n);
return rhs; return rhs;
} }
///
/// \brief postfix increment operator
/// \param lhs the iterator to increment
/// \returns \f$lhs\f$ before having moved to the next element in the list
constexpr friend iterator operator++(iterator& lhs, int) { constexpr friend iterator operator++(iterator& lhs, int) {
iterator prev = lhs; iterator prev = lhs;
++lhs; ++lhs;
return prev; return prev;
} }
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
constexpr value_t& operator*() { constexpr value_t& operator*() {
return *(_list->_table[_n].value); return *(_list->_table[_n].value);
} }
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
constexpr value_t* operator->() { constexpr value_t* operator->() {
return &*(_list->_table[_n].value); return &*(_list->_table[_n].value);
} }
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
constexpr bool operator==(const iterator& it) { constexpr bool operator==(const iterator& it) {
return _list == it._list and _n == it._n; return _list == it._list and _n == it._n;
} }
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
constexpr bool operator!=(const iterator& it) { constexpr bool operator!=(const iterator& it) {
return _list != it._list or _n != it._n; return _list != it._list or _n != it._n;
} }
@@ -497,11 +518,16 @@ public:
/// \brief Iterator Class for Const Access /// \brief Iterator Class for Const Access
class const_iterator { class const_iterator {
public: public:
///
/// \brief destructor
~const_iterator() { ~const_iterator() {
_list = nullptr; _list = nullptr;
} }
// prefix operator ///
/// \brief prefix increment operator
/// \param rhs the iterator to increment
/// \returns \f$rhs\f$ after having moved to the next element in the list
constexpr friend const_iterator& operator++(const_iterator& rhs) { constexpr friend const_iterator& operator++(const_iterator& rhs) {
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) { if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
return rhs; return rhs;
@@ -510,24 +536,42 @@ public:
return rhs; return rhs;
} }
///
/// \brief postfix increment operator
/// \param lhs the iterator to increment
/// \returns \f$lhs\f$ before having moved to the next element in the list
constexpr friend const_iterator operator++(const_iterator& lhs, int) { constexpr friend const_iterator operator++(const_iterator& lhs, int) {
const_iterator prev = lhs; const_iterator prev = lhs;
++lhs; ++lhs;
return prev; return prev;
} }
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
constexpr const value_t& operator*() { constexpr const value_t& operator*() {
return *(_list->_table[_n].value); return *(_list->_table[_n].value);
} }
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
constexpr const value_t* operator->() { constexpr const value_t* operator->() {
return &*(_list->_table[_n].value); return &*(_list->_table[_n].value);
} }
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
constexpr bool operator==(const const_iterator& it) { constexpr bool operator==(const const_iterator& it) {
return _list == it._list and _n == it._n; return _list == it._list and _n == it._n;
} }
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
constexpr bool operator!=(const const_iterator& it) { constexpr bool operator!=(const const_iterator& it) {
return _list != it._list or _n != it._n; return _list != it._list or _n != it._n;
} }

View File

@@ -56,7 +56,7 @@ namespace fennec
*/ */
/// ///
/// \brief Data Structure defining a mapping of `key` \f$KeyT\f$ to `value` \f$ValueT\f$ /// \brief Data Structure defining a mapping of \f$key\f$ \f$KeyT\f$ to \f$value\f$ \f$ValueT\f$
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:----------:|:----------:| /// |:----------:|:----------:|
@@ -91,15 +91,26 @@ public:
using set_t = set<elem_t, key_hash, key_equals, alloc_t>; ///< The underlying set using set_t = set<elem_t, key_hash, key_equals, alloc_t>; ///< The underlying set
using iterator = set_t::iterator; ///< Iterator type using iterator = set_t::iterator; ///< Iterator type
// We only want to hash the key ///
/// \brief key hash helper
struct key_hash : hash_t { struct key_hash : hash_t {
///
/// \brief C++ 11 Hash Specification `operator()`
/// \param p the pair to hash
/// \returns the hash of the key
constexpr size_t operator()(const elem_t& p) const { constexpr size_t operator()(const elem_t& p) const {
return hash_t::operator()(p.first); return hash_t::operator()(p.first);
} }
}; };
// We only want to compare the keys ///
/// \brief key comparison helper
struct key_equals : equality<KeyT> { struct key_equals : equality<KeyT> {
///
/// \brief C++ 11 Compare Specification `operator()`
/// \param a the first pair
/// \param b the second pair
/// \returns \f$true\f$ if the keys are equal, \f$false\f$ otherwise
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);
} }
@@ -134,7 +145,7 @@ public:
} }
/// ///
/// \returns `true` when there are no elements in the set, `false` otherwise /// \returns \f$true\f$ when there are no elements in the set, \f$false\f$ otherwise
constexpr size_t empty() const { constexpr size_t empty() const {
return _set.size(); return _set.size();
} }
@@ -156,7 +167,7 @@ public:
/// ///
/// \brief Key Access Operator /// \brief Key Access Operator
/// \param key Key value to access /// \param key Key value to access
/// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present. /// \returns A pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present.
constexpr value_t* operator[](const KeyT& key) { constexpr value_t* operator[](const KeyT& key) {
auto it = _set.at(this->_find(key)); auto it = _set.at(this->_find(key));
return it ? &it->second : nullptr; return it ? &it->second : nullptr;
@@ -165,7 +176,7 @@ public:
/// ///
/// \brief Key Const Access Operator /// \brief Key Const Access Operator
/// \param key Key value to access /// \param key Key value to access
/// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present. /// \returns A const-qualified pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present.
constexpr const value_t* operator[](const KeyT& key) const { constexpr const value_t* operator[](const KeyT& key) const {
auto it = _set.at(this->_find(key)); auto it = _set.at(this->_find(key));
return it ? &it->second : nullptr; return it ? &it->second : nullptr;
@@ -175,7 +186,7 @@ public:
/// \brief Argument Key Access Operator /// \brief Argument Key Access Operator
/// \tparam ArgsT Argument Types /// \tparam ArgsT Argument Types
/// \param args Arguments to construct the key with /// \param args Arguments to construct the key with
/// \returns A pointer to the value associated with `key`, `nullptr` if `key` is not present. /// \returns A pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present.
template<typename...ArgsT> template<typename...ArgsT>
constexpr value_t* operator[](ArgsT&&...args) { constexpr value_t* operator[](ArgsT&&...args) {
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...)); auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));
@@ -186,7 +197,7 @@ public:
/// \brief Argument Key Const Access Operator /// \brief Argument Key Const Access Operator
/// \tparam ArgsT Argument Type /// \tparam ArgsT Argument Type
/// \param args Argument to construct the key with /// \param args Argument to construct the key with
/// \returns A const-qualified pointer to the value associated with `key`, `nullptr` if `key` is not present. /// \returns A const-qualified pointer to the value associated with \f$key\f$, \f$nullptr\f$ if \f$key\f$ is not present.
template<typename...ArgsT> template<typename...ArgsT>
constexpr const value_t* operator[](ArgsT&&...args) const { constexpr const value_t* operator[](ArgsT&&...args) const {
auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...)); auto it = _set.at(this->_find(fennec::forward<ArgsT>(args)...));

View File

@@ -47,10 +47,10 @@ struct object_pool {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
using value_t = TypeT; using value_t = TypeT; //!< The held object type
using elem_t = optional<value_t>; using elem_t = optional<value_t>; //!< The element type
using table_t = dynarray<elem_t, AllocT>; using table_t = dynarray<elem_t, AllocT>; //!< The underlying table type
using freed_t = list<size_t, AllocT>; using freed_t = list<size_t, AllocT>; //!< The underlying free queue
class iterator; class iterator;
class const_iterator; class const_iterator;
@@ -92,13 +92,13 @@ public:
} }
/// ///
/// \returns `true` when there are no objects in the pool, `false` otherwise /// \returns \f$true\f$ when there are no objects in the pool, \f$false\f$ otherwise
constexpr bool empty() const { constexpr bool empty() const {
return size() == 0; return size() == 0;
} }
/// ///
/// \brief Retrieve the next id `i` that would be assigned to an object `o` were it added to the object pool /// \brief Retrieve the next id \f$i\f$ that would be assigned to an object \f$o\f$ were it added to the object pool
/// ///
/// \details This can be useful if there are constant members that need to be assigned at construction. /// \details This can be useful if there are constant members that need to be assigned at construction.
/// \returns The id of the next inserted node /// \returns The id of the next inserted node
@@ -120,7 +120,7 @@ public:
/// ///
/// \brief Array Access Operator /// \brief Array Access Operator
/// \param i id of the object /// \param i id of the object
/// \returns a reference to the object with id `i` /// \returns a reference to the object with id \f$i\f$
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
assert(_table[i], "Attempted to access null object.") assert(_table[i], "Attempted to access null object.")
@@ -130,7 +130,7 @@ public:
/// ///
/// \brief Array Const Access Operator /// \brief Array Const Access Operator
/// \param i id of the object /// \param i id of the object
/// \returns a const-qualified reference to the object with id `i` /// \returns a const-qualified reference to the object with id \f$i\f$
constexpr const value_t& operator[](size_t i) const { constexpr const value_t& operator[](size_t i) const {
assert(i < capacity(), "Index out of Bounds!"); assert(i < capacity(), "Index out of Bounds!");
assert(_table[i], "Attempted to access null object.") assert(_table[i], "Attempted to access null object.")
@@ -146,7 +146,7 @@ public:
/// @{ /// @{
/// ///
/// \brief Move Insertion, inserts `x` into the pool /// \brief Move Insertion, inserts \f$x\f$ into the pool
/// \param x the object to move /// \param x the object to move
/// \returns An integer corresponding to the id of the node /// \returns An integer corresponding to the id of the node
constexpr size_t insert(value_t&& x) { constexpr size_t insert(value_t&& x) {
@@ -154,7 +154,7 @@ public:
} }
/// ///
/// \brief Move Insertion, inserts a copy of `x` into the pool /// \brief Move Insertion, inserts a copy of \f$x\f$ into the pool
/// \param x the object to copy /// \param x the object to copy
/// \returns An integer corresponding to the id of the node /// \returns An integer corresponding to the id of the node
constexpr size_t insert(const value_t& x) { constexpr size_t insert(const value_t& x) {
@@ -195,62 +195,108 @@ public:
// Iterator ============================================================================================================ // Iterator ============================================================================================================
///
/// \returns an iterator at the start of the object pool
iterator begin() { iterator begin() {
return iterator(this, 0); return iterator(this, 0);
} }
iterator end() { ///
return iterator(this, _size); /// \brief C++ Iterator Specification `begin()`
} /// \returns an iterator at the start of the object pool
const_iterator begin() const { const_iterator begin() const {
return iterator(this, 0); return iterator(this, 0);
} }
///
/// \returns an iterator at the start of the end of the object pool
iterator end() {
return iterator(this, _size);
}
///
/// \brief C++ Iterator Specification `end()`
/// \returns an iterator at the start of the end of the object pool
const_iterator end() const { const_iterator end() const {
return iterator(this, _size); return iterator(this, _size);
} }
///
/// \brief C++ Iterator Specification `iterator`
class iterator { class iterator {
public: public:
iterator(object_pool* pool, size_t start) ///
: pool(pool), curr(start) { /// \brief copy constructor
_fix(); /// \param it the iterator to copy
} iterator(const iterator& it) = default;
iterator(const iterator&) = default; ///
iterator(iterator&&) noexcept = default; /// \brief move constructor
/// \param it the iterator to move
iterator(iterator&& it) noexcept = default;
///
/// \brief public destructor
~iterator() = default; ~iterator() = default;
iterator& operator=(const iterator&) = default;
iterator& operator=(iterator&&) noexcept = default;
iterator operator++(int) { ///
iterator ret = *this; /// \brief copy assignment
++curr; /// \param it the iterator to copy
_fix(); /// \returns a reference to self after having copied \f$it\f$
iterator& operator=(const iterator& it) = default;
///
/// \brief move assignment
/// \param it the iterator to move
/// \returns a reference to self after having moved \f$it\f$
iterator& operator=(iterator&& it) noexcept = default;
///
/// \brief postfix increment operator
/// \returns \f$it\f$ before having been incremented
friend iterator operator++(iterator& it, int) {
iterator ret = it;
++it.curr;
it._fix();
return ret; return ret;
} }
iterator& operator++() { ///
++curr; /// \brief prefix increment operator
_fix(); /// \returns \f$it\f$ after having moved to the next element
return *this; friend iterator& operator++(iterator& it) {
++it.curr;
it._fix();
return it;
} }
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
value_t& operator*() const { value_t& operator*() const {
return *pool->_table[curr]; return *pool->_table[curr];
} }
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
value_t* operator->() const { value_t* operator->() const {
return *pool->_table[curr]; return *pool->_table[curr];
} }
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
bool operator==(const iterator& it) { bool operator==(const iterator& it) {
return pool == it.pool and curr == it.curr; return pool == it.pool and curr == it.curr;
} }
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
bool operator!=(const iterator& it) { bool operator!=(const iterator& it) {
return pool != it.pool or curr != it.curr; return pool != it.pool or curr != it.curr;
} }
@@ -264,48 +310,91 @@ public:
++curr; ++curr;
} }
} }
};
class const_iterator { iterator(object_pool* pool, size_t start)
public:
const_iterator(const object_pool* pool, size_t start)
: pool(pool), curr(start) { : pool(pool), curr(start) {
_fix(); _fix();
} }
const_iterator(const const_iterator&) = default; friend struct object_pool;
const_iterator(const_iterator&&) noexcept = default; };
///
/// \brief C++ Iterator Specification `const_iterator`
class const_iterator {
public:
///
/// \brief copy constructor
/// \param it the iterator to copy
const_iterator(const const_iterator&it ) = default;
///
/// \brief move constructor
/// \param it the iterator to move
const_iterator(const_iterator&& it) noexcept = default;
///
/// \brief public destructor
~const_iterator() = default; ~const_iterator() = default;
const_iterator& operator=(const const_iterator&) = default;
const_iterator& operator=(const_iterator&&) noexcept = default;
const_iterator operator++(int) { ///
const_iterator ret = *this; /// \brief copy assignment
++curr; /// \param it the iterator to copy
_fix(); /// \returns a reference to self after having copied \f$it\f$
const_iterator& operator=(const const_iterator& it) = default;
///
/// \brief move assignment
/// \param it the iterator to move
/// \returns a reference to self after having moved \f$it\f$
const_iterator& operator=(const_iterator&& it) noexcept = default;
///
/// \brief postfix increment operator
/// \returns \f$it\f$ before having been incremented
friend const_iterator operator++(const_iterator& it, int) {
const_iterator ret = it;
++it.curr;
it._fix();
return ret; return ret;
} }
const_iterator& operator++() { ///
++curr; /// \brief prefix increment operator
_fix(); /// \returns \f$it\f$ after having moved to the next element
return *this; friend const_iterator& operator++(const_iterator& it) {
++it.curr;
it._fix();
return it;
} }
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
const value_t& operator*() const { const value_t& operator*() const {
return *pool->_table[curr]; return *pool->_table[curr];
} }
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
const value_t* operator->() const { const value_t* operator->() const {
return *pool->_table[curr]; return *pool->_table[curr];
} }
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
bool operator==(const const_iterator& it) { bool operator==(const const_iterator& it) {
return pool == it.pool and curr == it.curr; return pool == it.pool and curr == it.curr;
} }
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
bool operator!=(const const_iterator& it) { bool operator!=(const const_iterator& it) {
return pool != it.pool or curr != it.curr; return pool != it.pool or curr != it.curr;
} }
@@ -319,6 +408,13 @@ public:
++curr; ++curr;
} }
} }
const_iterator(const object_pool* pool, size_t start)
: pool(pool), curr(start) {
_fix();
}
friend struct object_pool;
}; };
private: private:

View File

@@ -38,10 +38,16 @@
namespace fennec namespace fennec
{ {
///
/// \brief struct to represent a \f$null\f$ `optional`
struct nullopt_t {}; struct nullopt_t {};
///
/// \brief value representing a \f$null\f$ `optional`
constexpr nullopt_t nullopt_v = {}; constexpr nullopt_t nullopt_v = {};
///
/// \brief alias for representing a \f$null\f$ `optional`
#define nullopt nullopt_v #define nullopt nullopt_v
/// ///
@@ -52,10 +58,10 @@ struct optional {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
using reference_t = T&; using reference_t = T&; //!< reference type
using pointer_t = T*; using pointer_t = T*; //!< pointer type
using const_reference_t = T&; using const_reference_t = T&; //!< const reference type
using const_pointer_t = const T*; using const_pointer_t = const T*; //!< const pointer type
// Constructors ======================================================================================================== // Constructors ========================================================================================================
@@ -116,12 +122,18 @@ public:
opt = nullopt; opt = nullopt;
} }
///
/// \brief Emplace Constructor
/// \tparam ArgsT The argument types
/// \param args The argument values
template<typename...ArgsT> template<typename...ArgsT>
constexpr optional(ArgsT&&...args) constexpr optional(ArgsT&&...args)
: _val(fennec::forward<ArgsT>(args)...) : _val(fennec::forward<ArgsT>(args)...)
, _set(true) { , _set(true) {
} }
///
/// \brief destructor
constexpr ~optional() { constexpr ~optional() {
if constexpr(is_fundamental_v<T>) { if constexpr(is_fundamental_v<T>) {
return; return;
@@ -141,13 +153,13 @@ public:
/// ///
/// \brief Implicit Boolean Check /// \brief Implicit Boolean Check
/// \returns `true` when there is a value contained /// \returns \f$true\f$ when there is a value contained
constexpr operator bool() const { constexpr operator bool() const {
return _set; return _set;
} }
/// ///
/// \returns `true` when there is no held value, `false` otherwise. /// \returns \f$true\f$ when there is no held value, \f$false\f$ otherwise.
constexpr bool empty() const { constexpr bool empty() const {
return not _set; return not _set;
} }
@@ -249,13 +261,13 @@ public:
/// @{ /// @{
/// ///
/// \returns A pointer to the value, `nullptr` if there is no value /// \returns A pointer to the value, \f$nullptr\f$ if there is no value
constexpr pointer_t operator->() noexcept { constexpr pointer_t operator->() noexcept {
return _set ? &_val : nullptr; return _set ? &_val : nullptr;
} }
/// ///
/// \returns A const-qualified pointer to the value, `nullptr` if there is no value /// \returns A const-qualified pointer to the value, \f$nullptr\f$ if there is no value
constexpr const_pointer_t operator->() const noexcept { constexpr const_pointer_t operator->() const noexcept {
return _set ? &_val : nullptr; return _set ? &_val : nullptr;
} }

View File

@@ -140,7 +140,7 @@ struct pair {
/// ///
/// \brief Equality Operator /// \brief Equality Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns `true` when both elements of each pair are equal /// \returns \f$true\f$ when both elements of each pair are equal
constexpr bool operator==(const pair& p) const { constexpr bool operator==(const pair& p) const {
return first == p.first and second == p.second; return first == p.first and second == p.second;
} }
@@ -148,7 +148,7 @@ struct pair {
/// ///
/// \brief Inequality Operator /// \brief Inequality Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns `true` when either element of each pair are equal /// \returns \f$true\f$ when either element of each pair are equal
constexpr bool operator!=(const pair& p) const { constexpr bool operator!=(const pair& p) const {
return first != p.first or second != p.second; return first != p.first or second != p.second;
} }
@@ -156,7 +156,7 @@ struct pair {
/// ///
/// \brief Less Than Operator /// \brief Less Than Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is less, or they are /// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is less, or they are
/// equal and the second element is less /// equal and the second element is less
constexpr bool operator<(const pair& p) const { constexpr bool operator<(const pair& p) const {
return first < p.first or (first == p.first and second < p.second); return first < p.first or (first == p.first and second < p.second);
@@ -165,7 +165,7 @@ struct pair {
/// ///
/// \brief Less Equal Operator /// \brief Less Equal Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is less, or they are /// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is less, or they are
/// equal and the second element is less or equal /// equal and the second element is less or equal
constexpr bool operator<=(const pair& p) const { constexpr bool operator<=(const pair& p) const {
return first < p.first or (first == p.first and second <= p.second); return first < p.first or (first == p.first and second <= p.second);
@@ -174,7 +174,7 @@ struct pair {
/// ///
/// \brief Greater Than Operator /// \brief Greater Than Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is greater, or they are /// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is greater, or they are
/// equal and the second element is greater /// equal and the second element is greater
constexpr bool operator>(const pair& p) const { constexpr bool operator>(const pair& p) const {
return first > p.first or (first == p.first and second > p.second); return first > p.first or (first == p.first and second > p.second);
@@ -183,7 +183,7 @@ struct pair {
/// ///
/// \brief Greater Equal Operator /// \brief Greater Equal Operator
/// \param p Pair to compare with /// \param p Pair to compare with
/// \returns lexical comparison of both elements, i.e. returns `true` when the first element is greater, or they are /// \returns lexical comparison of both elements, i.e. returns \f$true\f$ when the first element is greater, or they are
/// equal and the second element is greater or equal /// equal and the second element is greater or equal
constexpr bool operator>=(const pair& p) const { constexpr bool operator>=(const pair& p) const {
return first > p.first or (first == p.first and second >= p.second); return first > p.first or (first == p.first and second >= p.second);
@@ -192,8 +192,16 @@ struct pair {
/// @} /// @}
}; };
///
/// \brief C++ 11 Hash Specification for `pair<TypeT0, TypeT1>`
/// \tparam TypeT0 The first type of the pair
/// \tparam TypeT1 The second type of the pair
template<typename TypeT0, typename TypeT1> template<typename TypeT0, typename TypeT1>
struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> { struct hash<pair<TypeT0, TypeT1>> : hash<TypeT0>, hash<TypeT1> {
///
/// \brief C++ 11 Hash Specification `operator()`
/// \param p The pair to hash
/// \returns a pairing of the hashes of both elements of \f$p\f$ using `fennec::pair_hash`
constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const { constexpr size_t operator()(const pair<TypeT0, TypeT1>& p) const {
return fennec::pair_hash( // pair the hashes of both elements return fennec::pair_hash( // pair the hashes of both elements
hash<TypeT0>::operator()(p.first), hash<TypeT0>::operator()(p.first),

View File

@@ -53,16 +53,21 @@
namespace fennec namespace fennec
{ {
///
/// \brief a priority queue data structure implemented using a binary heap
/// \tparam ValueT The value type
/// \tparam CompareT The compare type, defaults to `fennec::less`
/// \tparam AllocT The allocator type, defaults to `fennec::allocator`
template<typename ValueT, class CompareT = less<ValueT>, class AllocT = allocator<ValueT>> template<typename ValueT, class CompareT = less<ValueT>, class AllocT = allocator<ValueT>>
struct priority_queue { struct priority_queue {
// Definitions & Constants ============================================================================================= // Definitions & Constants =============================================================================================
public: public:
using value_t = ValueT; using value_t = ValueT; //!< Alias for the value type
using compare_t = CompareT; using compare_t = CompareT; //!< Alias for the compare type
using alloc_t = allocation<value_t, AllocT>; using alloc_t = allocation<value_t, AllocT>; //!< The underlying allocation type
static constexpr size_t npos = -1; static constexpr size_t npos = -1; //!< value representing a null node
private: private:
constexpr size_t left(size_t n) const { constexpr size_t left(size_t n) const {
@@ -82,10 +87,15 @@ private:
// Constructors & Destructor =========================================================================================== // Constructors & Destructor ===========================================================================================
public: public:
///
/// \brief default constructor
/// \details initializes an empty queue
constexpr priority_queue() constexpr priority_queue()
: _size(0) { : _size(0) {
} }
///
/// \brief destructor
constexpr ~priority_queue() { constexpr ~priority_queue() {
while (_size > 0) { while (_size > 0) {
--_size; --_size;
@@ -96,14 +106,20 @@ public:
// Properties ========================================================================================================== // Properties ==========================================================================================================
///
/// \returns the size of the queue
constexpr size_t size() const { constexpr size_t size() const {
return _size; return _size;
} }
///
/// \returns the capacity of the underlying allocation
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _table.capacity(); return _table.capacity();
} }
///
/// \returns \f$true\f$ if the queue holds no elements
constexpr bool empty() const { constexpr bool empty() const {
return size() == 0; return size() == 0;
} }
@@ -111,6 +127,8 @@ public:
// Access ============================================================================================================== // Access ==============================================================================================================
///
/// \returns the value at the front of the queue
constexpr const value_t& front() const { constexpr const value_t& front() const {
return _table[0]; return _table[0];
} }
@@ -118,19 +136,30 @@ public:
// Modifiers =========================================================================================================== // Modifiers ===========================================================================================================
///
/// \brief push a new key into the queue
/// \param key the key to insert
constexpr void push(const value_t& key) { constexpr void push(const value_t& key) {
this->_insert(key); this->_insert(key);
} }
///
/// \param key the key to insert
constexpr void push(value_t&& key) { constexpr void push(value_t&& key) {
this->_insert(fennec::forward<value_t>(key)); this->_insert(fennec::forward<value_t>(key));
} }
///
/// \brief emplace a new key into the queue
/// \tparam ArgsT the argument types
/// \param args the argument values
template<typename...ArgsT> template<typename...ArgsT>
constexpr void emplace(ArgsT&&...args) { constexpr void emplace(ArgsT&&...args) {
this->_insert(fennec::forward<ArgsT>(args)...); this->_insert(fennec::forward<ArgsT>(args)...);
} }
///
/// \brief pop the element at the front of the queue
constexpr void pop() { constexpr void pop() {
fennec::swap(_table[0], _table[--_size]); fennec::swap(_table[0], _table[--_size]);
fennec::destruct(&_table[_size]); fennec::destruct(&_table[_size]);

View File

@@ -49,16 +49,16 @@ template<typename TypeT, typename AllocT = allocator<TypeT>>
struct rdtree { struct rdtree {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
protected: private:
struct node; struct node;
public: public:
using value_t = TypeT; using value_t = TypeT; //!< the held value type
using alloc_t = typename allocator_traits<AllocT>::template rebind<node>; using alloc_t = typename allocator_traits<AllocT>::template rebind<node>; //!< the underlying allocator type
static constexpr size_t root = 0; static constexpr size_t root = 0; //!< the id of the root node
static constexpr size_t npos = -1; static constexpr size_t npos = -1; //!< the id of a null node
protected: private:
struct node { struct node {
value_t value; value_t value;
size_t parent, child, prev, next; size_t parent, child, prev, next;
@@ -107,14 +107,14 @@ public:
} }
/// ///
/// \brief Copy Constructor, copies the contents of `tree` /// \brief Copy Constructor, copies the contents of \f$tree\f$
/// \param tree the rdtree to copy /// \param tree the rdtree to copy
constexpr rdtree(const rdtree& tree) constexpr rdtree(const rdtree& tree)
: _table(tree._table), _freed(tree._freed), _size(tree._size) { : _table(tree._table), _freed(tree._freed), _size(tree._size) {
} }
/// ///
/// \brief Move Constructor, takes ownership over the contents of `tree` /// \brief Move Constructor, takes ownership over the contents of \f$tree\f$
/// \param tree the rdtree to move /// \param tree the rdtree to move
constexpr rdtree(rdtree&& tree) noexcept constexpr rdtree(rdtree&& tree) noexcept
: _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) { : _table(fennec::move(tree._table)), _freed(fennec::move(tree._freed)), _size(tree._size) {
@@ -131,7 +131,7 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param rhs the rdtree to copy /// \param rhs the rdtree to copy
/// \returns `this` after copying the contents of `rhs` /// \returns \f$this\f$ after copying the contents of \f$rhs\f$
constexpr rdtree& operator=(const rdtree& rhs) { constexpr rdtree& operator=(const rdtree& rhs) {
for (value_t* it : this->_table) { for (value_t* it : this->_table) {
fennec::destruct(it); fennec::destruct(it);
@@ -145,7 +145,7 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param rhs the rdtree to move /// \param rhs the rdtree to move
/// \returns `this` after taking ownership over the contents of `rhs` /// \returns \f$this\f$ after taking ownership over the contents of \f$rhs\f$
constexpr rdtree& operator=(rdtree&& rhs) noexcept { constexpr rdtree& operator=(rdtree&& rhs) noexcept {
for (value_t* it : _table) { for (value_t* it : _table) {
fennec::destruct(it); fennec::destruct(it);
@@ -176,7 +176,7 @@ public:
} }
/// ///
/// \returns `true` when there are no nodes in the tree, `false` otherwise /// \returns \f$true\f$ when there are no nodes in the tree, \f$false\f$ otherwise
constexpr bool empty() const { constexpr bool empty() const {
return _size == 0; return _size == 0;
} }
@@ -256,7 +256,7 @@ public:
/// ///
/// \param i the node to start at /// \param i the node to start at
/// \returns the left-most child of node `i` /// \returns the left-most child of node \f$i\f$
constexpr size_t left_most(size_t i) const { constexpr size_t left_most(size_t i) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
size_t n = i; size_t n = i;
@@ -273,7 +273,7 @@ public:
/// ///
/// \param i the node to start at /// \param i the node to start at
/// \returns the right-most child of node `i` /// \returns the right-most child of node \f$i\f$
constexpr size_t right_most(size_t i) const { constexpr size_t right_most(size_t i) const {
if (i >= _table.capacity()) return npos; if (i >= _table.capacity()) return npos;
if ((i = child(i)) == npos) { if ((i = child(i)) == npos) {
@@ -308,7 +308,7 @@ public:
} }
/// ///
/// \returns The next node id were `insert` or `emplace` to be called /// \returns The next node id were \f$insert\f$ or \f$emplace\f$ to be called
constexpr size_t next_id() const { constexpr size_t next_id() const {
size_t i = _size; size_t i = _size;
if (not _freed.empty()) { if (not _freed.empty()) {
@@ -335,8 +335,8 @@ public:
// Insertion & Deletion ================================================================================================ // Insertion & Deletion ================================================================================================
/// ///
/// \brief Insertion, creates a node in the tree with parent `parent` /// \brief Insertion, creates a node in the tree with parent \f$parent\f$
/// \param parent the parent node, if `npos` sets the value of the root node /// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next /// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next
/// \param val the value to insert /// \param val the value to insert
/// \returns the index of the created node /// \returns the index of the created node
@@ -345,8 +345,8 @@ public:
} }
/// ///
/// \brief Insertion, creates a node in the tree with parent `parent` /// \brief Insertion, creates a node in the tree with parent \f$parent\f$
/// \param parent the parent node, if `npos` sets the value of the root node /// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \param next the next node, as an index relative to the parent /// \param next the next node, as an index relative to the parent
/// \param val the value to insert /// \param val the value to insert
/// \returns the index of the created node /// \returns the index of the created node
@@ -354,6 +354,12 @@ public:
return this->_insert(parent, next, fennec::forward<value_t>(val)); return this->_insert(parent, next, fennec::forward<value_t>(val));
} }
///
/// \brief tree insertion, copies the contents of tree into self with the root at the specified node location
/// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \param next the next node, as an index relative to the parent
/// \param tree the tree to insert
/// \returns the index of the inserted root
constexpr size_t insert(size_t parent, size_t next, const rdtree& tree) { constexpr size_t insert(size_t parent, size_t next, const rdtree& tree) {
list<pair<size_t, size_t>> visit; list<pair<size_t, size_t>> visit;
visit.push_front({ root, parent }); visit.push_front({ root, parent });
@@ -378,8 +384,8 @@ public:
} }
/// ///
/// \brief Insertion, creates a node in the tree with parent `parent` /// \brief Insertion, creates a node in the tree with parent \f$parent\f$
/// \param parent the parent node, if `npos` sets the value of the root node /// \param parent the parent node, if \f$npos\f$ sets the value of the root node
/// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next /// \param next the next node, as an index relative to the parent, i.e. parent[0] == parent.child, parent[1] == parent.child.next
/// \param args the args to construct the value to insert /// \param args the args to construct the value to insert
/// \returns the index of the created node /// \returns the index of the created node
@@ -426,7 +432,7 @@ public:
/// \brief Traverse the tree using a specified order and visiting functor /// \brief Traverse the tree using a specified order and visiting functor
/// ///
/// \details /// \details
/// The visitor should accept a reference to a value of type `TypeT` and a `size_t` which contains the node's id. /// The visitor should accept a reference to a value of type \f$TypeT\f$ and a `size_t` which contains the node's id.
/// The visitor should return one of the following values in the `fennec::traversal_control_` enum /// The visitor should return one of the following values in the `fennec::traversal_control_` enum
/// ///
/// \tparam OrderT The order with which to traverse the tree. /// \tparam OrderT The order with which to traverse the tree.
@@ -449,15 +455,25 @@ public:
} }
} }
///
/// \brief Traverser pattern for breadth-first traversal
struct breadth_first { struct breadth_first {
list<size_t> visit;
size_t head;
///
/// \brief Traversal Init
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const rdtree&, size_t start) { constexpr size_t operator()(const rdtree&, size_t start) {
head = start; head = start;
return start; return start;
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \param mode The mode specifying branch conditions
/// \returns The next index according to the traversal order
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -483,17 +499,31 @@ public:
return node; return node;
} }
private:
list<size_t> visit;
size_t head;
}; };
///
/// \brief Traverser pattern for pre-order traversal
struct pre_order { struct pre_order {
list<size_t> visit;
size_t head;
///
/// \brief Traversal Init
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const rdtree&, size_t start) { constexpr size_t operator()(const rdtree&, size_t start) {
head = start; head = start;
return start; return start;
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \param mode The mode specifying branch conditions
/// \returns The next index according to the traversal order
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t mode) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -519,17 +549,31 @@ public:
return node; return node;
} }
};
struct in_order { private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head;
};
///
/// \brief Traverser pattern for in-order traversal
struct in_order {
///
/// \brief Traversal Init
/// \param tree The tree we are operating on
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const rdtree& tree, size_t start) { constexpr size_t operator()(const rdtree& tree, size_t start) {
head = start; head = start;
return tree.left_most(start); return tree.left_most(start);
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \returns The next index according to the traversal order
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -557,17 +601,31 @@ public:
return node; return node;
} }
};
struct post_order { private:
list<size_t> visit; list<size_t> visit;
size_t head; size_t head;
};
///
/// \brief Traverser pattern for post-order traversal
struct post_order {
///
/// \brief Traversal Init
/// \param tree The tree we are operating on
/// \param start The node in the tree to start at
/// \returns The first index of the specified order
constexpr size_t operator()(const rdtree& tree, size_t start) { constexpr size_t operator()(const rdtree& tree, size_t start) {
head = start; head = start;
return tree.left_most(start); return tree.left_most(start);
} }
///
/// \brief Traverser Step
/// \param tree The tree we are operating on
/// \param node The current node
/// \returns The next index according to the traversal order
constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) { constexpr size_t operator[](const rdtree& tree, size_t node, uint8_t) {
if (node == npos) { if (node == npos) {
return npos; return npos;
@@ -593,10 +651,14 @@ public:
return node; return node;
} }
private:
list<size_t> visit;
size_t head;
}; };
protected: private:
allocation<node, alloc_t> _table; allocation<node, alloc_t> _table;
list<size_t> _freed; list<size_t> _freed;
size_t _size; size_t _size;

View File

@@ -30,15 +30,9 @@
#ifndef FENNEC_CONTAINERS_SEQUENCE_H #ifndef FENNEC_CONTAINERS_SEQUENCE_H
#define FENNEC_CONTAINERS_SEQUENCE_H #define FENNEC_CONTAINERS_SEQUENCE_H
#include <fennec/containers/bintree.h>
#include <fennec/containers/bintree.h>
#include <fennec/containers/pair.h> #include <fennec/containers/pair.h>
#include <fennec/containers/sequence.h> #include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/containers/sequence.h>
#include <fennec/lang/compare.h> #include <fennec/lang/compare.h>
#include <fennec/memory/allocator.h> #include <fennec/memory/allocator.h>
@@ -64,13 +58,13 @@ namespace fennec
/// ///
/// | Property | Value | /// | Property | Value |
/// |:----------:|:---------------:| /// |:----------:|:---------------:|
/// | stable | | /// | stable | |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogenous | ✅ | /// | homogenous | ✅ |
/// | distinct | ✅ | /// | distinct | ✅ |
/// | ordered | ✅ | /// | ordered | ✅ |
/// | space | \f$O(N)\f$ | /// | space | \f$O(N)\f$ |
/// | linear | ✅ | /// | linear | ✅ |
/// | access | \f$O(\log N)\f$ | /// | access | \f$O(\log N)\f$ |
/// | find | \f$O(\log N)\f$ | /// | find | \f$O(\log N)\f$ |
/// | insertion | \f$O(\log N)\f$ | /// | insertion | \f$O(\log N)\f$ |
@@ -83,15 +77,9 @@ template<typename TypeT, typename CompareT = less<TypeT>, class AllocT = allocat
struct sequence { struct sequence {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
protected: private:
struct _node; struct _node;
public:
using value_t = TypeT;
using node_t = pair<TypeT, bool>;
using alloc_t = allocator_traits<AllocT>::template rebind<_node>;
using compare_t = CompareT;
enum color_ : bool { enum color_ : bool {
black = false, black = false,
red = true, red = true,
@@ -102,9 +90,16 @@ public:
dir_right = true, dir_right = true,
}; };
class iterator; public:
using value_t = TypeT; //!< the value type
using node_t = pair<TypeT, bool>; //!< the node type
using alloc_t = allocator_traits<AllocT>::template rebind<_node>; //!< underlying alloc type
using compare_t = CompareT; //!< comparison type
protected: class iterator;
class const_iterator;
private:
using node = _node*; using node = _node*;
struct _node { struct _node {
@@ -246,7 +241,7 @@ public:
/// @{ /// @{
/// ///
/// \brief Value Find Function, finds the iterator position for `val`, otherwise returns `end()` /// \brief Value Find Function, finds the iterator position for \f$val\f$, otherwise returns `end()`
/// \param val The value to find /// \param val The value to find
/// \returns An iterator at the value /// \returns An iterator at the value
constexpr iterator find(const value_t& val) { constexpr iterator find(const value_t& val) {
@@ -266,7 +261,7 @@ public:
/// ///
/// \brief Value Contains Function, checks if the sequence contains a value /// \brief Value Contains Function, checks if the sequence contains a value
/// \param val The value to find /// \param val The value to find
/// \returns `true` if `val` is in the sequence, `false` otherwise /// \returns \f$true\f$ if \f$val\f$ is in the sequence, \f$false\f$ otherwise
bool contains(const value_t& val) { bool contains(const value_t& val) {
return find(val) != end(); return find(val) != end();
} }
@@ -286,7 +281,7 @@ public:
} }
/// ///
/// \returns `true` when there are no elements in the sequence, `false` otherwise. /// \returns \f$true\f$ when there are no elements in the sequence, \f$false\f$ otherwise.
constexpr bool empty() const { constexpr bool empty() const {
return _size == 0; return _size == 0;
} }
@@ -299,7 +294,7 @@ public:
/// @{ /// @{
/// ///
/// \brief Move Insertion, moves `val` into the sequence /// \brief Move Insertion, moves \f$val\f$ into the sequence
/// \param val The value to insert /// \param val The value to insert
constexpr void insert(value_t&& val) { constexpr void insert(value_t&& val) {
node i = _insert_bst(fennec::forward<value_t>(val)); node i = _insert_bst(fennec::forward<value_t>(val));
@@ -307,7 +302,7 @@ public:
} }
/// ///
/// \brief Copy Insertion, inserts a copy of `val` into the sequence /// \brief Copy Insertion, inserts a copy of \f$val\f$ into the sequence
/// \param val The value to insert /// \param val The value to insert
constexpr void insert(const value_t& val) { constexpr void insert(const value_t& val) {
node i = _insert_bst(val); node i = _insert_bst(val);
@@ -324,6 +319,9 @@ public:
_fix_insert(i); _fix_insert(i);
} }
///
/// \brief Erase the specified value from the sequence
/// \param val the value to erase
constexpr void erase(const value_t& val) { constexpr void erase(const value_t& val) {
_erase(find(val)._node); _erase(find(val)._node);
} }
@@ -336,7 +334,7 @@ public:
visit.push_back(it._node); visit.push_back(it._node);
} }
for (node n : visit) { for (node n : visit) {
_free_node(n); this->_free_node(n);
} }
_root = nullptr; _root = nullptr;
_size = 0; _size = 0;
@@ -352,21 +350,35 @@ public:
return sequence::iterator(this, _root); return sequence::iterator(this, _root);
} }
///
/// \brief C++ Iterator Specification `begin()`
/// \returns An iterator at the smallest element in the sequence
constexpr const_iterator begin() const {
return sequence::const_iterator(this, _root);
}
/// ///
/// \returns An iterator after the largest element in the sequence /// \returns An iterator after the largest element in the sequence
constexpr iterator end() { constexpr iterator end() {
return sequence::iterator(this, _root, nullptr); return sequence::iterator(this, _root, nullptr);
} }
///
/// \brief Const C++ Iterator Specification `end()`
/// \returns An iterator after the largest element in the sequence
constexpr const_iterator end() const {
return sequence::const_iterator(this, _root, nullptr);
}
///
/// \brief C++ Iterator Specification `iterator`
class iterator { class iterator {
protected: private:
sequence* _seq; sequence* _seq;
node _head; node _head;
node _node; node _node;
list<node> _visit; list<node> _visit;
public:
constexpr iterator(sequence* seq, node start) constexpr iterator(sequence* seq, node start)
: _seq(seq) : _seq(seq)
, _head(start) , _head(start)
@@ -379,49 +391,178 @@ public:
, _node(start) { , _node(start) {
} }
iterator& operator++() { public:
if (_node == nullptr) {
return *this; ///
/// \brief prefix increment operator
/// \param it the iterator to increment
/// \returns \f$it\f$ after having moved to the next element in the list
friend iterator& operator++(iterator& it) {
if (it._node == nullptr) {
return it;
} }
node parent = _seq->_parent(_node); node parent = it._seq->_parent(it._node);
node pright = _seq->right(parent); node pright = it._seq->right(parent);
node next = _seq->leftmost(_seq->right(_node)); node next = it._seq->leftmost(it._seq->right(it._node));
if (_node != pright && parent != nullptr) { if (it._node != pright && parent != nullptr) {
_visit.push_front(parent); it._visit.push_front(parent);
} }
if (next != nullptr) { if (next != nullptr) {
_visit.push_front(next); it._visit.push_front(next);
} }
if (not _visit.empty()) { if (not it._visit.empty()) {
_node = _visit.front(); it._node = it._visit.front();
_visit.pop_front(); it._visit.pop_front();
} else { } else {
_node = nullptr; it._node = nullptr;
} }
return *this; return it;
} }
iterator operator++(int) { ///
iterator prev = *this; /// \brief postfix increment operator
this->operator++(); /// \param it the iterator to increment
/// \returns \f$it\f$ before having moved to the next element in the list
friend iterator operator++(iterator& it, int) {
iterator prev = it;
++it;
return prev; return prev;
} }
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
const value_t& operator*() const { const value_t& operator*() const {
return _node->key; return _node->key;
} }
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
const value_t* operator->() const { const value_t* operator->() const {
return &_node->key; return &_node->key;
} }
///
/// \brief iterator equality operator
/// \param lhs the iterator
/// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
constexpr friend bool operator==(const iterator& lhs, const iterator& rhs) { constexpr friend bool operator==(const iterator& lhs, const iterator& rhs) {
return lhs._node == rhs._node; return lhs._seq == rhs._seq and lhs._node == rhs._node;
}
///
/// \brief iterator inequality operator
/// \param lhs the iterator
/// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
constexpr friend bool operator!=(const iterator& lhs, const iterator& rhs) {
return lhs._seq != rhs._seq or lhs._node != rhs._node;
}
friend struct sequence;
};
///
/// \brief C++ Iterator Specification `iterator`
class const_iterator {
private:
const sequence* _seq;
node _head;
node _node;
list<node> _visit;
constexpr const_iterator(const sequence* seq, node start)
: _seq(seq)
, _head(start)
, _node(seq->leftmost(start)) {
}
constexpr const_iterator(const sequence* seq, node root, node start)
: _seq(seq)
, _head(root)
, _node(start) {
}
public:
///
/// \brief prefix increment operator
/// \param it the iterator to increment
/// \returns \f$it\f$ after having moved to the next element in the list
friend const_iterator& operator++(const_iterator& it) {
if (it._node == nullptr) {
return it;
}
node parent = it._seq->_parent(it._node);
node pright = it._seq->right(parent);
node next = it._seq->leftmost(it._seq->right(it._node));
if (it._node != pright && parent != nullptr) {
it._visit.push_front(parent);
}
if (next != nullptr) {
it._visit.push_front(next);
}
if (not it._visit.empty()) {
it._node = it._visit.front();
it._visit.pop_front();
} else {
it._node = nullptr;
}
return it;
}
///
/// \brief postfix increment operator
/// \param it the iterator to increment
/// \returns \f$it\f$ before having moved to the next element in the list
friend const_iterator operator++(const_iterator& it, int) {
const_iterator prev = it;
++it;
return prev;
}
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
const value_t& operator*() const {
return _node->key;
}
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
const value_t* operator->() const {
return &_node->key;
}
///
/// \brief iterator equality operator
/// \param lhs the iterator
/// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
constexpr friend bool operator==(const const_iterator& lhs, const const_iterator& rhs) {
return lhs._seq == rhs._seq and lhs._node == rhs._node;
}
///
/// \brief iterator inequality operator
/// \param lhs the iterator
/// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
constexpr friend bool operator!=(const const_iterator& lhs, const const_iterator& rhs) {
return lhs._seq != rhs._seq or lhs._node != rhs._node;
} }
friend struct sequence; friend struct sequence;
@@ -429,14 +570,14 @@ public:
// Fields ============================================================================================================== // Fields ==============================================================================================================
protected: private:
alloc_t _alloc; alloc_t _alloc;
node _root; node _root;
compare_t _compare; compare_t _compare;
size_t _size; size_t _size;
// Helpers ============================================================================================================= // Helpers =============================================================================================================
protected: private:
template<typename...ArgsT> template<typename...ArgsT>
constexpr node _make_node(ArgsT&&...args) { constexpr node _make_node(ArgsT&&...args) {

View File

@@ -69,14 +69,13 @@ struct set {
// Definitions ========================================================================================================= // Definitions =========================================================================================================
public: public:
using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>; using alloc_t = typename allocator_traits<Alloc>::template rebind<TypeT>; //!< the allocator type
using hash_t = Hash; using hash_t = Hash; //!< the hash type
using equal_t = Equals; using equal_t = Equals; //!< the equality type
using elem_t = TypeT; using elem_t = TypeT; //!< the element type
static constexpr double default_load = 0.8; //!< the default load factor for reallocation
class iterator; class iterator;
static constexpr size_t npos = -1;
static constexpr double default_load = 0.8;
private: private:
struct node { struct node {
@@ -87,6 +86,8 @@ private:
constexpr ~node() = default; constexpr ~node() = default;
}; };
static constexpr size_t npos = -1;
// Constructors ======================================================================================================== // Constructors ========================================================================================================
public: public:
@@ -182,7 +183,7 @@ public:
} }
/// ///
/// \returns `true` when the set is empty, `false` otherwise /// \returns \f$true\f$ when the set is empty, \f$false\f$ otherwise
constexpr bool empty() const { constexpr bool empty() const {
return _size == 0; return _size == 0;
} }
@@ -252,7 +253,7 @@ public:
/// ///
/// \brief Check if a set contains a value /// \brief Check if a set contains a value
/// \param val Value to check /// \param val Value to check
/// \returns `true` if `val` can be found, `false` otherwise /// \returns \f$true\f$ if \f$val\f$ can be found, \f$false\f$ otherwise
constexpr bool contains(const elem_t& val) const { constexpr bool contains(const elem_t& val) const {
return this->find(val) != end(); return this->find(val) != end();
} }
@@ -260,7 +261,7 @@ public:
/// ///
/// \brief Iterator Access /// \brief Iterator Access
/// \param it Location to access /// \param it Location to access
/// \returns A pointer to the element, `nullptr` if not found. /// \returns A pointer to the element, \f$nullptr\f$ if not found.
/// The value should not be changed in a manner that will change the hash of the element. /// The value should not be changed in a manner that will change the hash of the element.
constexpr elem_t* at(const iterator& it) { constexpr elem_t* at(const iterator& it) {
if (it == end()) { if (it == end()) {
@@ -275,7 +276,7 @@ public:
/// ///
/// \brief Iterator Const Access /// \brief Iterator Const Access
/// \param it Location to access /// \param it Location to access
/// \returns A const-qualified pointer to the element, `nullptr` if not found. /// \returns A const-qualified pointer to the element, \f$nullptr\f$ if not found.
constexpr const elem_t* at(const iterator& it) const { constexpr const elem_t* at(const iterator& it) const {
if (not _alloc[it._i].value) return nullptr; if (not _alloc[it._i].value) return nullptr;
return &*_alloc[it._i].value; return &*_alloc[it._i].value;
@@ -347,11 +348,9 @@ public:
} }
/// ///
/// \brief /// \brief Clear all elements from the set, destructing them
constexpr void clear() { constexpr void clear() {
for (size_t i = 0; i < _alloc.capacity(); ++i) { _alloc.clear();
}
} }
/// @} /// @}
@@ -381,57 +380,79 @@ public:
/// @} /// @}
/// ///
/// \brief Class for Iterating the Set /// \brief C++ Iterator Specification `iterator`
class iterator { class iterator {
public: public:
constexpr iterator(const set* set, size_t i) ///
: _set(set) /// \brief destructor
, _i(i) {
}
constexpr ~iterator() { constexpr ~iterator() {
_set = nullptr; _set = nullptr;
} }
// prefix operator ///
constexpr friend iterator& operator++(iterator& rhs) { /// \brief prefix increment operator
while (++rhs._i < rhs._set->capacity()) { /// \param it the iterator to increment
if (rhs._set->_alloc[rhs._i].value) { /// \returns \f$it\f$ after having moved to the next element in the list
return rhs; constexpr friend iterator& operator++(iterator& it) {
while (++it._i < it._set->capacity()) {
if (it._set->_alloc[it._i].value) {
return it;
} }
} }
rhs._i = npos; it._i = npos;
return rhs; return it;
} }
constexpr friend iterator operator++(iterator& lhs, int) { ///
iterator prev = lhs; /// \brief postfix increment operator
++lhs; /// \param it the iterator to increment
/// \returns \f$it\f$ before having moved to the next element in the list
constexpr friend iterator operator++(iterator& it, int) {
iterator prev = it;
++it;
return prev; return prev;
} }
///
/// \brief dereference operator
/// \returns a reference to the value pointed by the iterator
constexpr const elem_t& operator*() const { constexpr const elem_t& operator*() const {
return *_set->_alloc[_i].value; return *_set->_alloc[_i].value;
} }
///
/// \brief pointer access operator
/// \returns a pointer to the value pointed by the iterator
constexpr const elem_t* operator->() const { constexpr const elem_t* operator->() const {
if (not _set->_alloc[_i].value) return nullptr; if (not _set->_alloc[_i].value) return nullptr;
return &*_set->_alloc[_i].value; return &*_set->_alloc[_i].value;
} }
///
/// \brief iterator equality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
constexpr bool operator==(const iterator& it) const { constexpr bool operator==(const iterator& it) const {
return _set == it._set and _i == it._i; return _set == it._set and _i == it._i;
} }
///
/// \brief iterator inequality operator
/// \param it the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
constexpr bool operator!=(const iterator& it) const { constexpr bool operator!=(const iterator& it) const {
return _set != it._set or _i != it._i; return _set != it._set or _i != it._i;
} }
constexpr size_t index() const { return _i; }
private: private:
const set* _set; const set* _set;
size_t _i; size_t _i;
constexpr iterator(const set* set, size_t i)
: _set(set)
, _i(i) {
}
friend set; friend set;
}; };

View File

@@ -42,24 +42,29 @@ namespace fennec
/// ///
/// \brief Tuple, holds a collection of values of different types /// \brief Tuple, holds a collection of values of different types
/// \details /// \details
/// | Property | Value | /// | Property | Value |
/// |:----------:|:----------:| /// |:----------:|:-----------:|
/// | stable | ⛔ | /// | stable | ⛔ |
/// | dynamic | ✅ | /// | dynamic | ✅ |
/// | homogenous | ⛔ | /// | homogenous | ⛔ |
/// | distinct | ⛔ | /// | distinct | ⛔ |
/// | ordered | ⛔ | /// | ordered | ⛔ |
/// | space | \f$O(N)\f$ | /// | space | \f$O(N)\f$ |
/// | linear | ✅ | /// | linear | ✅ |
/// | access | \f$O(1)\f$ | /// | access | \f$O(1)\f$ |
/// | find | \f$O(1)\f$ | /// | find | \f$O(1)\f$ |
/// | insertion | ⛔ | /// | insertion | ⛔ |
/// | deletion | ⛔ | /// | deletion | ⛔ |
/// ///
/// \tparam TypesT The types to store /// \tparam TypesT The types to store
template<typename...TypesT> struct tuple; template<typename...TypesT> struct tuple;
///
/// \brief tuple get
/// \tparam i the index
/// \tparam TypesT the types held in the tuple
/// \param x the tuple
/// \returns the \f$i\f$th element of the tuple
template<size_t i, typename...TypesT> template<size_t i, typename...TypesT>
constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) { constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x) {
using elem_t = typename tuple<TypesT...>::template elem_t<i>; using elem_t = typename tuple<TypesT...>::template elem_t<i>;
@@ -67,6 +72,11 @@ constexpr typename tuple<TypesT...>::template elem_t<i>& get(tuple<TypesT...>& x
return it.value; return it.value;
} }
///
/// \tparam i the index
/// \tparam TypesT the types held in the tuple
/// \param x the tuple
/// \returns the \f$i\f$th element of the tuple
template<size_t i, typename...TypesT> template<size_t i, typename...TypesT>
constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) { constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<TypesT...>& x) {
using elem_t = typename tuple<TypesT...>::template elem_t<i>; using elem_t = typename tuple<TypesT...>::template elem_t<i>;
@@ -78,28 +88,41 @@ constexpr const typename tuple<TypesT...>::template elem_t<i>& get(const tuple<T
template<typename ...TypesT> template<typename ...TypesT>
struct tuple : public detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...> struct tuple : public detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>
{ {
using base_t = detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>; using base_t = detail::_tuple<make_index_metasequence_t<sizeof...(TypesT)>, TypesT...>; //!< the base type
template<size_t i> template<size_t i>
using elem_t = typename nth_element<i, TypesT...>::type; using elem_t = typename nth_element<i, TypesT...>::type; //!< helper for getting the \f$i\f$th element
static constexpr size_t size = sizeof...(TypesT); static constexpr size_t size = sizeof...(TypesT); //!< the number of elements held by the tuple
///
/// \brief tuple constructor
/// \tparam ArgsT The element types
/// \param args The arguments to initialize the tuple with
template<typename...ArgsT> template<typename...ArgsT>
tuple(ArgsT&&...args) tuple(ArgsT&&...args)
: base_t(fennec::forward<ArgsT>(args)...) { : base_t(fennec::forward<ArgsT>(args)...) {
} }
///
/// \brief copy constructor
/// \param cpy the tuple to copy
tuple(const tuple& cpy) tuple(const tuple& cpy)
: base_t(cpy) { : base_t(cpy) {
} }
tuple(tuple&& cpy) ///
: base_t(cpy) { /// \brief move constructor
/// \param mov the tuple to move
tuple(tuple&& mov)
: base_t(mov) {
} }
}; };
// This is needed for ///
/// \brief Helper for deducing the tuple constructor
/// \tparam TypesT the types of the tuple
/// \returns A new tuple containing the passed values
template<typename...TypesT> template<typename...TypesT>
tuple(TypesT...) -> tuple<TypesT...>; tuple(TypesT...) -> tuple<TypesT...>;

View File

@@ -56,8 +56,8 @@ struct variant {
// Typedefs & Constants ================================================================================================ // Typedefs & Constants ================================================================================================
static constexpr size_t size = max_element_size_v<TypesT...>; static constexpr size_t size = max_element_size_v<TypesT...>; //!< size of the variant in bytes
static constexpr size_t nulltype = sizeof...(TypesT); static constexpr size_t nulltype = sizeof...(TypesT); //!< id for a null type
@@ -74,8 +74,8 @@ struct variant {
} }
/// ///
/// \brief Conversion Constructor, constructs the type in `TypesT...` that is identical to `T` /// \brief Conversion Constructor, constructs the type in `TypesT...` that is identical to \f$T\f$
/// or the first that is constructible with `T` /// or the first that is constructible with \f$T\f$
/// \tparam T The type of the value /// \tparam T The type of the value
/// \param t The value to forward /// \param t The value to forward
template<typename T> template<typename T>
@@ -146,10 +146,15 @@ struct variant {
// Assignment ========================================================================================================== // Assignment ==========================================================================================================
///
/// \brief value assignment operator
/// \tparam T The type to assign
/// \param t the value to assign
/// \returns a reference to \f$self\f$ after assigning \f$t\f$
template<typename T> template<typename T>
variant& operator=(T&& t) { variant& operator=(T&& t) {
// First, check if `T` is in `TypesT...` // First, check if \f$T\f$ is in `TypesT...`
if constexpr((contains_element_v<T, TypesT> or ...)) { if constexpr((contains_element_v<T, TypesT> or ...)) {
using type_t = remove_reference_t<T>; using type_t = remove_reference_t<T>;
if (_type == find_element_v<type_t, TypesT...>) { if (_type == find_element_v<type_t, TypesT...>) {
@@ -182,12 +187,21 @@ struct variant {
return *this; return *this;
} }
///
/// \brief emplace function
/// \tparam T The type to construct
/// \tparam ArgsT the argument types
/// \param args the argument values
template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>) template<typename T, typename...ArgsT> requires(contains_element_v<T, TypesT...>)
void emplace(ArgsT&&...args) { void emplace(ArgsT&&...args) {
_clear(); _clear();
fennec::construct<T>(_handle, fennec::forward<ArgsT>(args)...); fennec::construct<T>(_handle, fennec::forward<ArgsT>(args)...);
} }
///
/// \brief deduced emplace function
/// \tparam ArgsT the argument types
/// \param args the argument values
template<size_t I, typename...ArgsT> template<size_t I, typename...ArgsT>
void emplace(ArgsT&&...args) { void emplace(ArgsT&&...args) {
using type_t = nth_element_t<I, TypesT...>; using type_t = nth_element_t<I, TypesT...>;
@@ -198,21 +212,34 @@ struct variant {
// Access ============================================================================================================== // Access ==============================================================================================================
///
/// \brief get the value of the variant interpreted as \f$T\f$
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
template<typename T> requires(contains_element_v<T, TypesT...>) template<typename T> requires(contains_element_v<T, TypesT...>)
T& get() { T& get() {
return *static_cast<T*>(_handle); return *static_cast<T*>(_handle);
} }
///
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
template<typename T> requires(contains_element_v<T, TypesT...>) template<typename T> requires(contains_element_v<T, TypesT...>)
const T& get() const { const T& get() const {
return *static_cast<T*>(_handle); return *static_cast<T*>(_handle);
} }
///
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>) template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
T& get() { T& get() {
return *static_cast<T*>(_handle); return *static_cast<T*>(_handle);
} }
///
/// \tparam T the type to interpret as
/// \returns The value interpreted as \f$T\f$
template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>) template<size_t I, typename T = nth_element_t<I, TypesT...>> requires(contains_element_v<T, TypesT...>)
const T& get() const { const T& get() const {
return *static_cast<T*>(_handle); return *static_cast<T*>(_handle);

View File

@@ -34,6 +34,10 @@ struct event;
class event_listener { class event_listener {
public: public:
virtual ~event_listener() = default; virtual ~event_listener() = default;
///
/// \brief event handler callback
/// \param event the event to handle
virtual void handle_event(event* event) = 0; virtual void handle_event(event* event) = 0;
}; };
@@ -44,25 +48,42 @@ struct event {
/// ///
/// \brief Registers a listener for the event type /// \brief Registers a listener for the event type
/// \tparam EventT /// \tparam EventT the event type
/// \param listener /// \param listener the listener to register
template<typename EventT> template<typename EventT>
static void add_listener(event_listener* listener) { static void add_listener(event_listener* listener) {
event::add_listener(listener, typeuuid<EventT, event>()); event::add_listener(listener, typeuuid<EventT, event>());
} }
///
/// \brief Add a listener for an event type of \f$type\f$
/// \param listener the listener to add
/// \param type the event type to listen for
static void add_listener(event_listener* listener, uint64_t type);
///
/// \brief removes a listener from the event system
/// \param listener the listener to remove
static void remove_listener(event_listener* listener);
///
/// \brief Dispatch an event
/// \tparam EventT The event type
/// \param event the event to dispatch
template<typename EventT> template<typename EventT>
static void dispatch(EventT* event) { static void dispatch(EventT* event) {
dispatch(event); event::dispatch(event);
} }
static void add_listener(event_listener* listener, uint64_t type); ///
static void remove_listener(event_listener* listener); /// \brief Dispatch an event
/// \param event the event to dispatch
static void dispatch(event* event); static void dispatch(event* event);
#ifndef FENNEC_DOXYGEN
FENNEC_RTTI_CLASS_ENABLE() { FENNEC_RTTI_CLASS_ENABLE() {
} }
#endif
}; };
} }

View File

@@ -39,14 +39,23 @@
namespace fennec namespace fennec
{ {
///
/// \brief logger class
class logger : public singleton<logger> { class logger : public singleton<logger> {
public: public:
///
/// \brief default constructor
logger(); logger();
~logger(); ~logger();
///
/// \brief Log a string to the log file and cout
/// \param str the string to log
/// \param _line the line of the log call
/// \param _file the file log was called in
static void log(const cstring& str, static void log(const cstring& str,
uint32_t _line = FENNEC_BUILTIN_LINE(), uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* _file = FENNEC_BUILTIN_FILE() const char* _file = FENNEC_BUILTIN_FILE()
) { ) {
logger& inst = instance(); logger& inst = instance();
@@ -61,6 +70,11 @@ public:
inst._cout->println(str); inst._cout->println(str);
} }
///
/// \brief Log a string to the log file and cout
/// \param str the string to log
/// \param _line the line of the log call
/// \param _file the file log was called in
static void log(const string& str, static void log(const string& str,
uint32_t _line = FENNEC_BUILTIN_LINE(), uint32_t _line = FENNEC_BUILTIN_LINE(),
const char* _file = FENNEC_BUILTIN_FILE() const char* _file = FENNEC_BUILTIN_FILE()

View File

@@ -38,9 +38,13 @@
namespace fennec namespace fennec
{ {
///
/// \brief simple version struct for drivers and systems
struct version { struct version {
uint32_t major, minor, patch; uint32_t major; //!< the major version
string str; uint32_t minor; //!< the minor version
uint32_t patch; //!< the patch
string str; //!< string representation of the version
}; };
} }

View File

@@ -39,10 +39,10 @@ namespace fennec
/// <tr><th style="vertical-align: top">Flags /// <tr><th style="vertical-align: top">Flags
/// <th style="vertical-align: top">Description /// <th style="vertical-align: top">Description
/// ///
/// <tr><td style="vertical-align: top">`read` /// <tr><td style="vertical-align: top">\f$read\f$
/// <td style="vertical-align: top">Opens file as read-only, reading from start /// <td style="vertical-align: top">Opens file as read-only, reading from start
/// ///
/// <tr><td style="vertical-align: top">`write` /// <tr><td style="vertical-align: top">\f$write\f$
/// <td style="vertical-align: top">Opens file as write-only, writing to end /// <td style="vertical-align: top">Opens file as write-only, writing to end
/// ///
/// <tr><td style="vertical-align: top">`read | write` /// <tr><td style="vertical-align: top">`read | write`
@@ -109,16 +109,28 @@ public:
/// \brief default constructor, initializes an empty stream /// \brief default constructor, initializes an empty stream
file(); file();
///
/// \brief path constructor, initializes a stream pointing to \f$mode\f$ opened with \f$mode\f$
/// \param path the path of the file
/// \param mode the mode to open with
file(const cstring& path, uint8_t mode) file(const cstring& path, uint8_t mode)
: file() { : file() {
open(path, mode); open(path, mode);
} }
///
/// \brief path constructor, initializes a stream pointing to \f$mode\f$ opened with \f$mode\f$
/// \param path the path of the file
/// \param mode the mode to open with
file(const string& path, uint8_t mode) file(const string& path, uint8_t mode)
: file() { : file() {
open(path, mode); open(path, mode);
} }
///
/// \brief path constructor, initializes a stream pointing to \f$mode\f$ opened with \f$mode\f$
/// \param path the path of the file
/// \param mode the mode to open with
file(const path& path, uint8_t mode) file(const path& path, uint8_t mode)
: file() { : file() {
open(path, mode); open(path, mode);
@@ -133,6 +145,9 @@ public:
/// \param file the stream to take ownership of /// \param file the stream to take ownership of
file(file&& file) noexcept; file(file&& file) noexcept;
///
/// \brief move assignment
/// \param file the stream to take ownership of
file& operator=(file&& file) noexcept; file& operator=(file&& file) noexcept;
// don't allow copying streams // don't allow copying streams
@@ -258,21 +273,52 @@ public:
// File Positioning ==================================================================================================== // File Positioning ====================================================================================================
///
/// \returns the position index in the stream
size_t get_pos() const; size_t get_pos() const;
///
/// \param i the new index to move to
/// \returns \f$false\f$ on success, \f$true\f$ otherwise
bool set_pos(size_t i); bool set_pos(size_t i);
///
/// \brief return to the start of the stream
/// \returns \f$false\f$ on success, \f$true\f$ otherwise
bool rewind(); bool rewind();
///
/// \returns \f$true\f$ if the stream has reached the end of the file, \f$false\f$ otherwise
bool eof() const; bool eof() const;
// Binary Read Operations ============================================================================================== // Binary Read Operations ==============================================================================================
///
/// \brief binary read
/// \param data the buffer to write to
/// \param size the size of each object in bytes
/// \param n the number of objects to read
/// \returns the number of objects successfully read
size_t read(void* data, size_t size, size_t n); size_t read(void* data, size_t size, size_t n);
///
/// \brief type read
/// \tparam T the type to read
/// \param data the buffer to write to
/// \param n the number of objects to read
/// \returns the number of objects successfully read
template<typename T> template<typename T>
size_t read(T* data, size_t n) { size_t read(T* data, size_t n) {
return read(static_cast<void*>(data), sizeof(T), n); return read(static_cast<void*>(data), sizeof(T), n);
} }
///
/// \brief type read
/// \tparam T the type to read
/// \tparam n the number of objects to read
/// \param data the buffer to write to
/// \returns the number of objects successfully read
template<typename T, size_t n> template<typename T, size_t n>
size_t read(T (&data)[n]) { size_t read(T (&data)[n]) {
return read(static_cast<void*>(data), sizeof(T), n); return read(static_cast<void*>(data), sizeof(T), n);
@@ -281,26 +327,63 @@ public:
// Binary Write Operations ============================================================================================= // Binary Write Operations =============================================================================================
///
/// \brief put a character at the current position in the stream
/// \param c the character to put
/// \returns \f$false\f$ on success, \f$true\f$ otherwise
bool putc(char c); bool putc(char c);
///
/// \brief put a wide character at the current position in the stream
/// \param c the character to put
/// \returns \f$false\f$ on success, \f$true\f$ otherwise
bool putwc(wchar_t c); bool putwc(wchar_t c);
///
/// \brief write a buffer to at the current position in the stream
/// \param data the buffer to read from
/// \param size the size of each object in bytes
/// \param n the number of objects to write
/// \returns the number of objects successfully written
size_t write(const void* data, size_t size, size_t n); size_t write(const void* data, size_t size, size_t n);
///
/// \brief write a character buffer to at the current position in the stream
/// \tparam n the number of characters to write
/// \param data the buffer to read from
/// \returns the number of objects successfully written
template<size_t n> template<size_t n>
size_t write(const char (&data)[n]) { size_t write(const char (&data)[n]) {
return write(data, sizeof(char), n - 1); return write(data, sizeof(char), n - 1);
} }
///
/// \brief write a wide character buffer to at the current position in the stream
/// \tparam n the number of characters to write
/// \param data the buffer to read from
/// \returns the number of objects successfully written
template<size_t n> template<size_t n>
size_t write(const wchar_t (&data)[n]) { size_t write(const wchar_t (&data)[n]) {
return write(data, sizeof(wchar_t), n - 1); return write(data, sizeof(wchar_t), n - 1);
} }
///
/// \brief write a buffer to at the current position in the stream
/// \tparam T the object type to write
/// \param data the buffer to read from
/// \param n the number of objects to write
/// \returns the number of objects successfully written
template<typename T> template<typename T>
size_t write(const T* data, size_t n) { size_t write(const T* data, size_t n) {
return write(static_cast<const void*>(data), sizeof(T), n); return write(static_cast<const void*>(data), sizeof(T), n);
} }
///
/// \brief write a buffer to at the current position in the stream
/// \tparam T the object type to write
/// \tparam n the number of objects to write
/// \param data the buffer to read from
/// \returns the number of objects successfully written
template<typename T, size_t n> template<typename T, size_t n>
size_t write(const T (&data)[n]) { size_t write(const T (&data)[n]) {
return write(static_cast<const void*>(data), sizeof(T), n); return write(static_cast<const void*>(data), sizeof(T), n);
@@ -309,21 +392,48 @@ public:
// Read Operations ===================================================================================================== // Read Operations =====================================================================================================
///
/// \returns the character read at the current position in the stream
char getc(); char getc();
///
/// \returns the wide character read at the current position in the stream
wchar_t getwc(); wchar_t getwc();
///
/// \returns a string containing all characters from the current position in the stream to the next newline character
string getline(); string getline();
///
/// \returns a string containing all characters from the current position in the stream to the next newline character
wstring getwline(); wstring getwline();
// Printing Operations ================================================================================================= // Printing Operations =================================================================================================
///
/// \param str the string to print
void print(const cstring& str); void print(const cstring& str);
///
/// \brief print a string to the stream
/// \param str the string to print
void print(const string& str); void print(const string& str);
///
/// \param str the string to print
void println(const cstring& str); void println(const cstring& str);
///
/// \brief print a string to the stream followed by a newline character
/// \param str the string to print
void println(const string& str); void println(const string& str);
///
/// \brief print a formatted string to the stream
/// \tparam ArgsT the argument types
/// \param str the format string
/// \param args the argument values
template<typename...ArgsT> template<typename...ArgsT>
void printf(const cstring& str, ArgsT&&...args) { void printf(const cstring& str, ArgsT&&...args) {
string fmt = fennec::format(str, fennec::forward<ArgsT>(args)...); string fmt = fennec::format(str, fennec::forward<ArgsT>(args)...);
@@ -335,7 +445,12 @@ public:
// Error Handling ====================================================================================================== // Error Handling ======================================================================================================
///
/// \returns the current error state of the file
const char* get_error() const { return _error; } const char* get_error() const { return _error; }
///
/// \brief clears the errored state
void clear_error() { _error = nullptr; } void clear_error() { _error = nullptr; }
private: private:

View File

@@ -36,7 +36,7 @@ public:
// Definitions ========================================================================================================= // Definitions =========================================================================================================
class iterator; class iterator;
friend iterator; friend class iterator;
// Static Functions ==================================================================================================== // Static Functions ====================================================================================================
@@ -95,7 +95,7 @@ public:
/// ///
/// \brief C-String Assignment Operator /// \brief C-String Assignment Operator
/// \param str the cstring to assign /// \param str the cstring to assign
/// \returns a reference to `this` after assigning `p` /// \returns a reference to \f$this\f$ after assigning \f$p\f$
template<size_t n> template<size_t n>
path& operator=(const char (&str)[n]) { path& operator=(const char (&str)[n]) {
_str = str; _str = str;
@@ -105,7 +105,7 @@ public:
/// ///
/// \brief C-String Assignment Operator /// \brief C-String Assignment Operator
/// \param p the cstring to assign /// \param p the cstring to assign
/// \returns a reference to `this` after assigning `p` /// \returns a reference to \f$this\f$ after assigning \f$p\f$
path& operator=(const cstring& p) { path& operator=(const cstring& p) {
_str = p; _str = p;
return *this; return *this;
@@ -114,7 +114,7 @@ public:
/// ///
/// \brief String Assignment Operator /// \brief String Assignment Operator
/// \param p the cstring to assign /// \param p the cstring to assign
/// \returns a reference to `this` after assigning `p` /// \returns a reference to \f$this\f$ after assigning \f$p\f$
path& operator=(const string& p) { path& operator=(const string& p) {
_str = p; _str = p;
return *this; return *this;
@@ -123,7 +123,7 @@ public:
/// ///
/// \brief Path Copy Assignment Operator /// \brief Path Copy Assignment Operator
/// \param p the path to copy /// \param p the path to copy
/// \returns a reference to `this` after copying `p` /// \returns a reference to \f$this\f$ after copying \f$p\f$
path& operator=(const path& p) { path& operator=(const path& p) {
_str = p._str; _str = p._str;
return *this; return *this;
@@ -132,7 +132,7 @@ public:
/// ///
/// \brief Path Move Assignment Operator /// \brief Path Move Assignment Operator
/// \param p the path to take ownership of /// \param p the path to take ownership of
/// \returns a reference to `this` after taking ownership of `p` /// \returns a reference to \f$this\f$ after taking ownership of \f$p\f$
path& operator=(path&& p) noexcept { path& operator=(path&& p) noexcept {
_str = move(p._str); _str = move(p._str);
return *this; return *this;
@@ -142,33 +142,55 @@ public:
// Append Operators ==================================================================================================== // Append Operators ====================================================================================================
/// ///
/// \brief /// \brief path append operator
/// \param str /// \param str the filename to append
/// \return /// \returns a path containing the current path followed by \f$str\f$
path operator/(const cstring& str) const { path operator/(const cstring& str) const {
return path(_str + '/' + str); return path(_str + '/' + str);
} }
///
/// \brief path append operator
/// \param str the filename to append
/// \returns a path containing the current path followed by \f$str\f$
path operator/(const string& str) const { path operator/(const string& str) const {
return path(_str + '/' + str); return path(_str + '/' + str);
} }
///
/// \brief path append operator
/// \param p the path to append
/// \returns a path containing the current path followed by \f$p\f$
path operator/(const path& p) const { path operator/(const path& p) const {
return path(_str + '/' + p._str); return path(_str + '/' + p._str);
} }
///
/// \brief path equality operator
/// \param p the path to compare against
/// \returns \f$true\f$ if the paths are identical, \f$false\f$ otherwise. relative paths are not resolved
bool operator==(const path& p) const { bool operator==(const path& p) const {
return _str == p._str; return _str == p._str;
} }
///
/// \brief the filename of the current path
/// \returns a string containing a copy of the filename
string filename() const { string filename() const {
size_t i = _str.rfind('/'); size_t i = _str.rfind('/');
return _str.substring(i + 1); return _str.substring(i + 1);
} }
///
/// \returns the underlying string representation
const string& str() const { return _str; } const string& str() const { return _str; }
///
/// \returns the underlying C-Style string representation
const char* cstr() const { return _str.cstr(); } const char* cstr() const { return _str.cstr(); }
///
/// \returns \f$true\f$ if the path is empty or points to root
bool empty() { bool empty() {
size_t size = _str.size(); size_t size = _str.size();
if (size == 0) return true; if (size == 0) return true;
@@ -179,6 +201,8 @@ public:
#endif #endif
} }
///
/// \returns a copy of the path with the filename removed
path parent() const { path parent() const {
#ifdef FENNEC_PLATFORM_WINDOWS #ifdef FENNEC_PLATFORM_WINDOWS
size_t start = _str.size() - 1; size_t start = _str.size() - 1;
@@ -203,6 +227,9 @@ public:
#endif #endif
} }
///
/// \brief absolute path
/// \returns a copy of the path with relative paths resolved
path absolute() const { path absolute() const {
path parse = *this; path parse = *this;
path working; working._str.resize(0); path working; working._str.resize(0);
@@ -253,16 +280,83 @@ public:
// Iterator ============================================================================================================ // Iterator ============================================================================================================
///
/// \brief C++ Iterator Specification `begin()`
/// \returns an iterator at the first filename in the path
iterator begin() const { iterator begin() const {
return iterator(this, 0); return iterator(this, 0);
} }
///
/// \brief C++ Iterator Specification `end()`
/// \returns an iterator to the end of the path
iterator end() const { iterator end() const {
return iterator(this, _str.size()); return iterator(this, _str.size());
} }
///
/// \brief C++ Iterator Specification `iterator`
class iterator { class iterator {
public: public:
///
/// \brief copy constructor
/// \param it the iterator to copy
constexpr iterator(const iterator& it) = default;
///
/// \brief move constructor
/// \param it the iterator to move
constexpr iterator(iterator&& it) noexcept = default;
///
/// \brief dereference operator
/// \returns copy of the current file in the path
constexpr string operator*() const {
if ((*_str)[_pos] == '/') {
return string("");
}
size_t e = _str->find('/', _pos);
return _str->substring(_pos, e - _pos);
}
///
/// \brief prefix increment operator
/// \returns \f$self\f$ after having moved to the next element in the list
constexpr iterator& operator++() {
_pos = min(_str->find('/', _pos) + 1, _str->size());
return *this;
}
///
/// \brief postfix increment operator
/// \returns \f$self\f$ before having moved to the next element in the list
constexpr iterator operator++(int) {
iterator it = *this;
this->operator++();
return it;
}
///
/// \brief iterator equality operator
/// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are identical, \f$false\f$ otherwise
constexpr bool operator==(const iterator& rhs) const {
return _str == rhs._str and _pos == rhs._pos;
}
///
/// \brief iterator inequality operator
/// \param rhs the iterator to compare with
/// \returns \f$true\f$ if the iterators are different, \f$false\f$ otherwise
constexpr bool operator!=(const iterator& rhs) const {
return _str != rhs._str or _pos != rhs._pos;
}
private:
const string* _str;
size_t _pos;
constexpr iterator(const path* path, size_t p) constexpr iterator(const path* path, size_t p)
: _str(&path->_str) : _str(&path->_str)
, _pos(p) { , _pos(p) {
@@ -289,40 +383,7 @@ public:
} }
} }
constexpr iterator(const iterator&) = default; friend struct path;
constexpr iterator(iterator&&) noexcept = default;
constexpr string operator*() const {
if ((*_str)[_pos] == '/') {
return string("");
}
size_t e = _str->find('/', _pos);
return _str->substring(_pos, e - _pos);
}
constexpr iterator& operator++() {
_pos = min(_str->find('/', _pos) + 1, _str->size());
return *this;
}
constexpr iterator operator++(int) {
iterator it = *this;
this->operator++();
return it;
}
constexpr bool operator==(const iterator& rhs) const {
return _str == rhs._str and _pos == rhs._pos;
}
constexpr bool operator!=(const iterator& rhs) const {
return _str != rhs._str or _pos != rhs._pos;
}
private:
const string* _str;
size_t _pos;
}; };
private: private:

View File

@@ -34,31 +34,165 @@
namespace fennec namespace fennec
{ {
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, char x, int base); char* to_chars(char* first, char* last, char x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, signed char x, int base); char* to_chars(char* first, char* last, signed char x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, unsigned char x, int base); char* to_chars(char* first, char* last, unsigned char x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, signed short x, int base); char* to_chars(char* first, char* last, signed short x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, unsigned short x, int base); char* to_chars(char* first, char* last, unsigned short x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, signed int x, int base); char* to_chars(char* first, char* last, signed int x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, unsigned int x, int base); char* to_chars(char* first, char* last, unsigned int x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, signed long x, int base); char* to_chars(char* first, char* last, signed long x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, unsigned long x, int base); char* to_chars(char* first, char* last, unsigned long x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, signed long long x, int base); char* to_chars(char* first, char* last, signed long long x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, unsigned long long x, int base); char* to_chars(char* first, char* last, unsigned long long x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, signed long long x, int base); char* to_chars(char* first, char* last, signed long long x, int base);
///
/// \brief integer to ascii
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param base the base to interpret the integer as
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, unsigned long long x, int base); char* to_chars(char* first, char* last, unsigned long long x, int base);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, float x); char* to_chars(char* first, char* last, float x);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param fmt the float string format to use
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, float x, char fmt); char* to_chars(char* first, char* last, float x, char fmt);
///
/// \brief float to ascii
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param fmt the float string format to use
/// \param precision the number of decimal places to write
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, float x, char fmt, int precision); char* to_chars(char* first, char* last, float x, char fmt, int precision);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, double x); char* to_chars(char* first, char* last, double x);
///
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param fmt the float string format to use
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, double x, char fmt); char* to_chars(char* first, char* last, double x, char fmt);
///
/// \brief float to ascii
/// \param first the start of the buffer
/// \param last the end of the buffer
/// \param x the value to write
/// \param fmt the float string format to use
/// \param precision the number of decimal places to write
/// \returns a pointer to one past the last written character
char* to_chars(char* first, char* last, double x, char fmt, int precision); char* to_chars(char* first, char* last, double x, char fmt, int precision);

View File

@@ -38,7 +38,12 @@
namespace fennec namespace fennec
{ {
///
/// \brief C++ 20 format specification
/// \tparam ArgsT The argument types
/// \param str The format string
/// \param args The argument values
/// \returns A formatted string using the C++20 format specification
template<typename...ArgsT> template<typename...ArgsT>
string format(const cstring& str, ArgsT&&...args) { string format(const cstring& str, ArgsT&&...args) {
static constexpr size_t argc = sizeof...(ArgsT); static constexpr size_t argc = sizeof...(ArgsT);

View File

@@ -35,14 +35,18 @@
namespace fennec namespace fennec
{ {
///
/// \brief helper struct for `fennec::format`
struct format_arg { struct format_arg {
char fill; char fill; //!< the fill character of the argument
char align, sign; char align; //!< the alignment of the argument
bool alt, upper; char sign; //!< the sign to use
size_t width, precision; bool alt; //!< alternate form
size_t base; bool upper; //!< print as uppercase
char type; size_t width; //!< the width of the fill
size_t precision; //!< the number of decimal points
size_t base; //!< the base to use
char type; //!< the argument type
}; };
} }

View File

@@ -45,6 +45,11 @@ namespace fennec
/// \tparam T The type to format /// \tparam T The type to format
template<typename T> template<typename T>
struct formatter { struct formatter {
///
/// \brief default format function
///
/// \details throws a static assertion
/// \returns empty string
string operator()(const format_arg&, const T&) { string operator()(const format_arg&, const T&) {
static_assert(false, "Formatter not implemented for the provided type."); static_assert(false, "Formatter not implemented for the provided type.");
return string(""); return string("");
@@ -54,29 +59,55 @@ struct formatter {
// strings ============================================================================================================= // strings =============================================================================================================
///
/// \brief formatter of a character array
/// \tparam N the number of characters
template<size_t N> template<size_t N>
struct formatter<char[N]> { struct formatter<char[N]> {
///
/// \brief format function
/// \param str the string argument
/// \returns the formatted version of \f$str\f$
string operator()(const format_arg&, const char (&str)[N]) { string operator()(const format_arg&, const char (&str)[N]) {
return string(str); return string(str);
} }
}; };
///
/// \brief formatter of a character array
/// \tparam N the number of characters
template<size_t N> template<size_t N>
struct formatter<const char[N]> { struct formatter<const char[N]> {
///
/// \brief format function
/// \param str the string argument
/// \returns the formatted version of \f$str\f$
string operator()(const format_arg&, const char (&str)[N]) { string operator()(const format_arg&, const char (&str)[N]) {
return string(str); return string(str);
} }
}; };
///
/// \brief formatter of a C-Style string
template<> template<>
struct formatter<cstring> { struct formatter<cstring> {
///
/// \brief format function
/// \param str the string argument
/// \returns the formatted version of \f$str\f$
string operator()(const format_arg&, const cstring& str) { string operator()(const format_arg&, const cstring& str) {
return str; return str;
} }
}; };
///
/// \brief formatter of a string
template<> template<>
struct formatter<string> { struct formatter<string> {
///
/// \brief format function
/// \param str the string argument
/// \returns the formatted version of \f$str\f$
string operator()(const format_arg&, const string& str) { string operator()(const format_arg&, const string& str) {
return str; return str;
} }
@@ -85,8 +116,15 @@ struct formatter<string> {
// decimal types ======================================================================================================= // decimal types =======================================================================================================
///
/// \brief formatter of integral types
template<typename IntT> requires(is_integral_v<IntT> and not is_bool_v<IntT>) template<typename IntT> requires(is_integral_v<IntT> and not is_bool_v<IntT>)
struct formatter<IntT> { struct formatter<IntT> {
///
/// \brief format function
/// \param fmt the format specification
/// \param x the integral argument
/// \returns the formatted version of \f$x\f$
string operator()(const format_arg& fmt, IntT x) { string operator()(const format_arg& fmt, IntT x) {
char digits[128] = {}; char digits[128] = {};
auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.base); auto chk = fennec::to_chars(digits, digits + sizeof(digits), fennec::abs(x), fmt.base);
@@ -154,8 +192,15 @@ struct formatter<IntT> {
} }
}; };
///
/// \brief formatter of boolean types
template<typename BoolT> requires(is_bool_v<BoolT>) template<typename BoolT> requires(is_bool_v<BoolT>)
struct formatter<BoolT> { struct formatter<BoolT> {
///
/// \brief format function
/// \param fmt the format specification
/// \param x the boolean argument
/// \returns the formatted version of \f$x\f$
string operator()(const format_arg& fmt, BoolT x) { string operator()(const format_arg& fmt, BoolT x) {
if (fmt.type == 's' or fmt.type == '\0') { if (fmt.type == 's' or fmt.type == '\0') {
return x ? string("true") : string("false"); return x ? string("true") : string("false");
@@ -165,8 +210,15 @@ struct formatter<BoolT> {
} }
}; };
///
/// \brief formatter of floating point types
template<typename FloatT> requires(is_floating_point_v<FloatT>) template<typename FloatT> requires(is_floating_point_v<FloatT>)
struct formatter<FloatT> { struct formatter<FloatT> {
///
/// \brief format function
/// \param fmt the format specification
/// \param x the float argument
/// \returns the formatted version of \f$x\f$
string operator()(const format_arg& fmt, FloatT x) { string operator()(const format_arg& fmt, FloatT x) {
// nan & inf cases // nan & inf cases

View File

@@ -46,18 +46,18 @@
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// assert(expr, desc) /// assert(expr, desc)
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Make an assertion with expression `expr` and provide a description `desc`. Only halts in debug mode. /// Make an assertion with expression \f$expr\f$ and provide a description \f$desc\f$. Only halts in debug mode.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// assertf(expr, desc) /// assertf(expr, desc)
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Make an assertion with expression `expr` and provide a description `desc`. Always halts. /// Make an assertion with expression \f$expr\f$ and provide a description \f$desc\f$. Always halts.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// assertd(expr, desc) /// assertd(expr, desc)
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Make an assertion, ***only in debug mode***, with expression `expr` and provide a description `desc`. /// Make an assertion, ***only in debug mode***, with expression \f$expr\f$ and provide a description \f$desc\f$.
/// This should be used when the branching caused by `assert` would hinder performance in release mode. /// This should be used when the branching caused by \f$assert\f$ would hinder performance in release mode.
/// ///
/// </table> /// </table>
/// ///

View File

@@ -90,12 +90,12 @@ using conditional_t
= typename conditional<B, TrueT, FalseT>::type; = typename conditional<B, TrueT, FalseT>::type;
// specialization of fennec::conditional for `true` case // specialization of fennec::conditional for \f$true\f$ case
template<typename T, typename F> template<typename T, typename F>
struct conditional<true, T, F> : type_identity<T>{}; struct conditional<true, T, F> : type_identity<T>{};
// specialization of fennec::conditional for `false` case // specialization of fennec::conditional for \f$false\f$ case
template<typename T, typename F> template<typename T, typename F>
struct conditional<false, T, F> : type_identity<F>{}; struct conditional<false, T, F> : type_identity<F>{};
@@ -105,7 +105,7 @@ struct conditional<false, T, F> : type_identity<F>{};
/// ///
/// \brief Detect whether `DetectT<ArgsT...>` is a valid type /// \brief Detect whether `DetectT<ArgsT...>` is a valid type
/// ///
/// \details Selects `DetectT<ArgsT...>` if it exists, otherwise selects `DefaultT` The chosen type is stored in `detect::type` and /// \details Selects `DetectT<ArgsT...>` if it exists, otherwise selects \f$DefaultT\f$ The chosen type is stored in `detect::type` and
/// a boolean value is stored in `detect::is_detected` representing whether `DetectT<ArgsT...>` is found. /// a boolean value is stored in `detect::is_detected` representing whether `DetectT<ArgsT...>` is found.
/// \tparam DefaultT Default type /// \tparam DefaultT Default type
/// \tparam DetectT Type to detect /// \tparam DetectT Type to detect
@@ -138,7 +138,7 @@ struct detect<DefaultT, DetectT, ArgsT...>
/// ///
/// \brief Leverage SFINAE to conditionally enable a function or class at compile-time /// \brief Leverage SFINAE to conditionally enable a function or class at compile-time
/// ///
/// \details If `B` is `true`, define a public member type `type`. Otherwise, there is no member. <br> /// \details If \f$B\f$ is \f$true\f$, define a public member type \f$type\f$. Otherwise, there is no member. <br>
/// **Example Usage** /// **Example Usage**
/// \code{.cpp} /// \code{.cpp}
/// template<typename TypeT, /// template<typename TypeT,

View File

@@ -55,44 +55,44 @@
/// `FENNEC_HAS_BUILTIN_IS_CONVERTIBLE` <br> /// `FENNEC_HAS_BUILTIN_IS_CONVERTIBLE` <br>
/// `B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)` /// `B FENNEC_BUILTIN_IS_CONVERTIBLE(X, Y)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type `X` can be converted to type `Y`. /// Checks if type \f$X\f$ can be converted to type \f$Y\f$.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// `FENNEC_HAS_BUILTIN_IS_EMPTY` <br> /// `FENNEC_HAS_BUILTIN_IS_EMPTY` <br>
/// `B FENNEC_BUILTIN_IS_EMPTY(X)` /// `B FENNEC_BUILTIN_IS_EMPTY(X)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type `X` stores no data. /// Checks if type \f$X\f$ stores no data.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// `FENNEC_HAS_BUILTIN_IS_POLYMORPHIC` <br> /// `FENNEC_HAS_BUILTIN_IS_POLYMORPHIC` <br>
/// `B FENNEC_BUILTIN_IS_POLYMORPHIC(X)` /// `B FENNEC_BUILTIN_IS_POLYMORPHIC(X)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type `X` is polymorphic, this is for classes only thus checks only for subtyping /// Checks if type \f$X\f$ is polymorphic, this is for classes only thus checks only for subtyping
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// `FENNEC_HAS_BUILTIN_IS_FINAL` <br> /// `FENNEC_HAS_BUILTIN_IS_FINAL` <br>
/// `B FENNEC_BUILTIN_IS_FINAL(X)` /// `B FENNEC_BUILTIN_IS_FINAL(X)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type `X` is final, meaning a function or class cannot be derived from. /// Checks if type \f$X\f$ is final, meaning a function or class cannot be derived from.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// `FENNEC_HAS_BUILTIN_IS_ABSTRACT` <br> /// `FENNEC_HAS_BUILTIN_IS_ABSTRACT` <br>
/// `B FENNEC_BUILTIN_IS_ABSTRACT(X)` /// `B FENNEC_BUILTIN_IS_ABSTRACT(X)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Opposite of `FENNEC_BUILTIN_IS_FINAL`, checks if abstract, meaning `X` has at least one pure virtual function. /// Opposite of `FENNEC_BUILTIN_IS_FINAL`, checks if abstract, meaning \f$X\f$ has at least one pure virtual function.
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// `FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT` <br> /// `FENNEC_HAS_BUILTIN_IS_STANDARD_LAYOUT` <br>
/// `B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)` /// `B FENNEC_BUILTIN_IS_STANDARD_LAYOUT(X)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if `X` has a standard layout, here is [full criteria](https://www.cppreference.com/w/cpp/language/classes.html#Standard-layout_class) /// Checks if \f$X\f$ has a standard layout, here is [full criteria](https://www.cppreference.com/w/cpp/language/classes.html#Standard-layout_class)
/// for this trait /// for this trait
/// ///
/// <tr><td width="50%" style="vertical-align: top"> <br> /// <tr><td width="50%" style="vertical-align: top"> <br>
/// `FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE` <br> /// `FENNEC_HAS_BUILTIN_IS_CONSTRUCTIBLE` <br>
/// `B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)` /// `B FENNEC_BUILTIN_IS_CONSTRUCTIBLE(X, ...)`
/// <td width="50%" style="vertical-align: top"> /// <td width="50%" style="vertical-align: top">
/// Checks if type `X` is constructible with args `...`, such that `X::X(...)` exists. /// Checks if type \f$X\f$ is constructible with args `...`, such that `X::X(...)` exists.
/// ///
/// </table> /// </table>
/// ///

View File

@@ -80,7 +80,7 @@ namespace fennec
/// ///
/// \brief metaprogramming sequence /// \brief metaprogramming sequence
/// ///
/// \details Stores a sequence of values of type `ValueT` as a template pack. /// \details Stores a sequence of values of type \f$ValueT\f$ as a template pack.
/// You can access the parameter pack in another template function, i.e. /// You can access the parameter pack in another template function, i.e.
/// \code{cpp} /// \code{cpp}
/// template<typename TypeT, TypeT...Values> /// template<typename TypeT, TypeT...Values>

View File

@@ -97,7 +97,7 @@ template<size_t n, typename...TypesT> using nth_element_t = nth_element<n, Types
// fennec::replace_first_element ======================================================================================= // fennec::replace_first_element =======================================================================================
/// ///
/// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first `ArgT` of `ArgsT...` with `SubT` /// \brief Take a Template with a Pack `ClassT<ArgsT...>` and replace the first \f$ArgT\f$ of `ArgsT...` with \f$SubT\f$
template<typename ClassT, typename SubT> struct replace_first_element { }; template<typename ClassT, typename SubT> struct replace_first_element { };
// Implementation // Implementation
@@ -127,7 +127,7 @@ template<typename...Ts> constexpr size_t max_element_size_v = max_element_size<T
// fennec::find_element ================================================================================================ // fennec::find_element ================================================================================================
/// ///
/// \brief Finds the index of `T` in `Ts`, if `T` is not found, results in `sizeof...(Ts)` /// \brief Finds the index of \f$T\f$ in \f$Ts\f$, if \f$T\f$ is not found, results in `sizeof...(Ts)`
/// \tparam T The type to find /// \tparam T The type to find
/// \tparam Ts The type sequence to check /// \tparam Ts The type sequence to check
template<typename T, typename...Ts> struct find_element : detail::_find_element<0, T, Ts...> {}; template<typename T, typename...Ts> struct find_element : detail::_find_element<0, T, Ts...> {};
@@ -169,7 +169,7 @@ struct search_element_args<SearchT, type_sequence<ArgsT...>, TypesT...>
// fennec::contains_element ============================================================================================ // fennec::contains_element ============================================================================================
/// ///
/// \brief Checks if the type sequence `Ts...` contains `T` /// \brief Checks if the type sequence `Ts...` contains \f$T\f$
/// \tparam T The type to find /// \tparam T The type to find
/// \tparam Ts The type sequence to check /// \tparam Ts The type sequence to check
template<typename T, typename...Ts> struct contains_element : bool_constant<(is_same_v<T, Ts> or ...)> {}; template<typename T, typename...Ts> struct contains_element : bool_constant<(is_same_v<T, Ts> or ...)> {};

View File

@@ -649,7 +649,7 @@ template<typename T> constexpr bool_t is_pointer_v = is_pointer<T> {};
/// ///
/// \brief Check if \p T is of a floating point type /// \brief Check if \p T is of a floating point type
/// ///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`. /// \details Checks if type \f$T\f$ is a floating point type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_lvalue_reference template<typename T> struct is_lvalue_reference
: detail::_is_lvalue_reference<T>{}; : detail::_is_lvalue_reference<T>{};
@@ -666,7 +666,7 @@ template<typename T> constexpr bool_t is_lvalue_reference_v = is_lvalue_referenc
/// ///
/// \brief Check if \p T is of a floating point type /// \brief Check if \p T is of a floating point type
/// ///
/// \details Checks if type `T` is a floating point type and store it in `is_same::value`. /// \details Checks if type \f$T\f$ is a floating point type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_rvalue_reference template<typename T> struct is_rvalue_reference
: detail::_is_rvalue_reference<T>{}; : detail::_is_rvalue_reference<T>{};
@@ -683,7 +683,7 @@ template<typename T> constexpr bool_t is_rvalue_reference_v = is_rvalue_referenc
/// ///
/// \brief Check if \p T is a pointer to a member function /// \brief Check if \p T is a pointer to a member function
/// ///
/// \details Checks if type `T` is pointer to a member function and store it in `is_member_function_pointer::value`. /// \details Checks if type \f$T\f$ is pointer to a member function and store it in `is_member_function_pointer::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_member_function_pointer template<typename T> struct is_member_function_pointer
: bool_constant<FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(T)> {}; : bool_constant<FENNEC_BUILTIN_IS_MEMBER_FUNCTION_POINTER(T)> {};
@@ -700,7 +700,7 @@ template<typename T> constexpr bool_t is_member_function_pointer_v = is_member_f
/// ///
/// \brief Check if \p T is a pointer to a member object /// \brief Check if \p T is a pointer to a member object
/// ///
/// \details Checks if type `T` is pointer to a member object and store it in `is_member_object_pointer::value`. /// \details Checks if type \f$T\f$ is pointer to a member object and store it in `is_member_object_pointer::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_member_object_pointer template<typename T> struct is_member_object_pointer
: bool_constant<FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(T)> {}; : bool_constant<FENNEC_BUILTIN_IS_MEMBER_OBJECT_POINTER(T)> {};
@@ -722,7 +722,7 @@ template<typename T> constexpr bool_t is_member_object_pointer_v = is_member_obj
/// ///
/// \brief Check if \p T is an arithmetic type /// \brief Check if \p T is an arithmetic type
/// ///
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_same::value`. /// \details Checks if type \f$T\f$ is a built-in type with arithmetic operators and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_arithmetic template<typename T> struct is_arithmetic
: bool_constant<is_integral_v<T> or is_floating_point_v<T>>{}; : bool_constant<is_integral_v<T> or is_floating_point_v<T>>{};
@@ -753,7 +753,7 @@ template<typename T> constexpr bool_t is_fundamental_v = is_fundamental<T>::valu
/// ///
/// \brief Check if \p T is an arithmetic type /// \brief Check if \p T is an arithmetic type
/// ///
/// \details Checks if type `T` is a built-in type with arithmetic operators and store it in `is_scalar::value`. /// \details Checks if type \f$T\f$ is a built-in type with arithmetic operators and store it in `is_scalar::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_scalar template<typename T> struct is_scalar
: bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{}; : bool_constant<is_arithmetic_v<T> or is_enum_v<T> or is_pointer_v<T>>{};
@@ -770,7 +770,7 @@ template<typename T> constexpr bool_t is_scalar_v = is_scalar<T>::value;
/// ///
/// \brief Check if \p T is an object /// \brief Check if \p T is an object
/// ///
/// \details Checks if type `T` is an object and store it in `is_object::value`. /// \details Checks if type \f$T\f$ is an object and store it in `is_object::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_object : bool_constant<FENNEC_BUILTIN_IS_OBJECT(T)> {}; template<typename T> struct is_object : bool_constant<FENNEC_BUILTIN_IS_OBJECT(T)> {};
@@ -786,7 +786,7 @@ template<typename T> constexpr bool_t is_object_v = is_object<T>::value;
/// ///
/// \brief Check if \p T is a object compound type /// \brief Check if \p T is a object compound type
/// ///
/// \details Checks if type `T` is an object and store it in `is_compound::value`. /// \details Checks if type \f$T\f$ is an object and store it in `is_compound::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_compound : bool_constant<not is_fundamental_v<T>> {}; template<typename T> struct is_compound : bool_constant<not is_fundamental_v<T>> {};
@@ -802,7 +802,7 @@ template<typename T> constexpr bool_t is_compound_v = is_compound<T>::value;
/// ///
/// \brief Check if \p T is of a reference type /// \brief Check if \p T is of a reference type
/// ///
/// \details Checks if type `T` is a reference type and store it in `is_reference::value`. /// \details Checks if type \f$T\f$ is a reference type and store it in `is_reference::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_reference template<typename T> struct is_reference
: detail::_is_reference<T>{}; : detail::_is_reference<T>{};
@@ -819,7 +819,7 @@ template<typename T> constexpr bool_t is_reference_v = is_reference<T> {};
/// ///
/// \brief Check if \p T is a pointer to a member /// \brief Check if \p T is a pointer to a member
/// ///
/// \details Checks if type `T` is pointer to a member and store it in `is_member_function_pointer::value`. /// \details Checks if type \f$T\f$ is pointer to a member and store it in `is_member_function_pointer::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_member_pointer template<typename T> struct is_member_pointer
: bool_constant<FENNEC_BUILTIN_IS_MEMBER_POINTER(T)> {}; : bool_constant<FENNEC_BUILTIN_IS_MEMBER_POINTER(T)> {};
@@ -841,7 +841,7 @@ template<typename T> constexpr bool_t is_member_pointer_v = is_member_pointer<T>
/// ///
/// \brief Check if \p T is of a const type /// \brief Check if \p T is of a const type
/// ///
/// \details Checks if type `T` is a const type and store it in `is_same::value`. /// \details Checks if type \f$T\f$ is a const type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_const template<typename T> struct is_const
: detail::_is_const<T>{}; : detail::_is_const<T>{};
@@ -858,7 +858,7 @@ template<typename T> constexpr bool_t is_const_v = is_const<T> {};
/// ///
/// \brief Check if \p T is of a volatile type /// \brief Check if \p T is of a volatile type
/// ///
/// \details Checks if type `T` is a volatile type and store it in `is_same::value`. /// \details Checks if type \f$T\f$ is a volatile type and store it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_volatile template<typename T> struct is_volatile
: detail::_is_volatile<T>{}; : detail::_is_volatile<T>{};
@@ -873,9 +873,9 @@ template<typename T> constexpr bool_t is_volatile_v = is_volatile<T> {};
// fennec::is_trivial -------------------------------------------------------------------------------------------------- // fennec::is_trivial --------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is trivial /// \brief Check if type \f$T\f$ is trivial
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_trivial : bool_constant<FENNEC_BUILTIN_IS_TRIVIAL(T)> {}; template<typename T> struct is_trivial : bool_constant<FENNEC_BUILTIN_IS_TRIVIAL(T)> {};
@@ -889,9 +889,9 @@ template<typename T> constexpr bool_t is_trivial_v = is_trivial<T>{};
// fennec::is_trivially_copyable --------------------------------------------------------------------------------------- // fennec::is_trivially_copyable ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is trivially_copyable /// \brief Check if type \f$T\f$ is trivially_copyable
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_trivially_copyable : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(T)> {}; template<typename T> struct is_trivially_copyable : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_COPYABLE(T)> {};
@@ -905,9 +905,9 @@ template<typename T> constexpr bool_t is_trivially_copyable_v = is_trivially_cop
// fennec::is_standard_layout ------------------------------------------------------------------------------------------ // fennec::is_standard_layout ------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is standard_layout /// \brief Check if type \f$T\f$ is standard_layout
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_standard_layout : bool_constant<FENNEC_BUILTIN_IS_STANDARD_LAYOUT(T)> {}; template<typename T> struct is_standard_layout : bool_constant<FENNEC_BUILTIN_IS_STANDARD_LAYOUT(T)> {};
@@ -921,9 +921,9 @@ template<typename T> constexpr bool_t is_standard_layout_v = is_standard_layout<
// fennec::has_unique_object_representations --------------------------------------------------------------------------- // fennec::has_unique_object_representations ---------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` has unique object representations /// \brief Check if type \f$T\f$ has unique object representations
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct has_unique_object_representations template<typename T> struct has_unique_object_representations
: bool_constant<FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(remove_cv_t<T>)> {}; : bool_constant<FENNEC_BUILTIN_HAS_UNIQUE_OBJECT_REPRESENTATIONS(remove_cv_t<T>)> {};
@@ -938,9 +938,9 @@ template<typename T> constexpr bool_t has_unique_object_representations_v = has_
// fennec::is_empty ---------------------------------------------------------------------------------------------------- // fennec::is_empty ----------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is empty /// \brief Check if type \f$T\f$ is empty
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_empty : bool_constant<FENNEC_BUILTIN_IS_EMPTY(T)> {}; template<typename T> struct is_empty : bool_constant<FENNEC_BUILTIN_IS_EMPTY(T)> {};
@@ -954,9 +954,9 @@ template<typename T> constexpr bool_t is_empty_v = is_empty<T>{};
// fennec::is_polymorphic ---------------------------------------------------------------------------------------------- // fennec::is_polymorphic ----------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is polymorphic /// \brief Check if type \f$T\f$ is polymorphic
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_polymorphic : bool_constant<FENNEC_BUILTIN_IS_POLYMORPHIC(T)> {}; template<typename T> struct is_polymorphic : bool_constant<FENNEC_BUILTIN_IS_POLYMORPHIC(T)> {};
@@ -970,9 +970,9 @@ template<typename T> constexpr bool_t is_polymorphic_v = is_polymorphic<T>{};
// fennec::is_abstract ------------------------------------------------------------------------------------------------- // fennec::is_abstract -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is abstract /// \brief Check if type \f$T\f$ is abstract
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_abstract : bool_constant<FENNEC_BUILTIN_IS_ABSTRACT(T)> {}; template<typename T> struct is_abstract : bool_constant<FENNEC_BUILTIN_IS_ABSTRACT(T)> {};
@@ -986,9 +986,9 @@ template<typename T> constexpr bool_t is_abstract_v = is_abstract<T>{};
// fennec::is_complete ------------------------------------------------------------------------------------------------- // fennec::is_complete -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is complete /// \brief Check if type \f$T\f$ is complete
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_complete : detail::_is_complete<T>::type {}; template<typename T> struct is_complete : detail::_is_complete<T>::type {};
@@ -1002,9 +1002,9 @@ template<typename T> constexpr bool_t is_complete_v = is_complete<T>{};
// fennec::is_final ------------------------------------------------------------------------------------------------- // fennec::is_final -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is final /// \brief Check if type \f$T\f$ is final
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_final : bool_constant<FENNEC_BUILTIN_IS_FINAL(T)> {}; template<typename T> struct is_final : bool_constant<FENNEC_BUILTIN_IS_FINAL(T)> {};
@@ -1018,9 +1018,9 @@ template<typename T> constexpr bool_t is_final_v = is_final<T>{};
// fennec::is_aggregate ------------------------------------------------------------------------------------------------- // fennec::is_aggregate -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is aggregate /// \brief Check if type \f$T\f$ is aggregate
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_aggregate : bool_constant<FENNEC_BUILTIN_IS_AGGREGATE(T)> {}; template<typename T> struct is_aggregate : bool_constant<FENNEC_BUILTIN_IS_AGGREGATE(T)> {};
@@ -1037,7 +1037,7 @@ template<typename T> constexpr bool_t is_aggregate_v = is_aggregate<T>{};
/// ///
/// \brief Check if \p T is of a signed integral /// \brief Check if \p T is of a signed integral
/// ///
/// \details Checks if type `T` is a signed type i.e. `T(-1) < T(0)` and stores it in `is_same::value`. /// \details Checks if type \f$T\f$ is a signed type i.e. `T(-1) < T(0)` and stores it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_signed template<typename T> struct is_signed
: detail::_is_signed<remove_cvref_t<T>> {}; : detail::_is_signed<remove_cvref_t<T>> {};
@@ -1055,7 +1055,7 @@ template<typename T> constexpr bool_t is_signed_v = is_signed<T>::value;
/// ///
/// \brief Check if \p T is of an unsigned integral /// \brief Check if \p T is of an unsigned integral
/// ///
/// \details Checks if type `T` is an unsigned type i.e. `T(-1) > T(0)` and stores it in `is_same::value`. /// \details Checks if type \f$T\f$ is an unsigned type i.e. `T(-1) > T(0)` and stores it in `is_same::value`.
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_unsigned template<typename T> struct is_unsigned
: detail::_is_unsigned<remove_cvref_t<T>> {}; : detail::_is_unsigned<remove_cvref_t<T>> {};
@@ -1172,9 +1172,9 @@ template<typename T> constexpr bool_t is_scoped_enum_v = is_scoped_enum<T>::valu
// fennec::is_convertible ---------------------------------------------------------------------------------------------- // fennec::is_convertible ----------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T0` can be converted `T1` /// \brief Check if type \f$T0\f$ can be converted \f$T1\f$
/// ///
/// \details Checks if `TypeT0` /// \details Checks if \f$TypeT0\f$
/// \tparam FromT First type /// \tparam FromT First type
/// \tparam ToT Second type /// \tparam ToT Second type
template<typename FromT, typename ToT> struct is_convertible template<typename FromT, typename ToT> struct is_convertible
@@ -1191,8 +1191,8 @@ template<typename FromT, typename ToT> constexpr bool_t is_convertible_v = is_co
// fennec::is_constructible -------------------------------------------------------------------------------------------- // fennec::is_constructible --------------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`. /// \brief Check if \f$ClassT\f$ can be constructed with `ArgsT,` i.e. `ClassT(ArgsT...)`.
/// This may be read as "is `ClassT` constructible with `ArgsT`" /// This may be read as "is \f$ClassT\f$ constructible with \f$ArgsT\f$"
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor /// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_constructible template<typename ClassT, typename...ArgsT> struct is_constructible
@@ -1207,7 +1207,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_constructible_v
// fennec::is_trivially_constructible ---------------------------------------------------------------------------------- // fennec::is_trivially_constructible ----------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially constructible /// \brief Check if \f$ClassT\f$ is trivially constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor /// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_trivially_constructible template<typename ClassT, typename...ArgsT> struct is_trivially_constructible
@@ -1222,7 +1222,7 @@ template<typename ClassT> constexpr bool_t is_trivially_constructible_v = is_tri
// fennec::is_nothrow_constructible ------------------------------------------------------------------------------------ // fennec::is_nothrow_constructible ------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow constructible /// \brief Check if \f$ClassT\f$ is nothrow constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
/// \tparam ArgsT The arguments for the specific constructor /// \tparam ArgsT The arguments for the specific constructor
template<typename ClassT, typename...ArgsT> struct is_nothrow_constructible template<typename ClassT, typename...ArgsT> struct is_nothrow_constructible
@@ -1237,7 +1237,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_constructible_v = is_nothr
// fennec::is_default_constructible ------------------------------------------------------------------------------------ // fennec::is_default_constructible ------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is default constructible /// \brief Check if \f$ClassT\f$ is default constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_default_constructible template<typename ClassT> struct is_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT)> {};
@@ -1251,7 +1251,7 @@ template<typename ClassT> constexpr bool_t is_default_constructible_v = is_defau
// fennec::is_trivially_default_constructible -------------------------------------------------------------------------- // fennec::is_trivially_default_constructible --------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially default constructible /// \brief Check if \f$ClassT\f$ is trivially default constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_default_constructible template<typename ClassT> struct is_trivially_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_CONSTRUCTIBLE(ClassT)> {};
@@ -1265,7 +1265,7 @@ template<typename ClassT> constexpr bool_t is_trivially_default_constructible_v
// fennec::is_nothrow_default_constructible -------------------------------------------------------------------------- // fennec::is_nothrow_default_constructible --------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow default constructible /// \brief Check if \f$ClassT\f$ is nothrow default constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_default_constructible template<typename ClassT> struct is_nothrow_default_constructible
: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_NOTHROW_CONSTRUCTIBLE(ClassT)> {};
@@ -1279,7 +1279,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_default_constructible_v =
// fennec::is_copy_constructible --------------------------------------------------------------------------------------- // fennec::is_copy_constructible ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is copy constructible /// \brief Check if \f$ClassT\f$ is copy constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_constructible template<typename ClassT> struct is_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1293,7 +1293,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_copy_constructib
// fennec::is_trivially_copy_constructible ----------------------------------------------------------------------------- // fennec::is_trivially_copy_constructible -----------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially copy constructible /// \brief Check if \f$ClassT\f$ is trivially copy constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_copy_constructible template<typename ClassT> struct is_trivially_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1307,7 +1307,7 @@ template<typename ClassT> struct is_trivially_copy_constructible
// fennec::is_nothrow_copy_constructible ------------------------------------------------------------------------------- // fennec::is_nothrow_copy_constructible -------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow copy constructible /// \brief Check if \f$ClassT\f$ is nothrow copy constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_copy_constructible template<typename ClassT> struct is_nothrow_copy_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1321,7 +1321,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_nothrow_copy_con
// fennec::is_move_constructible --------------------------------------------------------------------------------------- // fennec::is_move_constructible ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is move constructible /// \brief Check if \f$ClassT\f$ is move constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_constructible template<typename ClassT> struct is_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_rvalue_reference_t<ClassT>)> {};
@@ -1335,7 +1335,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_move_constructib
// fennec::is_trivially_move_constructible ----------------------------------------------------------------------------- // fennec::is_trivially_move_constructible -----------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially move constructible /// \brief Check if \f$ClassT\f$ is trivially move constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_move_constructible template<typename ClassT> struct is_trivially_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1349,7 +1349,7 @@ template<typename ClassT> struct is_trivially_move_constructible
// fennec::is_nothrow_move_constructible ------------------------------------------------------------------------------- // fennec::is_nothrow_move_constructible -------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow move constructible /// \brief Check if \f$ClassT\f$ is nothrow move constructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_move_constructible template<typename ClassT> struct is_nothrow_move_constructible
: bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_CONSTRUCTIBLE(ClassT, add_lvalue_reference_t<const ClassT>)> {};
@@ -1363,7 +1363,7 @@ template<typename ClassT, typename...ArgsT> constexpr bool_t is_nothrow_move_con
// fennec::is_assignable ----------------------------------------------------------------------------------------------- // fennec::is_assignable -----------------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is assignable /// \brief Check if \f$ClassT\f$ is assignable
/// \tparam ClassAT The class type to test /// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor /// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_assignable template<typename ClassAT, typename ClassBT> struct is_assignable
@@ -1378,7 +1378,7 @@ template<typename ClassAT, typename ClassBT> constexpr bool_t is_assignable_v =
// fennec::is_trivially_assignable ------------------------------------------------------------------------------------- // fennec::is_trivially_assignable -------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially assignable /// \brief Check if \f$ClassT\f$ is trivially assignable
/// \tparam ClassAT The class type to test /// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor /// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_trivially_assignable template<typename ClassAT, typename ClassBT> struct is_trivially_assignable
@@ -1394,7 +1394,7 @@ template<typename ClassAT, typename ClassBT> constexpr bool_t is_trivially_assig
// fennec::is_nothrow_assignable --------------------------------------------------------------------------------------- // fennec::is_nothrow_assignable ---------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow assignable /// \brief Check if \f$ClassT\f$ is nothrow assignable
/// \tparam ClassAT The class type to test /// \tparam ClassAT The class type to test
/// \tparam ClassBT The arguments for the specific constructor /// \tparam ClassBT The arguments for the specific constructor
template<typename ClassAT, typename ClassBT> struct is_nothrow_assignable template<typename ClassAT, typename ClassBT> struct is_nothrow_assignable
@@ -1409,7 +1409,7 @@ template<typename ClassAT, typename ClassBT> constexpr bool_t is_nothrow_assigna
// fennec::is_copy_assignable ------------------------------------------------------------------------------------------ // fennec::is_copy_assignable ------------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is copy assignable /// \brief Check if \f$ClassT\f$ is copy assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_copy_assignable template<typename ClassT> struct is_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1423,7 +1423,7 @@ template<typename ClassT> constexpr bool_t is_copy_assignable_v = is_copy_assign
// fennec::is_trivially_copy_assignable -------------------------------------------------------------------------------- // fennec::is_trivially_copy_assignable --------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially_copy assignable /// \brief Check if \f$ClassT\f$ is trivially_copy assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_copy_assignable template<typename ClassT> struct is_trivially_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1437,7 +1437,7 @@ template<typename ClassT> constexpr bool_t is_trivially_copy_assignable_v = is_t
// fennec::is_nothrow_copy_assignable ---------------------------------------------------------------------------------- // fennec::is_nothrow_copy_assignable ----------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow_copy assignable /// \brief Check if \f$ClassT\f$ is nothrow_copy assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_copy_assignable template<typename ClassT> struct is_nothrow_copy_assignable
: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_lvalue_reference_t<const ClassT>)> {};
@@ -1451,7 +1451,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_copy_assignable_v = is_not
// fennec::is_move_assignable ------------------------------------------------------------------------------------------ // fennec::is_move_assignable ------------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is move assignable /// \brief Check if \f$ClassT\f$ is move assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_move_assignable template<typename ClassT> struct is_move_assignable
: bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
@@ -1465,7 +1465,7 @@ template<typename ClassT> constexpr bool_t is_move_assignable_v = is_move_assign
// fennec::is_trivially_move_assignable -------------------------------------------------------------------------------- // fennec::is_trivially_move_assignable --------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially_move assignable /// \brief Check if \f$ClassT\f$ is trivially_move assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_move_assignable template<typename ClassT> struct is_trivially_move_assignable
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
@@ -1479,7 +1479,7 @@ template<typename ClassT> constexpr bool_t is_trivially_move_assignable_v = is_t
// fennec::is_nothrow_move_assignable -------------------------------------------------------------------------------- // fennec::is_nothrow_move_assignable --------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow_move assignable /// \brief Check if \f$ClassT\f$ is nothrow_move assignable
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_move_assignable template<typename ClassT> struct is_nothrow_move_assignable
: bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {}; : bool_constant<FENNEC_BUILTIN_IS_NOTHROW_ASSIGNABLE(add_lvalue_reference_t<ClassT>, add_rvalue_reference_t<ClassT>)> {};
@@ -1493,7 +1493,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_move_assignable_v = is_not
// fennec::is_destructible --------------------------------------------------------------------------------------------- // fennec::is_destructible ---------------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is destructible /// \brief Check if \f$ClassT\f$ is destructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_destructible template<typename ClassT> struct is_destructible
: detail::_is_destructible<ClassT>::type {}; : detail::_is_destructible<ClassT>::type {};
@@ -1507,7 +1507,7 @@ template<typename ClassT> constexpr bool_t is_destructible_v = is_destructible<C
// fennec::is_trivially_destructible ----------------------------------------------------------------------------------- // fennec::is_trivially_destructible -----------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is trivially destructible /// \brief Check if \f$ClassT\f$ is trivially destructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_trivially_destructible template<typename ClassT> struct is_trivially_destructible
: bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {}; : bool_constant<FENNEC_BUILTIN_IS_TRIVIALLY_DESTRUCTIBLE(ClassT)> {};
@@ -1521,7 +1521,7 @@ template<typename ClassT> constexpr bool_t is_trivially_destructible_v = is_triv
// fennec::is_nothrow_destructible ------------------------------------------------------------------------------------- // fennec::is_nothrow_destructible -------------------------------------------------------------------------------------
/// ///
/// \brief Check if `ClassT` is nothrow destructible /// \brief Check if \f$ClassT\f$ is nothrow destructible
/// \tparam ClassT The class type to test /// \tparam ClassT The class type to test
template<typename ClassT> struct is_nothrow_destructible template<typename ClassT> struct is_nothrow_destructible
: detail::_is_nothrow_destructible<ClassT>::type {}; : detail::_is_nothrow_destructible<ClassT>::type {};
@@ -1542,7 +1542,7 @@ template<typename ClassT> constexpr bool_t is_nothrow_destructible_v = is_nothro
/// ///
/// \brief Check if the two types are identical /// \brief Check if the two types are identical
/// ///
/// \details Checks if `T0` and `T1` are identical and store it in `is_same::value` /// \details Checks if \f$T0\f$ and \f$T1\f$ are identical and store it in `is_same::value`
/// \tparam T0 first type to check /// \tparam T0 first type to check
/// \tparam T1 second type to check /// \tparam T1 second type to check
template<typename T0, typename T1> struct is_same : false_type {}; template<typename T0, typename T1> struct is_same : false_type {};
@@ -1561,9 +1561,9 @@ template<typename T0, typename T1> constexpr bool_t is_same_v = is_same<T0, T1>
// fennec::is_base_of -------------------------------------------------------------------------------------------------- // fennec::is_base_of --------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if `Derived` has a base type of `Base` /// \brief Check if \f$Derived\f$ has a base type of \f$Base\f$
/// ///
/// \details Checks if `Base` is a base type of `Derived` and stores it in `is_base_of::value` /// \details Checks if \f$Base\f$ is a base type of \f$Derived\f$ and stores it in `is_base_of::value`
/// \tparam Base base type to check /// \tparam Base base type to check
/// \tparam Derived derived type to check /// \tparam Derived derived type to check
template<typename Base, typename Derived> struct is_base_of : bool_constant< template<typename Base, typename Derived> struct is_base_of : bool_constant<
@@ -1581,9 +1581,9 @@ template<typename Base, typename Derived> constexpr bool_t is_base_of_v = is_bas
// fennec::is_iterable ------------------------------------------------------------------------------------------------- // fennec::is_iterable -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is iterable /// \brief Check if type \f$T\f$ is iterable
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {}; template<typename T> struct is_iterable : decltype(detail::_is_iterable<T>(0)) {};
@@ -1597,9 +1597,9 @@ template<typename T> constexpr bool_t is_iterable_v = is_iterable<T>{};
// fennec::is_indexable ------------------------------------------------------------------------------------------------ // fennec::is_indexable ------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is indexable /// \brief Check if type \f$T\f$ is indexable
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {}; template<typename T> struct is_indexable : decltype(detail::_is_indexable<T>(0)) {};
@@ -1613,9 +1613,9 @@ template<typename T> constexpr bool_t is_indexable_v = is_indexable<T>{};
// fennec::is_mappable ------------------------------------------------------------------------------------------------- // fennec::is_mappable -------------------------------------------------------------------------------------------------
/// ///
/// \brief Check if type `T` is mappable /// \brief Check if type \f$T\f$ is mappable
/// ///
/// \details Checks if `T` /// \details Checks if \f$T\f$
/// \tparam T type to check /// \tparam T type to check
template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {}; template<typename T> struct is_mappable : decltype(detail::_is_mappable<T>(0)) {};

View File

@@ -138,7 +138,7 @@ template<typename T> using decay_t = typename decay<T>::type;
/// ///
/// \brief adds a pointer level to \p T /// \brief adds a pointer level to \p T
/// ///
/// \details adds a pointer to the provided type such that `T` becomes `T*` /// \details adds a pointer to the provided type such that \f$T\f$ becomes `T*`
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct add_pointer : detail::_add_pointer<T>{}; template<typename T> struct add_pointer : detail::_add_pointer<T>{};
@@ -150,7 +150,7 @@ template<typename T> using add_pointer_t = typename add_pointer<T>::type;
/// ///
/// \brief removes a pointer level from \p T /// \brief removes a pointer level from \p T
/// ///
/// \details removes a pointer from the provided type such that `T*` becomes `T` /// \details removes a pointer from the provided type such that `T*` becomes \f$T\f$
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct remove_pointer : detail::_remove_pointer<T> {}; template<typename T> struct remove_pointer : detail::_remove_pointer<T> {};
@@ -162,7 +162,7 @@ template<typename T> using remove_pointer_t = typename remove_pointer<T>::type;
/// ///
/// \brief removes all pointer levels from \p T /// \brief removes all pointer levels from \p T
/// ///
/// \details removes all pointers from the provided type such that `T*`, `T**`, etc. becomes `T` /// \details removes all pointers from the provided type such that `T*`, `T**`, etc. becomes \f$T\f$
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct strip_pointers : conditional_t< template<typename T> struct strip_pointers : conditional_t<
detail::_is_pointer<T>::value, detail::_is_pointer<T>::value,
@@ -179,7 +179,7 @@ template<typename T> using strip_pointers_t = strip_pointers<T>::type;
/// ///
/// \brief add a reference to \p T /// \brief add a reference to \p T
/// ///
/// \details adds a pointer to the provided type such that `T` becomes `T&` /// \details adds a pointer to the provided type such that \f$T\f$ becomes `T&`
/// \tparam T Resultant Type /// \tparam T Resultant Type
template<typename T> struct add_reference : type_identity<T&> {}; template<typename T> struct add_reference : type_identity<T&> {};
@@ -191,7 +191,7 @@ template<typename T> using add_reference_t = typename add_reference<T>::type;
/// ///
/// \brief remove a reference from \p T /// \brief remove a reference from \p T
/// ///
/// \details removes references from the provided type such that `T&` and `T&&` become `T` /// \details removes references from the provided type such that `T&` and `T&&` become \f$T\f$
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_reference : type_identity<T> {}; template<typename T> struct remove_reference : type_identity<T> {};
@@ -236,7 +236,7 @@ template<typename T> using add_rvalue_reference_t = typename add_rvalue_referen
/// ///
/// \brief add the const qualifier to the provided type \p T /// \brief add the const qualifier to the provided type \p T
/// ///
/// \details adds const qualification to the provided type such that `T` becomes `const T` /// \details adds const qualification to the provided type such that \f$T\f$ becomes `const T`
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_const : detail::_add_const<T> {}; template<typename T> struct add_const : detail::_add_const<T> {};
@@ -248,7 +248,7 @@ template<typename T> using add_const_t = typename add_const<T>::type;
/// ///
/// \brief remove the const qualifier from the provided type \p T /// \brief remove the const qualifier from the provided type \p T
/// ///
/// \details removes const qualification from the provided type such that `const T` becomes `T` /// \details removes const qualification from the provided type such that `const T` becomes \f$T\f$
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_const : detail::_remove_const<T> {}; template<typename T> struct remove_const : detail::_remove_const<T> {};
@@ -261,7 +261,7 @@ template<typename T> using remove_const_t = typename remove_const<T>::type;
/// ///
/// \brief add the volatile qualifier to the provided type \p T /// \brief add the volatile qualifier to the provided type \p T
/// ///
/// \details removes references from the provided type such that `T` becomes `volatile T` /// \details removes references from the provided type such that \f$T\f$ becomes `volatile T`
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_volatile : detail::_add_volatile<T> {}; template<typename T> struct add_volatile : detail::_add_volatile<T> {};
@@ -273,7 +273,7 @@ template<typename T> using add_volatile_t = typename add_volatile<T>::type;
/// ///
/// \brief remove the volatile qualifier from the provided type \p T /// \brief remove the volatile qualifier from the provided type \p T
/// ///
/// \details removes references from the provided type such that `volatile T` becomes `T` /// \details removes references from the provided type such that `volatile T` becomes \f$T\f$
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_volatile : detail::_remove_volatile<T> {}; template<typename T> struct remove_volatile : detail::_remove_volatile<T> {};
@@ -286,7 +286,7 @@ template<typename T> using remove_volatile_t = typename remove_volatile<T>::type
/// ///
/// \brief remove the volatile qualifier from the provided type \p T /// \brief remove the volatile qualifier from the provided type \p T
/// ///
/// \details removes references from the provided type such that `T`, `const T`, and `volatile T` become /// \details removes references from the provided type such that \f$T\f$, `const T`, and `volatile T` become
/// `const volatile T` /// `const volatile T`
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct add_cv : detail::_add_cv<T> {}; template<typename T> struct add_cv : detail::_add_cv<T> {};
@@ -301,7 +301,7 @@ template<typename T> using add_cv_t = typename add_cv<T>::type;
/// \brief remove the const and volatile qualifiers from the provided type \p T /// \brief remove the const and volatile qualifiers from the provided type \p T
/// ///
/// \details removes const and volatile from the provided type such that `const T`, `volatile T`, and /// \details removes const and volatile from the provided type such that `const T`, `volatile T`, and
/// `const volatile T` become `T` /// `const volatile T` become \f$T\f$
/// \tparam T Reference Type /// \tparam T Reference Type
template<typename T> struct remove_cv : detail::_remove_cv<T> {}; template<typename T> struct remove_cv : detail::_remove_cv<T> {};

View File

@@ -247,7 +247,7 @@ namespace fennec
using uintptr_t = uintptr_t; ///< \brief Unsigned Integer Capable of Holding a Pointer to void using uintptr_t = uintptr_t; ///< \brief Unsigned Integer Capable of Holding a Pointer to void
using intmax_t = intmax_t; ///< \brief Maximum Width Signed Integer Type using intmax_t = intmax_t; ///< \brief Maximum Width Signed Integer Type
using uintmax_t = uintmax_t; ///< \brief Maximum Width Unsigned Integer Type using uintmax_t = uintmax_t; ///< \brief Maximum Width Unsigned Integer Type
using size_t = size_t; ///< \brief Unsigned Integer Type Returned By `sizeof`, `sizeof...`, and `alignof` using size_t = size_t; ///< \brief Unsigned Integer Type Returned By \f$sizeof\f$, `sizeof...`, and \f$alignof\f$
using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers using ptrdiff_t = __PTRDIFF_TYPE__; ///< \brief Signed Integer Type Returned by the Subtraction of two Pointers
struct empty_t {}; struct empty_t {};

View File

@@ -52,7 +52,7 @@ constexpr genType sqnorm(const qua<genType>& q) {
/// ///
/// \brief Norm Function /// \brief Norm Function
/// \param q The Quaternion /// \param q The Quaternion
/// \returns The Hamilton Tensor of `q` /// \returns The Hamilton Tensor of \f$q\f$
template<typename genType> template<typename genType>
constexpr genType norm(const qua<genType>& q) { constexpr genType norm(const qua<genType>& q) {
return fennec::sqrt(sqnorm(q)); return fennec::sqrt(sqnorm(q));
@@ -61,7 +61,7 @@ constexpr genType norm(const qua<genType>& q) {
/// ///
/// \brief Unit Function (Versor) /// \brief Unit Function (Versor)
/// \param q The Quaternion /// \param q The Quaternion
/// \returns A Quaternion of `q` with norm `1` /// \returns A Quaternion of \f$q\f$ with norm \f$1\f$
template<typename genType> template<typename genType>
constexpr qua<genType> unit(const qua<genType>& q) { constexpr qua<genType> unit(const qua<genType>& q) {
genType n = fennec::norm(q); genType n = fennec::norm(q);
@@ -97,7 +97,7 @@ public:
// Constructors ======================================================================================================== // Constructors ========================================================================================================
/// ///
/// \brief Default Constructor, creates a quaternion such that the real part is `1` and all others are `0` /// \brief Default Constructor, creates a quaternion such that the real part is \f$1\f$ and all others are \f$0\f$
constexpr quaternion() { constexpr quaternion() {
data = { 0, 0, 0, 1 }; data = { 0, 0, 0, 1 };
} }
@@ -105,9 +105,9 @@ public:
/// ///
/// \brief Component Constructor /// \brief Component Constructor
/// \param w The scalar component /// \param w The scalar component
/// \param x The coefficient of the `i` component /// \param x The coefficient of the \f$i\f$ component
/// \param y The coefficient of the `j` component /// \param y The coefficient of the \f$j\f$ component
/// \param z The coefficient of the `k` component /// \param z The coefficient of the \f$k\f$ component
constexpr quaternion(scalar_t w, scalar_t x, scalar_t y, scalar_t z) { constexpr quaternion(scalar_t w, scalar_t x, scalar_t y, scalar_t z) {
data = { x, y, z, w }; data = { x, y, z, w };
} }
@@ -178,7 +178,7 @@ public:
/// \brief Equality Operator /// \brief Equality Operator
/// \param lhs the left hand side of the expression /// \param lhs the left hand side of the expression
/// \param rhs the right hand side of the expression /// \param rhs the right hand side of the expression
/// \returns `true` when all components of `lhs` and `rhs` are equal, false otherwise /// \returns \f$true\f$ when all components of \f$lhs\f$ and \f$rhs\f$ are equal, false otherwise
constexpr friend bool operator==(const quat_t& lhs, const quat_t& rhs) { constexpr friend bool operator==(const quat_t& lhs, const quat_t& rhs) {
return lhs.data == rhs.data; return lhs.data == rhs.data;
} }
@@ -187,7 +187,7 @@ public:
/// \brief Inequality Operator /// \brief Inequality Operator
/// \param lhs the left hand side of the expression /// \param lhs the left hand side of the expression
/// \param rhs the right hand side of the expression /// \param rhs the right hand side of the expression
/// \returns `true` when any component of `lhs` and `rhs` are not equal, false otherwise /// \returns \f$true\f$ when any component of \f$lhs\f$ and \f$rhs\f$ are not equal, false otherwise
constexpr friend bool operator!=(const quat_t& lhs, const quat_t& rhs) { constexpr friend bool operator!=(const quat_t& lhs, const quat_t& rhs) {
return lhs.data != rhs.data; return lhs.data != rhs.data;
} }
@@ -198,7 +198,7 @@ public:
/// ///
/// \brief Unary Negation Operator /// \brief Unary Negation Operator
/// \param rhs The quaternion to negate /// \param rhs The quaternion to negate
/// \returns A quaternion with each component of `rhs` negated. /// \returns A quaternion with each component of \f$rhs\f$ negated.
constexpr friend quat_t operator-(const quat_t& rhs) { constexpr friend quat_t operator-(const quat_t& rhs) {
return quat_t(-rhs.w, -rhs.x, -rhs.y, -rhs.z); return quat_t(-rhs.w, -rhs.x, -rhs.y, -rhs.z);
} }
@@ -206,7 +206,7 @@ public:
/// ///
/// \brief Unary Conjugation Operator /// \brief Unary Conjugation Operator
/// \param rhs The quaternion to conjugate /// \param rhs The quaternion to conjugate
/// \returns A quaternion with each vector component of `rhs` negated. /// \returns A quaternion with each vector component of \f$rhs\f$ negated.
constexpr friend quat_t operator~(const quat_t& rhs) { constexpr friend quat_t operator~(const quat_t& rhs) {
return quat_t(rhs.w, -rhs.x, -rhs.y, -rhs.z); return quat_t(rhs.w, -rhs.x, -rhs.y, -rhs.z);
} }
@@ -218,7 +218,7 @@ public:
/// \brief Quaternion-Scalar Multiplication Operator /// \brief Quaternion-Scalar Multiplication Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns A quaternion with each component of `lhs` multiplied by `rhs` /// \returns A quaternion with each component of \f$lhs\f$ multiplied by \f$rhs\f$
constexpr friend quat_t operator*(const quat_t& lhs, scalar_t rhs) { constexpr friend quat_t operator*(const quat_t& lhs, scalar_t rhs) {
return quat_t(lhs.w * rhs, lhs.x * rhs, lhs.y * rhs, lhs.z * rhs); return quat_t(lhs.w * rhs, lhs.x * rhs, lhs.y * rhs, lhs.z * rhs);
} }
@@ -227,7 +227,7 @@ public:
/// \brief Scalar-Quaternion Multiplication Operator /// \brief Scalar-Quaternion Multiplication Operator
/// \param lhs The scalar /// \param lhs The scalar
/// \param rhs The quaternion /// \param rhs The quaternion
/// \returns A quaternion with each component of `rhs` multiplied by `lhs` /// \returns A quaternion with each component of \f$rhs\f$ multiplied by \f$lhs\f$
constexpr friend quat_t operator*(scalar_t lhs, const quat_t& rhs) { constexpr friend quat_t operator*(scalar_t lhs, const quat_t& rhs) {
return quat_t(lhs * rhs.w, lhs * rhs.x, lhs * rhs.y, lhs * rhs.z); return quat_t(lhs * rhs.w, lhs * rhs.x, lhs * rhs.y, lhs * rhs.z);
} }
@@ -236,7 +236,7 @@ public:
/// \brief Quaternion-Scalar Division Operator /// \brief Quaternion-Scalar Division Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns A quaternion with each component of `lhs` divided by `rhs` /// \returns A quaternion with each component of \f$lhs\f$ divided by \f$rhs\f$
constexpr friend quat_t operator/(const quat_t& lhs, scalar_t rhs) { constexpr friend quat_t operator/(const quat_t& lhs, scalar_t rhs) {
return quat_t(lhs.w / rhs, lhs.x / rhs, lhs.y / rhs, lhs.z / rhs); return quat_t(lhs.w / rhs, lhs.x / rhs, lhs.y / rhs, lhs.z / rhs);
} }
@@ -245,7 +245,7 @@ public:
/// \brief Scalar-Quaternion Division Operator /// \brief Scalar-Quaternion Division Operator
/// \param lhs The scalar /// \param lhs The scalar
/// \param rhs The quaternion /// \param rhs The quaternion
/// \returns A quaternion with each component of `rhs` divided by `lhs` /// \returns A quaternion with each component of \f$rhs\f$ divided by \f$lhs\f$
constexpr friend quat_t operator/(scalar_t lhs, const quat_t& rhs) { constexpr friend quat_t operator/(scalar_t lhs, const quat_t& rhs) {
return quat_t(lhs / rhs.w, lhs / rhs.x, lhs / rhs.y, lhs / rhs.z); return quat_t(lhs / rhs.w, lhs / rhs.x, lhs / rhs.y, lhs / rhs.z);
} }
@@ -257,7 +257,7 @@ public:
/// \brief Quaternion-Scalar Multiplication Assignment Operator /// \brief Quaternion-Scalar Multiplication Assignment Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns `lhs` with each component multiplied by `rhs` /// \returns \f$lhs\f$ with each component multiplied by \f$rhs\f$
constexpr friend quat_t& operator*=(quat_t& lhs, scalar_t rhs) { constexpr friend quat_t& operator*=(quat_t& lhs, scalar_t rhs) {
lhs.x *= rhs; lhs.x *= rhs;
lhs.y *= rhs; lhs.y *= rhs;
@@ -270,7 +270,7 @@ public:
/// \brief Quaternion-Scalar Division Assignment Operator /// \brief Quaternion-Scalar Division Assignment Operator
/// \param lhs The quaternion /// \param lhs The quaternion
/// \param rhs The scalar /// \param rhs The scalar
/// \returns `lhs` with each component divided by `rhs` /// \returns \f$lhs\f$ with each component divided by \f$rhs\f$
constexpr friend quat_t& operator/=(const quat_t& lhs, scalar_t rhs) { constexpr friend quat_t& operator/=(const quat_t& lhs, scalar_t rhs) {
lhs.x /= rhs; lhs.x /= rhs;
lhs.y /= rhs; lhs.y /= rhs;

View File

@@ -627,7 +627,7 @@ struct matrix
/// \brief matrix comparison operator /// \brief matrix comparison operator
/// \param lhs the first matrix /// \param lhs the first matrix
/// \param rhs the second matrix /// \param rhs the second matrix
/// \returns a boolean value that contains \f$true\f$ when all components of `lhs` and `rhs` are equal and \f$false\f$ otherwise /// \returns a boolean value that contains \f$true\f$ when all components of \f$lhs\f$ and \f$rhs\f$ are equal and \f$false\f$ otherwise
constexpr friend bool operator==(const matrix_t& lhs, const matrix_t& rhs) { constexpr friend bool operator==(const matrix_t& lhs, const matrix_t& rhs) {
return lhs.data == rhs.data; return lhs.data == rhs.data;
} }
@@ -636,7 +636,7 @@ struct matrix
/// \brief matrix comparison operator /// \brief matrix comparison operator
/// \param lhs the first matrix /// \param lhs the first matrix
/// \param rhs the second matrix /// \param rhs the second matrix
/// \returns a boolean value that contains \f$true\f$ when all components of `lhs` and `rhs` are not equal and \f$false\f$ otherwise /// \returns a boolean value that contains \f$true\f$ when all components of \f$lhs\f$ and \f$rhs\f$ are not equal and \f$false\f$ otherwise
constexpr friend bool operator!=(const matrix_t& lhs, const matrix_t& rhs) { constexpr friend bool operator!=(const matrix_t& lhs, const matrix_t& rhs) {
return lhs.data != rhs.data; return lhs.data != rhs.data;
} }

View File

@@ -23,26 +23,26 @@
namespace fennec::detail namespace fennec::detail
{ {
// ///
// \brief Backing storage struct for \ref fennec::swizzle "swizzle" /// \brief Backing storage struct for \ref fennec::swizzle "swizzle"
// \tparam DataT Data Type /// \tparam DataT Data Type
// \tparam ScalarT Element Types /// \tparam ScalarT Element Types
// \tparam IndicesV Swizzle Order /// \tparam IndicesV Swizzle Order
template<typename DataT, typename ScalarT, size_t...IndicesV> template<typename DataT, typename ScalarT, size_t...IndicesV>
struct swizzle_storage struct swizzle_storage
{ {
// ///
// \brief an array containing the indices of this swizzle /// \brief an array containing the indices of this swizzle
inline static constexpr size_t indices[] = { IndicesV... }; inline static constexpr size_t indices[] = { IndicesV... };
// ///
// \brief an array containing the scalar values of this swizzle /// \brief an array containing the scalar values of this swizzle
DataT data; DataT data;
// ///
// \brief element access, returns a copy of the value at index \p i /// \brief element access, returns a copy of the value at index \p i
// \param i the index /// \param i the index
// \returns a copy of the scalar value at index \p i /// \returns a copy of the scalar value at index \p i
constexpr ScalarT operator[](size_t i) const noexcept { constexpr ScalarT operator[](size_t i) const noexcept {
return data[indices[i]]; return data[indices[i]];
} }

View File

@@ -46,33 +46,33 @@
/// <table width="100%" class="fieldtable" id="table_fennec_math_vector_types"> /// <table width="100%" class="fieldtable" id="table_fennec_math_vector_types">
/// <tr><th>Type <th>Corresponding Type <th>Brief /// <tr><th>Type <th>Corresponding Type <th>Brief
/// <tr><th colspan=3 style="text-align: center;">Floats /// <tr><th colspan=3 style="text-align: center;">Floats
/// <tr><td>```vec2``` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2 /// <tr><td>``\f$vec2\f$`` <td>\ref fennec::vec2 <td>\copybrief fennec::vec2
/// <tr><td>```vec3``` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3 /// <tr><td>``\f$vec3\f$`` <td>\ref fennec::vec3 <td>\copybrief fennec::vec3
/// <tr><td>```vec4``` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4 /// <tr><td>``\f$vec4\f$`` <td>\ref fennec::vec4 <td>\copybrief fennec::vec4
/// <tr><th colspan=3 style="text-align: center;">Doubles /// <tr><th colspan=3 style="text-align: center;">Doubles
/// <tr><td>```dvec2```<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2 /// <tr><td>``\f$dvec2\f$``<td>\ref fennec::dvec2 <td>\copybrief fennec::dvec2
/// <tr><td>```dvec3```<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3 /// <tr><td>``\f$dvec3\f$``<td>\ref fennec::dvec3 <td>\copybrief fennec::dvec3
/// <tr><td>```dvec4```<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4 /// <tr><td>``\f$dvec4\f$``<td>\ref fennec::dvec4 <td>\copybrief fennec::dvec4
/// <tr><th colspan=3 style="text-align: center;">Booleans /// <tr><th colspan=3 style="text-align: center;">Booleans
/// <tr><td>```bvec2``` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2 /// <tr><td>``\f$bvec2\f$`` <td>\ref fennec::bvec2 <td>\copybrief fennec::bvec2
/// <tr><td>```bvec3``` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3 /// <tr><td>``\f$bvec3\f$`` <td>\ref fennec::bvec3 <td>\copybrief fennec::bvec3
/// <tr><td>```bvec4``` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4 /// <tr><td>``\f$bvec4\f$`` <td>\ref fennec::bvec4 <td>\copybrief fennec::bvec4
/// <tr><th colspan=3 style="text-align: center;">Integers /// <tr><th colspan=3 style="text-align: center;">Integers
/// <tr><td>```ivec2``` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2 /// <tr><td>``\f$ivec2\f$`` <td>\ref fennec::ivec2 <td>\copybrief fennec::ivec2
/// <tr><td>```ivec3``` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3 /// <tr><td>``\f$ivec3\f$`` <td>\ref fennec::ivec3 <td>\copybrief fennec::ivec3
/// <tr><td>```ivec4``` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4 /// <tr><td>``\f$ivec4\f$`` <td>\ref fennec::ivec4 <td>\copybrief fennec::ivec4
/// <tr><th colspan=3 style="text-align: center;">Unsigned Integers /// <tr><th colspan=3 style="text-align: center;">Unsigned Integers
/// <tr><td>```uvec2``` <td>\ref fennec::uvec2 <td>\copybrief fennec::uvec2 /// <tr><td>``\f$uvec2\f$`` <td>\ref fennec::uvec2 <td>\copybrief fennec::uvec2
/// <tr><td>```uvec3``` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3 /// <tr><td>``\f$uvec3\f$`` <td>\ref fennec::uvec3 <td>\copybrief fennec::uvec3
/// <tr><td>```uvec4``` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4 /// <tr><td>``\f$uvec4\f$`` <td>\ref fennec::uvec4 <td>\copybrief fennec::uvec4
/// </table> /// </table>
/// ///
/// ///
/// ///
/// \section vector_components Components /// \section vector_components Components
/// ///
/// Vectors are usually made up of one to four components, named ```x```, ```y```, ```z```, and ```w```. /// Vectors are usually made up of one to four components, named ``\f$x\f$``, ``\f$y\f$``, ``\f$z\f$``, and ``\f$w\f$``.
/// Each component also has aliases for usage in colors ```rgba```, and texture coordinates ```stpq```. Accessing a /// Each component also has aliases for usage in colors ``\f$rgba\f$``, and texture coordinates ``\f$stpq\f$``. Accessing a
/// component outside the vector will cause an error at compile time, for example: /// component outside the vector will cause an error at compile time, for example:
/// ///
/// \code{.cpp} /// \code{.cpp}

View File

@@ -30,54 +30,55 @@
namespace fennec::detail namespace fennec::detail
{ {
// ///
// \brief helper class for generating vectors /// \brief helper class for generating vectors
// \tparam scalar base scalar type /// \tparam scalar base scalar type
// \tparam size size of the vector type /// \tparam size size of the vector type
template<typename scalar, size_t size> template<typename scalar, size_t size>
struct vector_base_type_helper struct vector_base_type_helper
{ {
// ///
// \var SizeV /// \var SizeV
// \brief size of the vector type /// \brief size of the vector type
inline static constexpr size_t SizeV = size; inline static constexpr size_t SizeV = size;
// ///
// \brief Base scalar type /// \brief Base scalar type
using ScalarT = scalar; using ScalarT = scalar;
// ///
// \brief Base vector type /// \brief Base vector type
using VectorT = vec<ScalarT, SizeV>; using VectorT = vec<ScalarT, SizeV>;
// ///
// \brief Backing array holding the elements /// \brief Backing array holding the elements
using DataT = array<ScalarT, SizeV>; using DataT = array<ScalarT, SizeV>;
// ///
// \brief Helper for generating a swizzle from a set of indices /// \brief Helper for generating a swizzle from a set of indices
// \tparam IndicesV Indices of the vector to pull from /// \tparam IndicesV Indices of the vector to pull from
template<size_t...IndicesV> struct SwizzleGen template<size_t...IndicesV> struct SwizzleGen
{ {
// \brief generated swizzle type // \brief generated swizzle type
using type = swizzle<VectorT, DataT, ScalarT, IndicesV...>; using type = swizzle<VectorT, DataT, ScalarT, IndicesV...>;
}; };
// Specialization for single component swizzles to decay into a scalar ///
/// \tparam IndicesV Indices of the vector to pull from
template<size_t IndexV> struct SwizzleGen<IndexV> template<size_t IndexV> struct SwizzleGen<IndexV>
{ {
// \brief decayed scalar type // \brief decayed scalar type
using type = ScalarT; using type = ScalarT;
}; };
// ///
// \brief backing storage type /// \brief backing storage type
using StorageT = vector_storage<SizeV, SwizzleGen, DataT>; using StorageT = vector_storage<SizeV, SwizzleGen, DataT>;
}; };
// ///
// \brief helper for getting the storage type of the vector constructed with the provided size and scalar type /// \brief helper for getting the storage type of the vector constructed with the provided size and scalar type
template<typename ScalarT, size_t SizeV> template<typename ScalarT, size_t SizeV>
using vector_base_type = typename vector_base_type_helper<ScalarT, SizeV>::StorageT; using vector_base_type = typename vector_base_type_helper<ScalarT, SizeV>::StorageT;

View File

@@ -33,15 +33,16 @@
namespace fennec::detail namespace fennec::detail
{ {
// ///
// \brief backing storage type for vectors /// \brief backing storage type for vectors
// \tparam SizeV size of the vector /// \tparam SizeV size of the vector
// \tparam SwizzleGenT generator for swizzles /// \tparam SwizzleGenT generator for swizzles
// \tparam DataT backing data type /// \tparam DataT backing data type
template<size_t SizeV, template<size_t...> class SwizzleGenT, typename DataT> struct vector_storage; template<size_t SizeV, template<size_t...> class SwizzleGenT, typename DataT> struct vector_storage;
///
// specialization for single component vectors /// \tparam SwizzleGenT generator for swizzles
/// \tparam DataT backing data type
template <template <size_t...> class SwizzleGenT, typename DataT> template <template <size_t...> class SwizzleGenT, typename DataT>
struct vector_storage<1, SwizzleGenT, DataT> struct vector_storage<1, SwizzleGenT, DataT>
{ {
@@ -65,7 +66,9 @@ namespace fennec::detail
}; };
// specialization for two component vectors ///
/// \tparam SwizzleGenT generator for swizzles
/// \tparam DataT backing data type
template <template <size_t...> class SwizzleGenT, typename DataT> template <template <size_t...> class SwizzleGenT, typename DataT>
struct vector_storage<2, SwizzleGenT, DataT> struct vector_storage<2, SwizzleGenT, DataT>
{ {
@@ -114,7 +117,9 @@ namespace fennec::detail
}; };
// specialization for three component vectors ///
/// \tparam SwizzleGenT generator for swizzles
/// \tparam DataT backing data type
template <template <size_t...> class SwizzleGenT, typename DataT> template <template <size_t...> class SwizzleGenT, typename DataT>
struct vector_storage<3, SwizzleGenT, DataT> struct vector_storage<3, SwizzleGenT, DataT>
{ {
@@ -250,7 +255,9 @@ namespace fennec::detail
}; };
// specialization for four component vectors ///
/// \tparam SwizzleGenT generator for swizzles
/// \tparam DataT backing data type
template <template <size_t...> class SwizzleGenT, typename DataT> template <template <size_t...> class SwizzleGenT, typename DataT>
struct vector_storage<4, SwizzleGenT, DataT> struct vector_storage<4, SwizzleGenT, DataT>
{ {

View File

@@ -130,7 +130,7 @@ public:
/// \brief Checks if this allocator type is always equal to another allocator of similar type /// \brief Checks if this allocator type is always equal to another allocator of similar type
using is_always_equal = detect_t<false_type, _is_always_equal, Alloc>; using is_always_equal = detect_t<false_type, _is_always_equal, Alloc>;
/// \brief Rebinds the allocator type to produce an element type of type `TypeT` /// \brief Rebinds the allocator type to produce an element type of type \f$TypeT\f$
template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type; template<typename TypeT> using rebind = typename _rebind<Alloc, TypeT>::type;
// TODO: allocator_traits static functions // TODO: allocator_traits static functions
@@ -138,7 +138,7 @@ public:
/// ///
/// \brief Allocator implementation, uses `new` and `delete` operators. /// \brief Allocator implementation, uses \f$new\f$ and \f$delete\f$ operators.
/// \tparam T The data type to allocate /// \tparam T The data type to allocate
template<typename T> template<typename T>
class allocator class allocator
@@ -171,34 +171,34 @@ public:
/// ///
/// \brief Equality operator /// \brief Equality operator
/// \returns `true` /// \returns \f$true\f$
constexpr bool_t operator==(const allocator&) { constexpr bool_t operator==(const allocator&) {
return true; return true;
} }
/// ///
/// \brief Inequality operator /// \brief Inequality operator
/// \returns `false` /// \returns \f$false\f$
constexpr bool_t operator!=(const allocator&) { constexpr bool_t operator!=(const allocator&) {
return false; return false;
} }
/// ///
/// \brief Equality operator for allocators of same type but with different data type /// \brief Equality operator for allocators of same type but with different data type
/// \returns `false` /// \returns \f$false\f$
template<typename U> constexpr bool_t operator==(const allocator<U>&) { template<typename U> constexpr bool_t operator==(const allocator<U>&) {
return false; return false;
} }
/// ///
/// \brief Inequality operator for allocators of same type but with different data type /// \brief Inequality operator for allocators of same type but with different data type
/// \returns `true` /// \returns \f$true\f$
template<typename U> constexpr bool_t operator!=(const allocator<U>&) { template<typename U> constexpr bool_t operator!=(const allocator<U>&) {
return true; return true;
} }
/// ///
/// \brief Allocate a block of memory large enough to hold `n` elements of type `T` /// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$
/// \param n The number of elements /// \param n The number of elements
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
constexpr T* allocate(size_t n) { constexpr T* allocate(size_t n) {
@@ -206,7 +206,7 @@ public:
} }
/// ///
/// \brief Allocate a block of memory large enough to hold `n` elements of type `T` /// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$
/// \param n The number of elements /// \param n The number of elements
/// \param align The alignment /// \param align The alignment
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
@@ -215,14 +215,14 @@ public:
} }
/// ///
/// \brief Deallocate a block of memory with type `T` /// \brief Deallocate a block of memory with type \f$T\f$
/// \param ptr The block to release /// \param ptr The block to release
constexpr void deallocate(T* ptr) { constexpr void deallocate(T* ptr) {
return ::operator delete(ptr); return ::operator delete(ptr);
} }
/// ///
/// \brief Deallocate a block of memory with type `T` /// \brief Deallocate a block of memory with type \f$T\f$
/// \param ptr The block to release /// \param ptr The block to release
/// \param align The alignment /// \param align The alignment
constexpr void deallocate(T* ptr, align_t align) { constexpr void deallocate(T* ptr, align_t align) {
@@ -232,7 +232,7 @@ public:
/// ///
/// \brief Allocator implementation, uses `new` and `delete` operators. /// \brief Allocator implementation, uses \f$new\f$ and \f$delete\f$ operators.
/// \tparam T The data type to allocate /// \tparam T The data type to allocate
template<typename T> template<typename T>
class allocator<T[]> class allocator<T[]>
@@ -266,34 +266,34 @@ public:
/// ///
/// \brief Equality operator /// \brief Equality operator
/// \returns `true` /// \returns \f$true\f$
constexpr bool_t operator==(const allocator&) { constexpr bool_t operator==(const allocator&) {
return true; return true;
} }
/// ///
/// \brief Inequality operator /// \brief Inequality operator
/// \returns `false` /// \returns \f$false\f$
constexpr bool_t operator!=(const allocator&) { constexpr bool_t operator!=(const allocator&) {
return false; return false;
} }
/// ///
/// \brief Equality operator for allocators of same type but with different data type /// \brief Equality operator for allocators of same type but with different data type
/// \returns `false` /// \returns \f$false\f$
template<typename U> constexpr bool_t operator==(const allocator<U>&) { template<typename U> constexpr bool_t operator==(const allocator<U>&) {
return false; return false;
} }
/// ///
/// \brief Inequality operator for allocators of same type but with different data type /// \brief Inequality operator for allocators of same type but with different data type
/// \returns `true` /// \returns \f$true\f$
template<typename U> constexpr bool_t operator!=(const allocator<U>&) { template<typename U> constexpr bool_t operator!=(const allocator<U>&) {
return true; return true;
} }
/// ///
/// \brief Allocate a block of memory large enough to hold `n` elements of type `T` /// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$
/// \param n The number of elements /// \param n The number of elements
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
constexpr T* allocate(size_t n) { constexpr T* allocate(size_t n) {
@@ -301,7 +301,7 @@ public:
} }
/// ///
/// \brief Allocate a block of memory large enough to hold `n` elements of type `T` /// \brief Allocate a block of memory large enough to hold \f$n\f$ elements of type \f$T\f$
/// \param n The number of elements /// \param n The number of elements
/// \param align The alignment /// \param align The alignment
/// \returns A pointer to the allocated block /// \returns A pointer to the allocated block
@@ -310,14 +310,14 @@ public:
} }
/// ///
/// \brief Deallocate a block of memory with type `T` /// \brief Deallocate a block of memory with type \f$T\f$
/// \param ptr The block to release /// \param ptr The block to release
constexpr void deallocate(T* ptr) { constexpr void deallocate(T* ptr) {
return ::operator delete[](ptr); return ::operator delete[](ptr);
} }
/// ///
/// \brief Deallocate a block of memory with type `T` /// \brief Deallocate a block of memory with type \f$T\f$
/// \param ptr The block to release /// \param ptr The block to release
/// \param align The alignment /// \param align The alignment
constexpr void deallocate(T* ptr, align_t align) { constexpr void deallocate(T* ptr, align_t align) {
@@ -353,14 +353,14 @@ public:
// Cosntructors ======================================================================================================== // Cosntructors ========================================================================================================
/// ///
/// \brief Default Constructor, initializes internal data to `null` and the capacity to `0` /// \brief Default Constructor, initializes internal data to \f$null\f$ and the capacity to \f$0\f$
constexpr allocation() noexcept constexpr allocation() noexcept
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) { : _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
} }
/// ///
/// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes /// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes
/// \param n The number of elements of type `T` to allocate for /// \param n The number of elements of type \f$T\f$ to allocate for
explicit constexpr allocation(size_t n) noexcept explicit constexpr allocation(size_t n) noexcept
: _data(nullptr), _capacity(0), _alignment(zero<align_t>()) { : _data(nullptr), _capacity(0), _alignment(zero<align_t>()) {
callocate(n); callocate(n);
@@ -378,7 +378,7 @@ public:
/// ///
/// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes /// \brief Sized Constructor, initializes the allocation with a block of size `n * sizeof(T)` bytes
/// \param n The number of elements of type `T` to allocate for /// \param n The number of elements of type \f$T\f$ to allocate for
/// \param align The alignment of the allocation /// \param align The alignment of the allocation
constexpr allocation(size_t n, align_t align) noexcept constexpr allocation(size_t n, align_t align) noexcept
: _data(nullptr) : _data(nullptr)
@@ -402,7 +402,7 @@ public:
/// \brief Allocator Constructor /// \brief Allocator Constructor
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type `AllocT` needs internal data. /// \details This constructor should be used when the type \f$AllocT\f$ needs internal data.
explicit constexpr allocation(const alloc_t& alloc) noexcept explicit constexpr allocation(const alloc_t& alloc) noexcept
: _alloc(alloc) : _alloc(alloc)
, _data(nullptr) , _data(nullptr)
@@ -412,10 +412,10 @@ public:
/// ///
/// \brief Sized Allocator Constructor /// \brief Sized Allocator Constructor
/// \param n The number of elements of type `T` to allocate for /// \param n The number of elements of type \f$T\f$ to allocate for
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type `AllocT` needs internal data. /// \details This constructor should be used when the type \f$AllocT\f$ needs internal data.
constexpr allocation(size_t n, const alloc_t& alloc) noexcept constexpr allocation(size_t n, const alloc_t& alloc) noexcept
: _alloc(alloc) : _alloc(alloc)
, _data(nullptr) , _data(nullptr)
@@ -431,7 +431,7 @@ public:
/// \param n the number of elements /// \param n the number of elements
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type `AllocT` needs internal data. /// \details This constructor should be used when the type \f$AllocT\f$ needs internal data.
constexpr allocation(const T* data, size_t n, const alloc_t& alloc) constexpr allocation(const T* data, size_t n, const alloc_t& alloc)
: allocation(n, alloc) { : allocation(n, alloc) {
fennec::memmove(static_cast<void*>(_data), data, n); fennec::memmove(static_cast<void*>(_data), data, n);
@@ -439,11 +439,11 @@ public:
/// ///
/// \brief Sized Allocator Constructor /// \brief Sized Allocator Constructor
/// \param n The number of elements of type `T` to allocate for /// \param n The number of elements of type \f$T\f$ to allocate for
/// \param align The alignment of the allocation /// \param align The alignment of the allocation
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type `AllocT` needs internal data. /// \details This constructor should be used when the type \f$AllocT\f$ needs internal data.
constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept constexpr allocation(size_t n, align_t align, const alloc_t& alloc) noexcept
: _alloc(alloc) : _alloc(alloc)
, _data(nullptr) , _data(nullptr)
@@ -460,7 +460,7 @@ public:
/// \param align The alignment of the allocation /// \param align The alignment of the allocation
/// \param alloc The allocation object to copy. /// \param alloc The allocation object to copy.
/// ///
/// \details This constructor should be used when the type `AllocT` needs internal data. /// \details This constructor should be used when the type \f$AllocT\f$ needs internal data.
constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc) constexpr allocation(const T* data, size_t n, align_t align, const alloc_t& alloc)
: allocation(n, align, alloc) { : allocation(n, align, alloc) {
fennec::memmove(_data, data, n); fennec::memmove(_data, data, n);
@@ -478,7 +478,7 @@ public:
} }
/// ///
/// \brief Move Constructor, moves the data in `alloc` to the new object and cleans `alloc` so that it /// \brief Move Constructor, moves the data in \f$alloc\f$ to the new object and cleans \f$alloc\f$ so that it
/// can safely destruct /// can safely destruct
/// \param alloc The allocation to move /// \param alloc The allocation to move
constexpr allocation(allocation&& alloc) noexcept constexpr allocation(allocation&& alloc) noexcept
@@ -505,7 +505,7 @@ public:
/// ///
/// \brief Copy Assignment Operator /// \brief Copy Assignment Operator
/// \param alloc the allocation to copy /// \param alloc the allocation to copy
/// \returns a reference to `this` /// \returns a reference to \f$this\f$
constexpr allocation& operator=(const allocation& alloc) { constexpr allocation& operator=(const allocation& alloc) {
allocation::allocate(alloc.capacity(), alloc.alignment()); allocation::allocate(alloc.capacity(), alloc.alignment());
fennec::memmove(_data, alloc, size()); fennec::memmove(_data, alloc, size());
@@ -515,7 +515,7 @@ public:
/// ///
/// \brief Move Assignment Operator /// \brief Move Assignment Operator
/// \param alloc the allocation to copy /// \param alloc the allocation to copy
/// \returns a reference to `this` /// \returns a reference to \f$this\f$
constexpr allocation& operator=(allocation&& alloc) noexcept { constexpr allocation& operator=(allocation&& alloc) noexcept {
// Copy contents // Copy contents
@@ -534,7 +534,7 @@ public:
/// \brief Allocate a block of memory for the allocation. /// \brief Allocate a block of memory for the allocation.
/// 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 \f$T\f$ to allocate for
/// \param align The alignment to use /// \param align The alignment to use
constexpr void allocate(size_t n, align_t align = zero<align_t>()) noexcept { constexpr void allocate(size_t n, align_t align = zero<align_t>()) noexcept {
deallocate(); deallocate();
@@ -550,7 +550,7 @@ public:
/// \brief Allocate a block of memory for the allocation. /// \brief Allocate a block of memory for the allocation.
/// 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 \f$T\f$ to allocate for
/// \param align The alignment to use /// \param align The alignment to use
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 {
allocate(n, align); allocate(n, align);
@@ -577,7 +577,7 @@ public:
/// \brief Reallocate the block with a new size. /// \brief Reallocate the block with a new size.
/// Contents are copied to the new allocation. /// Contents are copied to the new allocation.
/// ///
/// \param n The number of elements of type `T` to allocate for /// \param n The number of elements of type \f$T\f$ to allocate for
/// \param align The alignment to use /// \param align The alignment to use
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) {
@@ -599,7 +599,7 @@ public:
/// \brief Reallocate the block with a new size. /// \brief Reallocate the block with a new size.
/// Contents are copied to the new allocation. /// Contents are copied to the new allocation.
/// ///
/// \param n The number of elements of type `T` to allocate for /// \param n The number of elements of type \f$T\f$ to allocate for
/// \param align The alignment to use /// \param align The alignment to use
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) {
@@ -626,7 +626,7 @@ public:
/// ///
/// \param i The index to access /// \param i The index to access
/// \returns a reference to the value at position `i` in the allocation /// \returns a reference to the value at position \f$i\f$ in the allocation
constexpr value_t& operator[](size_t i) { constexpr value_t& operator[](size_t i) {
assertd(i < capacity(), "Array Out of Bounds"); assertd(i < capacity(), "Array Out of Bounds");
return _data[i]; return _data[i];
@@ -635,7 +635,7 @@ public:
/// ///
/// \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 value at position `i` in the allocation /// \returns a reference to the value at position \f$i\f$ in the allocation
constexpr const value_t& operator[](size_t i) const { 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];
@@ -697,7 +697,7 @@ public:
} }
/// ///
/// \brief Getter for the number of elements `n` of type `T` that the allocation can hold. /// \brief Getter for the number of elements \f$n\f$ of type \f$T\f$ that the allocation can hold.
/// \returns the size of the allocation in elements /// \returns the size of the allocation in elements
constexpr size_t capacity() const { constexpr size_t capacity() const {
return _capacity; return _capacity;

View File

@@ -89,7 +89,7 @@ public:
/// ///
/// \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 byte at `i` /// \returns a reference to the byte at \f$i\f$
constexpr byte_t& operator[](int i) { constexpr byte_t& operator[](int i) {
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
assertd(i >= 0 && (size_t)i < _size, "Array Out of Bounds"); assertd(i >= 0 && (size_t)i < _size, "Array Out of Bounds");
@@ -99,7 +99,7 @@ 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 byte at `i` /// \returns a copy of the byte at \f$i\f$
constexpr byte_t operator[](int i) const { constexpr byte_t operator[](int i) const {
assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const"); assertd(not _const, "Attempted to Access Const-Qualified Memory as Non-Const");
assertd(i >= 0 && (size_t)i < _size, "Array Out of Bounds"); assertd(i >= 0 && (size_t)i < _size, "Array Out of Bounds");
@@ -109,7 +109,7 @@ public:
/// ///
/// \brief Cast Function /// \brief Cast Function
/// \tparam T type to cast to /// \tparam T type to cast to
/// \returns a pointer to the underlying buffer interpreted as an array of `T` /// \returns a pointer to the underlying buffer interpreted as an array of \f$T\f$
template<typename T> template<typename T>
constexpr T* cast() { constexpr T* cast() {
void* temp = _arr; void* temp = _arr;
@@ -119,7 +119,7 @@ public:
/// ///
/// \brief Const Cast Function /// \brief Const Cast Function
/// \tparam T type to cast to /// \tparam T type to cast to
/// \returns a pointer to the underlying buffer interpreted as an array of `T` /// \returns a pointer to the underlying buffer interpreted as an array of \f$T\f$
template<typename T> template<typename T>
constexpr const T* cast() const { constexpr const T* cast() const {
const void* temp = _carr; const void* temp = _carr;

View File

@@ -26,7 +26,7 @@ namespace fennec
{ {
/// ///
/// \brief Struct for wrapping C++ `delete` /// \brief Struct for wrapping C++ \f$delete\f$
/// \tparam TypeT The type of the buffer to be deleted /// \tparam TypeT The type of the buffer to be deleted
template<typename TypeT> template<typename TypeT>
struct default_delete struct default_delete
@@ -42,7 +42,7 @@ struct default_delete
constexpr default_delete(const default_delete<ConvT>&) noexcept {} constexpr default_delete(const default_delete<ConvT>&) noexcept {}
/// ///
/// \brief Function Call Operator, calls `delete` on `ptr` /// \brief Function Call Operator, calls \f$delete\f$ on \f$ptr\f$
/// \param ptr Memory resource to delete /// \param ptr Memory resource to delete
constexpr void operator()(TypeT* ptr) const noexcept { constexpr void operator()(TypeT* ptr) const noexcept {
static_assert(not is_void_v<TypeT>, "cannot delete a pointer to an incomplete type"); static_assert(not is_void_v<TypeT>, "cannot delete a pointer to an incomplete type");
@@ -51,7 +51,8 @@ struct default_delete
} }
}; };
// Overload for Arrays ///
/// \tparam TypeT The type of the buffer to be deleted
template<typename TypeT> template<typename TypeT>
struct default_delete<TypeT[]> struct default_delete<TypeT[]>
{ {
@@ -66,7 +67,7 @@ struct default_delete<TypeT[]>
constexpr default_delete(const default_delete<ConvT(*)[]>&) noexcept {} constexpr default_delete(const default_delete<ConvT(*)[]>&) noexcept {}
/// ///
/// \brief Function Call Operator, calls `delete` on `ptr` /// \brief Function Call Operator, calls \f$delete\f$ on \f$ptr\f$
/// \param ptr Memory resource to delete /// \param ptr Memory resource to delete
template<class ArrT> requires requires { is_convertible_v<ArrT(*)[], TypeT(*)[]> == true; } template<class ArrT> requires requires { is_convertible_v<ArrT(*)[], TypeT(*)[]> == true; }
constexpr void operator()(TypeT* ptr) const noexcept { constexpr void operator()(TypeT* ptr) const noexcept {
@@ -107,7 +108,7 @@ public:
constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr, delete_t()) {} constexpr unique_ptr(nullptr_t) noexcept : unique_ptr(nullptr, delete_t()) {}
/// ///
/// \brief Pointer Constructor, creates a unique_ptr that owns `ptr` with deleter `del` /// \brief Pointer Constructor, creates a unique_ptr that owns \f$ptr\f$ with deleter \f$del\f$
/// \param ptr The resource to own /// \param ptr The resource to own
/// \param del The deleter /// \param del The deleter
explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del = delete_t()) explicit constexpr unique_ptr(pointer_t ptr, const delete_t& del = delete_t())
@@ -116,7 +117,7 @@ public:
} }
/// ///
/// \brief Move Constructor, transfers ownership from `other` /// \brief Move Constructor, transfers ownership from \f$other\f$
/// \param other The unique_ptr to take ownership from /// \param other The unique_ptr to take ownership from
constexpr unique_ptr(unique_ptr&& other) constexpr unique_ptr(unique_ptr&& other)
: _handle(other._handle) { : _handle(other._handle) {
@@ -161,7 +162,7 @@ public:
return retval; return retval;
} }
pointer_t get() { pointer_t get() const {
return _handle; return _handle;
} }
@@ -188,11 +189,11 @@ private:
}; };
/// ///
/// \brief Creates a unique pointer holding an object of type `TypeT` /// \brief Creates a unique pointer holding an object of type \f$TypeT\f$
/// \tparam TypeT The type /// \tparam TypeT The type
/// \tparam ArgsT The constructor arguments, automatically deduced /// \tparam ArgsT The constructor arguments, automatically deduced
/// \param args The constructor arguments /// \param args The constructor arguments
/// \returns A unique pointer holding a heap allocated object of type `TypeT` constructed with arguments `args` /// \returns A unique pointer holding a heap allocated object of type \f$TypeT\f$ constructed with arguments \f$args\f$
template<typename TypeT, typename...ArgsT> template<typename TypeT, typename...ArgsT>
unique_ptr<TypeT> make_unique(ArgsT&&...args) { unique_ptr<TypeT> make_unique(ArgsT&&...args) {
return unique_ptr<TypeT>(new TypeT(fennec::forward<ArgsT>(args)...)); return unique_ptr<TypeT>(new TypeT(fennec::forward<ArgsT>(args)...));

View File

@@ -51,9 +51,9 @@ class display_server;
/// ///
/// \details An implementation for a display server should inherit `display_server_base` and note the following: /// \details An implementation for a display server should inherit `display_server_base` and note the following:
/// ///
/// For a server type `DisplayT`; any `gfxcontext` implementation that wishes to implement `DisplayT` /// For a server type \f$DisplayT\f$; any \f$gfxcontext\f$ implementation that wishes to implement \f$DisplayT\f$
/// must provide a constructor that accepts a `DisplayT*`. `DisplayT::ctx_registry::register_type` must then be /// must provide a constructor that accepts a `DisplayT*`. `DisplayT::ctx_registry::register_type` must then be
/// called for the `gfxcontext` implementation. /// called for the \f$gfxcontext\f$ implementation.
class display_server : public type_registry<display_server, platform*> { class display_server : public type_registry<display_server, platform*> {
// Typedefs/Constants/Enums ============================================================================================ // Typedefs/Constants/Enums ============================================================================================
public: public:
@@ -134,6 +134,8 @@ protected:
} }
}; };
///
/// \brief Interface resembling the API for a display server of an operating system, e.g. Linux X11/Wayland
template<typename DisplayT, typename WindowT> template<typename DisplayT, typename WindowT>
class display_server_base : public display_server, public type_registry<gfxcontext, DisplayT*> { class display_server_base : public display_server, public type_registry<gfxcontext, DisplayT*> {
public: public:

View File

@@ -41,7 +41,7 @@ struct singleton {
return instance; return instance;
} }
static T& instance() requires(is_default_constructible_v<T> and not is_pointer_v<T>) { static T& instance() requires(not is_pointer_v<T>) {
static T instance; static T instance;
return instance; return instance;
} }

View File

@@ -65,25 +65,25 @@ struct type {
} }
/// ///
/// \returns `true` if this is a complete type, false otherwise /// \returns \f$true\f$ if this is a complete type, false otherwise
bool is_complete() const { bool is_complete() const {
return _data ? _data->properties.test(type_data::property_complete) : false; return _data ? _data->properties.test(type_data::property_complete) : false;
} }
/// ///
/// \returns `true` if this type fulfills the [C++11 range-initializer](https://en.cppreference.com/w/cpp/language/range-for.html), false otherwise /// \returns \f$true\f$ if this type fulfills the [C++11 range-initializer](https://en.cppreference.com/w/cpp/language/range-for.html), false otherwise
bool is_iterable() const { bool is_iterable() const {
return _data ? _data->properties.test(type_data::property_iterable) : false; return _data ? _data->properties.test(type_data::property_iterable) : false;
} }
/// ///
/// \returns `true` if this type implements `operator[]` with a single parameter of integral type, false otherwise /// \returns \f$true\f$ if this type implements `operator[]` with a single parameter of integral type, false otherwise
bool is_indexable() const { bool is_indexable() const {
return _data ? _data->properties.test(type_data::property_indexable) : false; return _data ? _data->properties.test(type_data::property_indexable) : false;
} }
/// ///
/// \returns `true` if this type implements `operator[]` with a single parameter of type `type::key_t` /// \returns \f$true\f$ if this type implements `operator[]` with a single parameter of type `type::key_t`
bool is_mappable() const { bool is_mappable() const {
return _data ? _data->properties.test(type_data::property_mappable) : false; return _data ? _data->properties.test(type_data::property_mappable) : false;
} }

View File

@@ -26,11 +26,15 @@
namespace fennec namespace fennec
{ {
///
/// \brief Base Component Functionality
class component { class component {
public: public:
// MEMBERS ============================================================================================================= // MEMBERS =============================================================================================================
public: public:
///
/// \brief reference to the
scene_node* const node; scene_node* const node;
component(scene_node* node) component(scene_node* node)

View File

@@ -20,6 +20,7 @@
#define FENNEC_SCENE_SCENE_H #define FENNEC_SCENE_SCENE_H
#include <fennec/containers/rdtree.h> #include <fennec/containers/rdtree.h>
#include <fennec/memory/pointers.h>
#include <fennec/string/string.h> #include <fennec/string/string.h>
#include <fennec/scene/forward.h> #include <fennec/scene/forward.h>
@@ -33,7 +34,13 @@ namespace fennec
/// \details This structure only contains the names of nodes and defers storage for components to /// \details This structure only contains the names of nodes and defers storage for components to
/// their respective systems. Simple components may be isolated, \see components.h for more info. /// their respective systems. Simple components may be isolated, \see components.h for more info.
/// The hierarchy should be displayed using pre-order traversal. /// The hierarchy should be displayed using pre-order traversal.
class scene : private rdtree<scene_node*> { class scene {
// Definitions =========================================================================================================
private:
using elem_t = unique_ptr<scene_node>;
using table_t = rdtree<elem_t>;
// Access ============================================================================================================== // Access ==============================================================================================================
public: public:
@@ -41,17 +48,18 @@ public:
/// \brief Find a node by name. /// \brief Find a node by name.
/// \details If multiple nodes have the same name, finds the first one in pre-order traversal. /// \details If multiple nodes have the same name, finds the first one in pre-order traversal.
/// \param name The name of the node to search for /// \param name The name of the node to search for
/// \returns The id of the node, `npos` if not found. /// \returns The id of the node, \f$npos\f$ if not found.
scene_node* operator[](const cstring& name) const; scene_node* operator[](const cstring& name) const;
/// ///
/// \brief Find a node by name. /// \brief Find a node by name.
/// \details If multiple nodes have the same name, finds the first one in pre-order traversal. /// \details If multiple nodes have the same name, finds the first one in pre-order traversal.
/// \param name The name of the node to search for /// \param name The name of the node to search for
/// \returns The id of the node, `npos` if not found. /// \returns The id of the node, \f$npos\f$ if not found.
scene_node* operator[](const string& name) const; scene_node* operator[](const string& name) const;
private:
table_t _table;
}; };
} }

View File

@@ -283,10 +283,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `c` in the string /// \brief Finds the index of the first occurrence of \f$c\f$ in the string
/// \param c the character to find /// \param c the character 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 \f$c\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(char c, size_t i = 0) const { constexpr size_t find(char c, size_t i = 0) const {
if (i >= _size) { // bounds check if (i >= _size) { // bounds check
return _size; return _size;
@@ -297,10 +297,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of \f$str\f$ in the string.
/// \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 \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(const cstring& str, size_t i = 0) const { constexpr size_t find(const cstring& str, size_t i = 0) const {
if (i + str._size > _size) { // bounds check if (i + str._size > _size) { // bounds check
return _size; return _size;
@@ -311,10 +311,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `c` in the string. /// \brief Finds the index of the last occurrence of \f$c\f$ in the string.
/// \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 \f$c\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(char 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;
@@ -328,10 +328,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `str` in the string. /// \brief Finds the index of the last occurrence of \f$str\f$ in the string.
/// \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 \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(const cstring& str, size_t i = npos) const { constexpr size_t rfind(const cstring& str, size_t i = npos) const {
if (_size == 0) { if (_size == 0) {
return _size; return _size;

View File

@@ -57,7 +57,7 @@ public:
} }
/// ///
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...` /// \brief Sized Constructor, initializes a null-terminated string of size \f$n\f$ with `'c'...`
/// \param n the number of characters /// \param n the number of characters
/// \param c the character to fill with /// \param c the character to fill with
/// ///
@@ -75,7 +75,7 @@ public:
} }
/// ///
/// \brief Sized Alloc Constructor, initializes a null-terminated string of size `n` with `'c'...` /// \brief Sized Alloc Constructor, initializes a null-terminated string of size \f$n\f$ with `'c'...`
/// \param n the number of characters /// \param n the number of characters
/// \param c the character to fill with /// \param c the character to fill with
/// \param alloc The allocator to use /// \param alloc The allocator to use
@@ -187,7 +187,7 @@ public:
} }
/// ///
/// \returns `true` if the string contains no characters, `false` otherwise. /// \returns \f$true\f$ if the string contains no characters, \f$false\f$ otherwise.
constexpr bool empty() const { constexpr bool empty() const {
return size() == 0; return size() == 0;
} }
@@ -238,7 +238,7 @@ public:
/// ///
/// \param str the string to compare against /// \param str the string to compare against
/// \param i An offset to start with in `this` /// \param i An offset to start with in \f$this\f$
/// \param n The number of characters to compare /// \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.
@@ -254,7 +254,7 @@ public:
/// ///
/// \brief String Comparison /// \brief String Comparison
/// \param str the string to compare against /// \param str the string to compare against
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \param n The number of characters to compare /// \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.
@@ -285,17 +285,17 @@ public:
/// ///
/// \brief Check if the string contains a character /// \brief Check if the string contains a character
/// \param c The character to find /// \param c The character to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns `true` if `c` is contained in `this` /// \returns \f$true\f$ if \f$c\f$ is contained in \f$this\f$
constexpr bool contains(char c, size_t i = 0) const { constexpr bool contains(char c, size_t i = 0) const {
return find(c, i) != size(); return find(c, i) != size();
} }
/// ///
/// \brief Finds the index of the first occurrence of `c` in the string /// \brief Finds the index of the first occurrence of \f$c\f$ in the string
/// \param c the character to find /// \param c the character to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$c\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(char c, size_t i = 0) const { constexpr size_t find(char c, size_t i = 0) const {
if (i >= size()) { // bounds check if (i >= size()) { // bounds check
return size(); return size();
@@ -306,10 +306,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(const string& str, size_t i = 0) const { // bounds check constexpr size_t find(const string& str, size_t i = 0) const { // bounds check
if (i >= size()) { // bounds check if (i >= size()) { // bounds check
return size(); return size();
@@ -320,10 +320,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(const cstring& str, size_t i = 0) const { constexpr size_t find(const cstring& str, size_t i = 0) const {
if (i + str.size() > size()) { // bounds check if (i + str.size() > size()) { // bounds check
return size(); return size();
@@ -334,10 +334,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `c` in the string. /// \brief Finds the index of the last occurrence of \f$c\f$ in the string.
/// \param c the string to find /// \param c the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$c\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(char 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();
@@ -352,10 +352,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `str` in the string. /// \brief Finds the index of the last occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(const cstring& str, size_t i = npos) const { constexpr size_t rfind(const cstring& str, size_t i = npos) const {
if (size() == 0) { if (size() == 0) {
return size(); return size();
@@ -373,10 +373,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `str` in the string. /// \brief Finds the index of the last occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(const string& 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();
@@ -395,9 +395,9 @@ public:
/// ///
/// \brief Retrieve a substring of a string /// \brief Retrieve a substring of a string
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \param n the number of characters /// \param n the number of characters
/// \returns A new string containing the range of characters specified by `i` and `n` /// \returns A new string containing the range of characters specified by \f$i\f$ and \f$n\f$
constexpr _string substring(size_t i, size_t n = npos) const { constexpr _string substring(size_t i, size_t n = npos) const {
if (i >= size() || n == 0) { if (i >= size() || n == 0) {
return _string(""); return _string("");
@@ -415,7 +415,7 @@ public:
/// ///
/// \brief String Resize /// \brief String Resize
/// \brief Resizes the underlying allocation to hold `n` characters and a null terminator. /// \brief Resizes the underlying allocation to hold \f$n\f$ characters and a null terminator.
/// \param n The new size of the string /// \param n The new size of the string
constexpr void resize(size_t n) { constexpr void resize(size_t n) {
_str.creallocate(n + 1); _str.creallocate(n + 1);
@@ -425,7 +425,7 @@ public:
/// ///
/// \brief Character Append /// \brief Character Append
/// \param c A character to append /// \param c A character to append
/// \returns A new string containing the previous contents and an additional character `c`. /// \returns A new string containing the previous contents and an additional character \f$c\f$.
constexpr _string operator+(char c) const { constexpr _string operator+(char c) const {
if (_str == nullptr) { if (_str == nullptr) {
return _string(1, c); return _string(1, c);
@@ -440,7 +440,7 @@ public:
/// ///
/// \brief Character Prepend /// \brief Character Prepend
/// \param c A character to append /// \param c A character to append
/// \returns A new string containing the character `c` followed by the previous contents. /// \returns A new string containing the character \f$c\f$ followed by the previous contents.
friend constexpr _string operator+(char c, const _string& str) { friend constexpr _string operator+(char c, const _string& str) {
_string res(str.size() + 1); _string res(str.size() + 1);
res[0] = c; res[0] = c;
@@ -450,7 +450,7 @@ public:
/// ///
/// \param cstr The string to append /// \param cstr The string to append
/// \returns A new string containing the previous contents followed by the contents of `cstr` /// \returns A new string containing the previous contents followed by the contents of \f$cstr\f$
constexpr _string operator+(const cstring& cstr) const { constexpr _string operator+(const cstring& cstr) const {
if (_str == nullptr) { if (_str == nullptr) {
return _string(cstr); return _string(cstr);
@@ -465,7 +465,7 @@ public:
/// ///
/// \brief String Append /// \brief String Append
/// \param str The string to append /// \param str The string to append
/// \returns A new string containing the previous contents followed by the contents of `cstr` /// \returns A new string containing the previous contents followed by the contents of \f$cstr\f$
constexpr _string operator+(const _string& str) const { constexpr _string operator+(const _string& str) const {
if (_str == nullptr) { if (_str == nullptr) {
return _string(str); return _string(str);
@@ -483,7 +483,7 @@ public:
/// ///
/// \brief Character Append Assignment /// \brief Character Append Assignment
/// \param c A character to append /// \param c A character to append
/// \returns `this` string containing an additional character `c`. /// \returns \f$this\f$ string containing an additional character \f$c\f$.
constexpr _string& operator+=(char c) { constexpr _string& operator+=(char c) {
if (_str == nullptr) { if (_str == nullptr) {
_str.callocate(2); _str.callocate(2);
@@ -497,7 +497,7 @@ public:
/// ///
/// \param cstr The string to append /// \param cstr The string to append
/// \returns `this` string expanded to additionally contain `cstr` /// \returns \f$this\f$ string expanded to additionally contain \f$cstr\f$
constexpr _string& operator+=(const cstring& cstr) { constexpr _string& operator+=(const cstring& cstr) {
if (_str == nullptr) { if (_str == nullptr) {
return *this = cstr; return *this = cstr;
@@ -511,7 +511,7 @@ public:
/// ///
/// \brief String Append Assignment /// \brief String Append Assignment
/// \param str The string to append /// \param str The string to append
/// \returns `this` string expanded to additionally contain `str` /// \returns \f$this\f$ string expanded to additionally contain \f$str\f$
constexpr _string& operator+=(const _string& str) { constexpr _string& operator+=(const _string& str) {
if (_str == nullptr) { if (_str == nullptr) {
return *this = str; return *this = str;

View File

@@ -267,10 +267,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `c` in the string /// \brief Finds the index of the first occurrence of \f$c\f$ in the string
/// \param c the character to find /// \param c the character 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 \f$c\f$ 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;
@@ -281,10 +281,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of \f$str\f$ in the string.
/// \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 \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(const wcstring& str, size_t i = 0) const { constexpr size_t find(const wcstring& str, size_t i = 0) const {
if (i + str._size > _size) { // bounds check if (i + str._size > _size) { // bounds check
return _size; return _size;
@@ -295,10 +295,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `c` in the string. /// \brief Finds the index of the last occurrence of \f$c\f$ in the string.
/// \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 \f$c\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(char 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;
@@ -312,10 +312,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `str` in the string. /// \brief Finds the index of the last occurrence of \f$str\f$ in the string.
/// \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 \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(const wcstring& str, size_t i = npos) const { constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
if (_size == 0) { if (_size == 0) {
return _size; return _size;

View File

@@ -60,7 +60,7 @@ public:
} }
/// ///
/// \brief Sized Constructor, initializes a null-terminated string of size `n` with `'c'...` /// \brief Sized Constructor, initializes a null-terminated string of size \f$n\f$ with `'c'...`
/// \param n the number of wchar_tacters /// \param n the number of wchar_tacters
/// \param c the wchar_tacter to fill with /// \param c the wchar_tacter to fill with
/// ///
@@ -78,7 +78,7 @@ public:
} }
/// ///
/// \brief Sized Alloc Constructor, initializes a null-terminated string of size `n` with `'c'...` /// \brief Sized Alloc Constructor, initializes a null-terminated string of size \f$n\f$ with `'c'...`
/// \param n the number of characters /// \param n the number of characters
/// \param c the character to fill with /// \param c the character to fill with
/// \param alloc The allocator to use /// \param alloc The allocator to use
@@ -180,7 +180,7 @@ public:
} }
/// ///
/// \returns `true` if the string contains no characters, `false` otherwise. /// \returns \f$true\f$ if the string contains no characters, \f$false\f$ otherwise.
constexpr bool empty() const { constexpr bool empty() const {
return size() == 0; return size() == 0;
} }
@@ -231,7 +231,7 @@ public:
/// ///
/// \param str the string to compare against /// \param str the string to compare against
/// \param i An offset to start with in `this` /// \param i An offset to start with in \f$this\f$
/// \param n The number of characters to compare /// \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.
@@ -247,7 +247,7 @@ public:
/// ///
/// \brief String Comparison /// \brief String Comparison
/// \param str the string to compare against /// \param str the string to compare against
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \param n The number of characters to compare /// \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.
@@ -278,17 +278,17 @@ public:
/// ///
/// \brief Check if the string contains a character /// \brief Check if the string contains a character
/// \param c The character to find /// \param c The character to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns `true` if `c` is contained in `this` /// \returns \f$true\f$ if \f$c\f$ is contained in \f$this\f$
constexpr bool contains(char c, size_t i = 0) const { constexpr bool contains(char c, size_t i = 0) const {
return find(c, i) != size(); return find(c, i) != size();
} }
/// ///
/// \brief Finds the index of the first occurrence of `c` in the string /// \brief Finds the index of the first occurrence of \f$c\f$ in the string
/// \param c the wchar_tacter to find /// \param c the wchar_tacter to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$c\f$ 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();
@@ -299,10 +299,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ 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();
@@ -313,10 +313,10 @@ public:
} }
/// ///
/// \brief Finds the index of the first occurrence of `str` in the string. /// \brief Finds the index of the first occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t find(const wcstring& str, size_t i = 0) const { constexpr size_t find(const wcstring& str, size_t i = 0) const {
if (i + str.size() > size()) { // bounds check if (i + str.size() > size()) { // bounds check
return size(); return size();
@@ -327,10 +327,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `c` in the string. /// \brief Finds the index of the last occurrence of \f$c\f$ in the string.
/// \param c the string to find /// \param c the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `c` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$c\f$ 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(wchar_t c, size_t i = npos) const {
if (size() == 0) { if (size() == 0) {
return size(); return size();
@@ -345,10 +345,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `str` in the string. /// \brief Finds the index of the last occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(const wcstring& str, size_t i = npos) const { constexpr size_t rfind(const wcstring& str, size_t i = npos) const {
if (size() == 0) { if (size() == 0) {
return size(); return size();
@@ -366,10 +366,10 @@ public:
} }
/// ///
/// \brief Finds the index of the last occurrence of `str` in the string. /// \brief Finds the index of the last occurrence of \f$str\f$ in the string.
/// \param str the string to find /// \param str the string to find
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \returns The index of `str` if it occurs in the string, otherwise returns `size()` /// \returns The index of \f$str\f$ if it occurs in the string, otherwise returns `size()`
constexpr size_t rfind(const string& 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();
@@ -388,9 +388,9 @@ public:
/// ///
/// \brief Retrieve a substring of a string /// \brief Retrieve a substring of a string
/// \param i An offset to start at in `this` /// \param i An offset to start at in \f$this\f$
/// \param n the number of characters /// \param n the number of characters
/// \returns A new string containing the range of characters specified by `i` and `n` /// \returns A new string containing the range of characters specified by \f$i\f$ and \f$n\f$
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("");
@@ -408,7 +408,7 @@ public:
/// ///
/// \brief String Resize /// \brief String Resize
/// \brief Resizes the underlying allocation to hold `n` characters and a null terminator. /// \brief Resizes the underlying allocation to hold \f$n\f$ characters and a null terminator.
/// \param n The new size of the string /// \param n The new size of the string
constexpr void resize(size_t n) { constexpr void resize(size_t n) {
_str.creallocate(n + 1); _str.creallocate(n + 1);
@@ -418,7 +418,7 @@ public:
/// ///
/// \brief Character Append /// \brief Character Append
/// \param c A character to append /// \param c A character to append
/// \returns A new string containing the previous contents and an additional character `c`. /// \returns A new string containing the previous contents and an additional character \f$c\f$.
constexpr _wstring operator+(wchar_t c) const { constexpr _wstring operator+(wchar_t c) const {
if (_str == nullptr) { if (_str == nullptr) {
return _wstring(1, c); return _wstring(1, c);
@@ -433,7 +433,7 @@ public:
/// ///
/// \brief Character Prepend /// \brief Character Prepend
/// \param c A character to append /// \param c A character to append
/// \returns A new string containing the character `c` followed by the previous contents. /// \returns A new string containing the character \f$c\f$ followed by the previous contents.
friend constexpr _wstring operator+(wchar_t c, const _wstring& str) { friend constexpr _wstring operator+(wchar_t c, const _wstring& str) {
_wstring res(1, c); _wstring res(1, c);
return res += str; return res += str;
@@ -441,7 +441,7 @@ public:
/// ///
/// \param cstr The string to append /// \param cstr The string to append
/// \returns A new string containing the previous contents followed by the contents of `cstr` /// \returns A new string containing the previous contents followed by the contents of \f$cstr\f$
constexpr _wstring operator+(const wcstring& cstr) const { constexpr _wstring operator+(const wcstring& cstr) const {
if (_str == nullptr) { if (_str == nullptr) {
return _wstring(cstr); return _wstring(cstr);
@@ -456,7 +456,7 @@ public:
/// ///
/// \brief String Append /// \brief String Append
/// \param str The string to append /// \param str The string to append
/// \returns A new string containing the previous contents followed by the contents of `cstr` /// \returns A new string containing the previous contents followed by the contents of \f$cstr\f$
constexpr _wstring operator+(const _wstring& str) const { constexpr _wstring operator+(const _wstring& str) const {
if (_str == nullptr) { if (_str == nullptr) {
return _wstring(str); return _wstring(str);
@@ -474,7 +474,7 @@ public:
/// ///
/// \brief Character Append Assignment /// \brief Character Append Assignment
/// \param c A character to append /// \param c A character to append
/// \returns `this` string containing an additional character `c`. /// \returns \f$this\f$ string containing an additional character \f$c\f$.
constexpr _wstring& operator+=(wchar_t c) { constexpr _wstring& operator+=(wchar_t c) {
if (_str == nullptr) { if (_str == nullptr) {
_str.callocate(2); _str.callocate(2);
@@ -488,7 +488,7 @@ public:
/// ///
/// \param cstr The string to append /// \param cstr The string to append
/// \returns `this` string expanded to additionally contain `cstr` /// \returns \f$this\f$ string expanded to additionally contain \f$cstr\f$
constexpr _wstring& operator+=(const wcstring& cstr) { constexpr _wstring& operator+=(const wcstring& cstr) {
if (_str == nullptr) { if (_str == nullptr) {
return *this = cstr; return *this = cstr;
@@ -502,7 +502,7 @@ public:
/// ///
/// \brief String Append Assignment /// \brief String Append Assignment
/// \param str The string to append /// \param str The string to append
/// \returns `this` string expanded to additionally contain `str` /// \returns \f$this\f$ string expanded to additionally contain \f$str\f$
constexpr _wstring& operator+=(const _wstring& str) { constexpr _wstring& operator+=(const _wstring& str) {
if (_str == nullptr) { if (_str == nullptr) {
return *this = str; return *this = str;

View File

@@ -71,7 +71,7 @@ public:
/// ///
/// \brief Default Constructor /// \brief Default Constructor
/// ///
/// \details Initializes the held atomic variable with `0`. /// \details Initializes the held atomic variable with \f$0\f$.
constexpr atomic() noexcept constexpr atomic() noexcept
: _value(static_cast<T>(0)) { : _value(static_cast<T>(0)) {
} }
@@ -79,7 +79,7 @@ public:
/// ///
/// \brief Value Constructor /// \brief Value Constructor
/// ///
/// \details Initializes the held atomic variable with `value`. /// \details Initializes the held atomic variable with \f$value\f$.
/// \param value The value to initialize the atomic variable with. /// \param value The value to initialize the atomic variable with.
constexpr atomic(const T value) noexcept constexpr atomic(const T value) noexcept
: _value(value) { : _value(value) {
@@ -95,9 +95,9 @@ public:
atomic& operator=(const atomic&) volatile = delete; atomic& operator=(const atomic&) volatile = delete;
/// ///
/// \details Atomically assigns `x` to the atomic variable. /// \details Atomically assigns \f$x\f$ to the atomic variable.
/// \param x The value to assign /// \param x The value to assign
/// \returns `x` /// \returns \f$x\f$
T operator=(const T x) noexcept { T operator=(const T x) noexcept {
this->store(x); this->store(x);
return x; return x;
@@ -106,9 +106,9 @@ public:
/// ///
/// \brief Stores a value into an atomic object /// \brief Stores a value into an atomic object
/// ///
/// \details Atomically assigns `x` to the atomic variable. /// \details Atomically assigns \f$x\f$ to the atomic variable.
/// \param x The value to assign /// \param x The value to assign
/// \returns `x` /// \returns \f$x\f$
T operator=(const T x) volatile noexcept { T operator=(const T x) volatile noexcept {
this->store(x); this->store(x);
return x; return x;
@@ -119,7 +119,7 @@ public:
// Modifiers =========================================================================================================== // Modifiers ===========================================================================================================
/// ///
/// \details Atomically replaces the current value with `x`. Memory is affected according to the value of `order`. /// \details Atomically replaces the current value with \f$x\f$. Memory is affected according to the value of \f$order\f$.
/// \param x The value to store into the atomic variable /// \param x The value to store into the atomic variable
/// \param order Memory order constraints to enforce /// \param order Memory order constraints to enforce
void store(const T x, memory_order order = memory_order_seq_cst) noexcept { void store(const T x, memory_order order = memory_order_seq_cst) noexcept {
@@ -129,7 +129,7 @@ public:
/// ///
/// \brief Atomically replaces the value of the atomic object with a non-atomic argument /// \brief Atomically replaces the value of the atomic object with a non-atomic argument
/// ///
/// \details Atomically replaces the current value with `x`. Memory is affected according to the value of `order`. /// \details Atomically replaces the current value with \f$x\f$. Memory is affected according to the value of \f$order\f$.
/// \param x The value to store into the atomic variable /// \param x The value to store into the atomic variable
/// \param order Memory order constraints to enforce /// \param order Memory order constraints to enforce
void store(const T x, memory_order order = memory_order_seq_cst) volatile noexcept { void store(const T x, memory_order order = memory_order_seq_cst) volatile noexcept {
@@ -139,7 +139,7 @@ public:
/// ///
/// \details Atomically loads and returns the current value of the atomic variable. /// \details Atomically loads and returns the current value of the atomic variable.
/// Memory is affected according to the value of `order`. /// Memory is affected according to the value of \f$order\f$.
/// \param order Memory order constraints to enforce /// \param order Memory order constraints to enforce
/// \returns The current value of the atomic variable. /// \returns The current value of the atomic variable.
T load(memory_order order = memory_order_seq_cst) const noexcept { T load(memory_order order = memory_order_seq_cst) const noexcept {
@@ -150,7 +150,7 @@ public:
/// \brief Atomically obtains the value of the atomic object /// \brief Atomically obtains the value of the atomic object
/// ///
/// \details Atomically loads and returns the current value of the atomic variable. /// \details Atomically loads and returns the current value of the atomic variable.
/// Memory is affected according to the value of `order`. /// Memory is affected according to the value of \f$order\f$.
/// \param order Memory order constraints to enforce /// \param order Memory order constraints to enforce
/// \returns The current value of the atomic variable. /// \returns The current value of the atomic variable.
T load(memory_order order = memory_order_seq_cst) const volatile noexcept { T load(memory_order order = memory_order_seq_cst) const volatile noexcept {
@@ -174,8 +174,8 @@ public:
/// ///
/// \details Atomically replaces the underlying value with `x` (a read-modify-write operation). /// \details Atomically replaces the underlying value with \f$x\f$ (a read-modify-write operation).
/// Memory is affected according to the value of `order`. /// Memory is affected according to the value of \f$order\f$.
/// \param x Value to assign /// \param x Value to assign
/// \param order Memory order constraints to enforce /// \param order Memory order constraints to enforce
/// \return The value of the atomic variable before the call. /// \return The value of the atomic variable before the call.
@@ -186,8 +186,8 @@ public:
/// ///
/// \brief Atomically replaces the value of the atomic object and obtains the value held previously /// \brief Atomically replaces the value of the atomic object and obtains the value held previously
/// ///
/// \details Atomically replaces the underlying value with `x` (a read-modify-write operation). /// \details Atomically replaces the underlying value with \f$x\f$ (a read-modify-write operation).
/// Memory is affected according to the value of `order`. /// Memory is affected according to the value of \f$order\f$.
/// \param x Value to assign /// \param x Value to assign
/// \param order Memory order constraints to enforce /// \param order Memory order constraints to enforce
/// \return The value of the atomic variable before the call. /// \return The value of the atomic variable before the call.
@@ -197,39 +197,39 @@ public:
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds. /// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails. /// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order succ, memory_order fail) noexcept { bool compare_exchange_weak(T& exp, T x, memory_order succ, memory_order fail) noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, succ, fail); return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, succ, fail);
} }
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds. /// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails. /// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order succ, memory_order fail) volatile noexcept { bool compare_exchange_weak(T& exp, T x, memory_order succ, memory_order fail) volatile noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, succ, fail); return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, succ, fail);
} }
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param order The memory synchronization ordering for both operations. /// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order order = memory_order_seq_cst) noexcept { bool compare_exchange_weak(T& exp, T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, order, order); return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, order, order);
} }
@@ -237,52 +237,52 @@ public:
/// ///
/// \brief Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not /// \brief Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param order The memory synchronization ordering for both operations. /// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_weak(T& exp, T x, memory_order order = memory_order_seq_cst) volatile noexcept { bool compare_exchange_weak(T& exp, T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, order, order); return ::atomic_compare_exchange_weak_explicit(&_value, &exp, x, order, order);
} }
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds. /// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails. /// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order succ, memory_order fail) noexcept { bool compare_exchange_strong(T& exp, T x, memory_order succ, memory_order fail) noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, succ, fail); return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, succ, fail);
} }
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds. /// \param succ The memory synchronization ordering for the read-modify-write operation if the comparison succeeds.
/// \param fail The memory synchronization ordering for the load operation if the comparison fails. /// \param fail The memory synchronization ordering for the load operation if the comparison fails.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order succ, memory_order fail) volatile noexcept { bool compare_exchange_strong(T& exp, T x, memory_order succ, memory_order fail) volatile noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, succ, fail); return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, succ, fail);
} }
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param order The memory synchronization ordering for both operations. /// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order order = memory_order_seq_cst) noexcept { bool compare_exchange_strong(T& exp, T x, memory_order order = memory_order_seq_cst) noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, order, order); return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, order, order);
} }
@@ -290,13 +290,13 @@ public:
/// ///
/// \brief Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not /// \brief Atomically compares the value of the atomic object with non-atomic argument and performs atomic exchange if equal or atomic load if not
/// ///
/// \details Atomically compares the value of `*this` with that of `exp`. /// \details Atomically compares the value of `*this` with that of \f$exp\f$.
/// If they are equal, replaces the former with `x` (performs read-modify-write operation). /// If they are equal, replaces the former with \f$x\f$ (performs read-modify-write operation).
/// Otherwise, loads the actual value stored in *this into `exp` (performs load operation). /// Otherwise, loads the actual value stored in *this into \f$exp\f$ (performs load operation).
/// \param exp Reference to the value expected to be found in the atomic object. /// \param exp Reference to the value expected to be found in the atomic object.
/// \param x The value to store in the atomic object if it is as expected. /// \param x The value to store in the atomic object if it is as expected.
/// \param order The memory synchronization ordering for both operations. /// \param order The memory synchronization ordering for both operations.
/// \returns `true` if the underlying atomic value was successfully changed, `false` otherwise. /// \returns \f$true\f$ if the underlying atomic value was successfully changed, \f$false\f$ otherwise.
bool compare_exchange_strong(T& exp, T x, memory_order order = memory_order_seq_cst) volatile noexcept { bool compare_exchange_strong(T& exp, T x, memory_order order = memory_order_seq_cst) volatile noexcept {
return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, order, order); return ::atomic_compare_exchange_strong_explicit(&_value, &exp, x, order, order);
} }

View File

@@ -36,16 +36,16 @@ namespace fennec
scene_node* scene::operator[](const cstring& name) const { scene_node* scene::operator[](const cstring& name) const {
list<size_t> parse; list<size_t> parse;
parse.push_back(root); parse.push_back(table_t::root);
while (not parse.empty()) { while (not parse.empty()) {
size_t n = parse.front(); size_t n = parse.front();
if (_table[n].value->name == name) { if (_table[n]->name == name) {
return _table[n].value; return _table[n].get();
} }
// Pre-Order traversal // Pre-Order traversal
parse.push_front(next(n)); parse.push_front(_table.next(n));
parse.push_front(child(n)); parse.push_front(_table.child(n));
parse.pop_front(); parse.pop_front();
} }
return nullptr; return nullptr;
@@ -53,16 +53,16 @@ scene_node* scene::operator[](const cstring& name) const {
scene_node* scene::operator[](const string& name) const { scene_node* scene::operator[](const string& name) const {
list<size_t> parse; list<size_t> parse;
parse.push_back(root); parse.push_back(table_t::root);
while (not parse.empty()) { while (not parse.empty()) {
size_t n = parse.front(); size_t n = parse.front();
if (_table[n].value->name == name) { if (_table[n]->name == name) {
return _table[n].value; return _table[n].get();
} }
// Pre-Order traversal // Pre-Order traversal
parse.push_front(next(n)); parse.push_front(_table.next(n));
parse.push_front(child(n)); parse.push_front(_table.child(n));
parse.pop_front(); parse.pop_front();
} }
return nullptr; return nullptr;