diff --git a/CMakeLists.txt b/CMakeLists.txt
index cad838e..e0d59ed 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -244,7 +244,7 @@ fennec_add_sources(
include/fennec/math/ext/transform.h
- include/fennec/math/detail/_fwd.h
+ include/fennec/math/detail/_forward.h
include/fennec/math/detail/_math.h
include/fennec/math/detail/_matrix.h
include/fennec/math/detail/_types.h
@@ -297,7 +297,7 @@ fennec_add_sources(
# PLATFORM =============================================================================================================
- include/fennec/platform/interface/fwd.h
+ include/fennec/platform/interface/forward.h
include/fennec/platform/interface/display_server.h
include/fennec/platform/interface/platform.h source/platform/interface/platform.cpp
include/fennec/platform/interface/window.h source/platform/interface/window.cpp
@@ -314,6 +314,7 @@ add_subdirectory(test)
add_library(fennec STATIC
${FENNEC_SOURCES}
+ include/fennec/rtti/this_t.h
)
add_dependencies(fennec metaprogramming fennec-dependencies)
diff --git a/README.md b/README.md
index 6daf8ed..1dc0205 100644
--- a/README.md
+++ b/README.md
@@ -78,6 +78,24 @@ fennec Standards:
* Most behaviours should be type independent. Specifically interactions with the core systems of the engine.
+ - Classes should have banners between each distinct group of definitions, with the access specifier on the following
+ line. E.G.
+ ```c++
+ class foo {
+ // Definitions ============================
+ public:
+ using bar = int;
+
+ // Constructors & Destructor ==============
+ public:
+ foo();
+ ~foo();
+ };
+ ```
+ This helps significantly with readability, and it also serves to reduce bugs related to mistakes involving access
+ specifiers. E.G. in the example above, bar is changed to private, the constructors are still labeled public in the
+ case the person forgets to update the succeeding access specifiers.
+
diff --git a/cmake/compiler.cmake b/cmake/compiler.cmake
index 5cc38d0..72c9496 100644
--- a/cmake/compiler.cmake
+++ b/cmake/compiler.cmake
@@ -20,6 +20,10 @@
message(STATUS "Compiler: ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}")
+fennec_add_definitions(
+ FENNEC_LONG_COMPILER_NAME="${CMAKE_CXX_COMPILER_ID} ${CMAKE_SYSTEM_NAME} ${CMAKE_SYSTEM_PROCESSOR}"
+)
+
if(${CMAKE_CXX_COMPILER_ID} MATCHES "GNU")
set(FENNEC_COMPILER "GCC")
include("${FENNEC_SOURCE_DIR}/cmake/gcc.cmake")
diff --git a/include/fennec/containers/array.h b/include/fennec/containers/array.h
index 9ba65dc..d15b20b 100644
--- a/include/fennec/containers/array.h
+++ b/include/fennec/containers/array.h
@@ -44,23 +44,24 @@ namespace fennec
/// \brief Data Structure that defines a compile-time allocated array
///
/// \details
-/// | Property | Value |
-/// |:-----------:|:-----------:|
-/// | stable | ✅ |
-/// | dynamic | ⛔ |
-/// | homogeneous | ✅ |
-/// | distinct | ⛔ |
-/// | ordered | ⛔ |
-/// | space | \f$O(N)\f$ |
-/// | linear | ✅ |
-/// | access | \f$O(1)\f$ |
-/// | find | \f$O(N)\f$ |
-/// | insertion | ⛔ |
-/// | deletion | ⛔ |
+/// | Property | Value |
+/// |:-----------:|:----------:|
+/// | stable | ✅ |
+/// | dynamic | ⛔ |
+/// | homogeneous | ✅ |
+/// | distinct | ⛔ |
+/// | ordered | ⛔ |
+/// | space | \f$O(N)\f$ |
+/// | linear | ✅ |
+/// | access | \f$O(1)\f$ |
+/// | find | \f$O(N)\f$ |
+/// | insertion | ⛔ |
+/// | deletion | ⛔ |
+/// | space | \f$O(N)\f$ |
///
/// \tparam ValueT value type
-/// \tparam ElemV number of elements
-template
+/// \tparam N number of elements
+template
struct array {
// Definitions =========================================================================================================
@@ -69,21 +70,19 @@ public:
/// \name Definitions
/// @{
- using value_t = ValueT; ///< Alias for \f$ValueT\f$
+ using value_t = ValueT; //!< Alias for \f$ValueT\f$
/// @}
-// Public Members ======================================================================================================
+// Public Member Variables =============================================================================================
public:
- /// \name Public Members
+ /// \name Member Variables
/// @{
- ///
- /// \brief backing c-style array handle
- value_t data[ElemV];
+ value_t data[N]; //!< Backing c-style array handle
/// @}
@@ -96,14 +95,22 @@ public:
/// @{
///
- /// \brief returns the number of elements in the array
- /// \returns the number of elements in the array
- [[nodiscard]] constexpr size_t size() const { return ElemV; }
+ /// \brief Returns the number of elements in the array.
+ /// \returns \f$N\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ [[nodiscard]] constexpr size_t size() const { return N; }
///
- /// \brief returns **true** when the array is empty
- /// \return \f$ElemV == 0\f$
- [[nodiscard]] constexpr bool_t is_empty() const { return ElemV == 0; }
+ /// \brief Returns \f$true\f$ when the array is empty
+ /// \returns \f$ElemV == 0\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ [[nodiscard]] constexpr bool_t is_empty() const { return N == 0; }
/// @}
@@ -120,58 +127,68 @@ public:
/// \param i index of the element to return
/// \return reference to the requested element
///
- /// \par Time-Complexity
- /// Constant
+ /// \par Complexity
+ /// \f$O(1)\f$
///
- /// \par Space-Complexity
- /// Constant
constexpr value_t& operator[](size_t i) {
- assertd(i < ElemV, "Array Out of Bounds");
+ assertd(i < N, "Array Out of Bounds");
return data[i];
}
///
- /// \brief access specified element
+ /// \brief Indexed access
/// \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 Complexity
+ /// \f$O(1)\f$
///
- /// \par Space-Complexity
- /// Constant
constexpr const value_t& operator[](size_t i) const {
- assertd(i < ElemV, "Array Out of Bounds");
+ assertd(i < N, "Array Out of Bounds");
return data[i];
}
///
- /// \brief Access the first element
- /// \returns A reference to the element at \f$elements[0]\f$
+ /// \returns A reference to \f$data[0]\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr value_t& front() {
return data[0];
}
///
- /// \brief Const Access the first element
- /// \returns A const-qualified reference to the element at \f$elements[0]\f$
+ /// \brief Access the first element
+ /// \returns A const-qualified reference to \f$data[0]\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const value_t& front() const {
return data[0];
}
///
- /// \brief Access the first element
- /// \returns A reference to the element at \f$elements[ElemV - 1]\f$
+ /// \returns A reference to \f$data[N - 1]\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr value_t& back() {
- return data[ElemV - 1];
+ return data[N - 1];
}
///
- /// \brief Const Access the first element
- /// \returns A const-qualified reference to the element at \f$elements[ElemV - 1]\f$
+ /// \brief Access the last element
+ /// \returns A const-qualified reference to \f$data[N - 1]\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const value_t& back() const {
- return data[ElemV - 1];
+ return data[N - 1];
}
/// @}
@@ -186,14 +203,22 @@ public:
///
/// \brief Checks if all elements in the arrays are equal
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
friend constexpr bool_t operator==(const array& lhs, const array& rhs) {
- return array::_compare(lhs, rhs, make_index_metasequence{});
+ return array::_compare(lhs, rhs, make_index_metasequence{});
}
///
/// \brief Checks if any element in the arrays is not equal
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
friend constexpr bool_t operator!=(const array& lhs, const array& rhs) {
- return not array::_compare(lhs, rhs, make_index_metasequence{});
+ return not array::_compare(lhs, rhs, make_index_metasequence{});
}
/// @}
@@ -206,39 +231,51 @@ public:
/// @{
///
- /// \brief C++ Iterator Specification \f$begin()\f$
/// \returns A pointer to the first element of the array
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr value_t* begin() {
return data;
}
///
- /// \brief C++ Iterator Specification \f$end()\f$
- /// \returns A pointer to one after the end of the array
- constexpr value_t* end() {
- return data + ElemV;
- }
-
-
-
- ///
- /// \brief Const C++ Iterator Specification \f$begin()\f$
+ /// \brief C++ Iterator Specification \f$begin()\f$
/// \returns A const-qualified pointer to the first element of the array
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const value_t* begin() const {
return data;
}
///
- /// \brief Const C++ Iterator Specification \f$end()\f$
+ /// \returns A pointer to one after the end of the array
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ constexpr value_t* end() {
+ return data + N;
+ }
+
+ ///
+ /// \brief C++ Iterator Specification \f$end()\f$
/// \returns A const-qualified pointer to one after the end of the array
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const value_t* end() const {
- return data + ElemV;
+ return data + N;
}
/// @}
-// Helpers =============================================================================================================
+// Private Helpers =====================================================================================================
private:
template
static bool _compare(const array& lhs, const array& rhs, index_metasequence) {
diff --git a/include/fennec/containers/bintree.h b/include/fennec/containers/bintree.h
index ab4e5da..8e92753 100644
--- a/include/fennec/containers/bintree.h
+++ b/include/fennec/containers/bintree.h
@@ -18,7 +18,7 @@
///
/// \file fennec/containers/bintree.h
-/// \brief
+/// \brief A header containing the definition for an in-array binary tree.
///
///
/// \details
@@ -31,8 +31,10 @@
#ifndef FENNEC_CONTAINERS_BINTREE_H
#define FENNEC_CONTAINERS_BINTREE_H
+#include
#include
#include
+#include
#include
#include
@@ -43,19 +45,20 @@ namespace fennec
/// \brief Structure defining a binary tree
///
/// \details
-/// | Property | Value |
-/// |:-----------:|:-----------:|
-/// | stable | ⛔ |
-/// | dynamic | ✅ |
-/// | homogeneous | ✅ |
-/// | distinct | ⛔ |
-/// | ordered | ⛔ |
-/// | space | \f$O(N)\f$ |
-/// | linear | ⛔ |
-/// | access | \f$O(1)\f$ |
-/// | find | \f$O(N)\f$ |
-/// | insertion | \f$O(1)\f$ |
-/// | deletion | \f$O(1)\f$ |
+/// | Property | Value |
+/// |:-----------:|:----------:|
+/// | stable | ⛔ |
+/// | dynamic | ✅ |
+/// | homogeneous | ✅ |
+/// | distinct | ⛔ |
+/// | ordered | ⛔ |
+/// | space | \f$O(N)\f$ |
+/// | linear | ⛔ |
+/// | access | \f$O(1)\f$ |
+/// | find | \f$O(N)\f$ |
+/// | insertion | \f$O(1)\f$ |
+/// | deletion | \f$O(1)\f$ |
+/// | space | \f$O(N)\f$ |
///
/// \tparam TypeT The data type
/// \tparam AllocT An allocator class
@@ -67,6 +70,7 @@ private:
struct node;
public:
+
/// \name Definitions
/// @{
@@ -74,39 +78,20 @@ public:
using alloc_t = allocator_traits::template rebind; //!< The allocator type
static constexpr size_t npos = -1; //!< null position constant
+ ///
+ /// \brief Enum representing node side relative to parent
+ enum side_ : bool {
+ side_left = false, //!< Left Side
+ side_right = true //!< Right Side
+ };
+
/// @}
friend class iterator;
friend class const_iterator;
+
private:
- struct node {
- value_t value;
- size_t parent;
- size_t child[2];
-
- constexpr node()
- : value()
- , parent(npos), child{ npos, npos } {
- }
-
- template
- constexpr node(size_t p, size_t l, size_t r, ArgsT&&...args)
- : value(fennec::forward(args)...)
- , parent(p), child{ l, r } {
- }
-
- constexpr ~node() {
- parent = npos;
- child[0] = npos;
- child[1] = npos;
- }
-
- size_t& operator[](bool d) {
- return child[d];
- }
- };
-
using table_t = allocation;
using freed_t = list;
@@ -118,6 +103,12 @@ public:
///
/// \brief Default Constructor, initializes an empty tree
+ ///
+ /// \details The underlying allocation is not initialized.
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr bintree()
: _table()
, _freed()
@@ -128,6 +119,12 @@ public:
///
/// \brief Move Constructor, takes ownership of a tree
/// \param tree The tree to take ownership of
+ ///
+ /// \details Takes ownership of the underlying allocation of \f$tree\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr bintree(bintree&& tree) noexcept
: _table(fennec::move(tree._table))
, _freed(fennec::move(tree._freed))
@@ -138,15 +135,49 @@ public:
///
/// \brief Copy Constructor, copies a tree
/// \param tree The tree to copy
+ ///
+ /// \details Copies the contents of \f$tree\f$ into a new tree. Invokes copy constructor.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr bintree(const bintree& tree)
- : _table(tree._table)
- , _freed(tree._freed)
- , _root(tree._root)
- , _size(tree._size) {
+ : _table(tree._table.capacity())
+ , _freed()
+ , _root(nullid)
+ , _size(0) {
+
+ // Visitor for copying
+ struct {
+ bintree& self;
+ const bintree& target;
+ deque> stack;
+
+ uint8_t operator()(const value_t& x, size_t n) {
+ while (stack.back().second != target.parent(n)) {
+ stack.pop_back();
+ }
+ stack.emplace_back(self.insert(stack.back().first, target.side(n), x), n);
+ return traversal_control_continue;
+ }
+ } visitor = {
+ .self = *this,
+ .target = tree
+ };
+
+ tree.template traverse(
+ visitor, tree._root
+ );
}
///
/// \brief Destructor, clears the tree
+ ///
+ /// \details Clears the contents of \f$tree\f$. Invokes destructor.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr ~bintree() {
clear();
}
@@ -162,24 +193,40 @@ public:
///
/// \returns The number of elements in the tree
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t size() const {
return _size;
}
///
/// \returns \f$true\f$ when there are no elements in the tree, \f$false\f$ otherwise.
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr bool is_empty() const {
return _size == 0;
}
///
/// \returns The capacity of the underlying allocation
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t capacity() const {
return _table.capacity();
}
///
/// \returns The next id to be returned by \f$insert\f$ or \f$emplace\f$.
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t next_id() const {
size_t i = _size;
if (not _freed.is_empty()) {
@@ -190,6 +237,10 @@ public:
///
/// \returns The next id to be returned by \f$insert\f$ or \f$emplace\f$.
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t root() const {
return _root;
}
@@ -205,58 +256,79 @@ public:
/// @{
///
- /// \details \f$O(1)\f$
/// \param i The node id
/// \returns The parent of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t parent(size_t i) const {
return i == npos ? npos : _table[i].parent;
}
///
- /// \details \f$O(1)\f$
/// \param i The node id
/// \returns The grandparent of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t grandparent(size_t i) const {
return parent(parent(i));
}
///
- /// \details \f$O(1)\f$
/// \param i The node id
/// \returns The left child of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t left(size_t i) const {
return i == npos ? npos : _table[i].child[false];
}
///
- /// \details \f$O(1)\f$
/// \param i The node id
/// \returns The right child of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t right(size_t i) const {
return i == npos ? npos : _table[i].child[true];
}
///
- /// \details \f$O(1)\f$
/// \param i The node id
/// \param dir The direction to go \f$true\f$ for right, \f$false\f$ for left
/// \returns The child in the direction specified by \f$dir\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t child(size_t i, bool dir) const {
return i == npos ? npos : _table[i].child[dir];
}
///
- /// \details \f$O(1)\f$
/// \param i The node id
/// \returns \f$true\f$ if \f$i\f$ is the right node of \f$parent(i)\f$, \f$false\f$ otherwise
- constexpr bool direction(size_t i) const {
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ constexpr bool side(size_t i) const {
return i == npos ? false : i == right(_parent(i));
}
///
- /// \details \f$O(1)\f$
/// \param i The id of the node
/// \returns The id of the sibling of \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t sibling(size_t i) const {
if (i == npos) {
return npos;
@@ -270,9 +342,12 @@ public:
}
///
- /// \details \f$O(\log n)\f$
/// \param i The node id
/// \returns The depth of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(\log n)\f$
+ ///
constexpr size_t depth(size_t i) const {
size_t d = 0;
while (i != npos) {
@@ -283,9 +358,12 @@ public:
}
///
- /// \details \f$O(\log n)\f$
/// \param i The node id
/// \returns The id of the left-most node of \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(\log n)\f$
+ ///
constexpr size_t left_most(size_t i) const {
if (i >= _table.size()) {
return npos;
@@ -297,9 +375,12 @@ public:
}
///
- /// \details \f$O(\log n)\f$
/// \param i The node id
/// \returns The id of the right-most node of \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(\log n)\f$
+ ///
constexpr size_t right_most(size_t i) const {
if (i >= _table.size()) {
return npos;
@@ -320,18 +401,25 @@ public:
/// @{
///
- /// \details \f$O(1)\f$
/// \param i The node id
- /// \returns \f$nullptr\f$ if node \f$i\f$ does not exist, otherwise, a pointer to the value of node \f$i\f$
+ /// \returns a reference to the value of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr value_t& operator[](size_t i) {
assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value;
}
///
- /// \details Const Access, \f$O(1)\f$
+ /// \details Node access
/// \param i The node id
- /// \returns \f$nullptr\f$ if node \f$i\f$ does not exist, otherwise, a pointer to the value of node \f$i\f$
+ /// \returns a reference to the value of node \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const value_t& operator[](size_t i) const {
assertd(i < _table.size(), "Index out of bounds.");
return _table[i].value;
@@ -339,7 +427,9 @@ public:
/// @}
+
// Modifiers ===========================================================================================================
+public:
/// \name Modifiers
/// @{
@@ -349,6 +439,10 @@ public:
/// \param p The parent node
/// \param val The object to move into the new node
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t insert_left(size_t p, value_t&& val) {
return this->_insert_left(p, fennec::forward(val));
}
@@ -358,6 +452,10 @@ public:
/// \param p The parent node
/// \param val The object to copy to the new node
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t insert_left(size_t p, const value_t& val) {
return this->_insert_left(p, val);
}
@@ -368,6 +466,10 @@ public:
/// \param p The parent node
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
constexpr size_t emplace_left(size_t p, ArgsT&&...args) {
return this->_insert_left(p, fennec::forward(args)...);
@@ -378,6 +480,10 @@ public:
/// \param p The parent node
/// \param val The object to move into the new node
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t insert_right(size_t p, value_t&& val) {
return this->_insert_right(p, fennec::forward(val));
}
@@ -387,6 +493,10 @@ public:
/// \param p The parent node
/// \param val The object to copy to the new node
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t insert_right(size_t p, const value_t& val) {
return this->_insert_right(p, val);
}
@@ -397,6 +507,10 @@ public:
/// \param p The parent node
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
constexpr size_t emplace_right(size_t p, ArgsT&&...args) {
return this->_insert_right(p, fennec::forward(args)...);
@@ -409,6 +523,10 @@ public:
/// \param sub The root node for the rotation
/// \param dir The direction to rotate, \f$true\f$ for right, \f$false\f$ for left
/// \returns the new root node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t rotate(size_t sub, bool dir) {
if (sub == npos) {
return npos;
@@ -439,6 +557,10 @@ public:
/// \param side The side to insert on
/// \param val The object to move into the new node
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t insert(size_t parent, bool side, value_t&& val) {
return this->_insert(parent, side, fennec::forward(val));
}
@@ -449,6 +571,10 @@ public:
/// \param side The side to insert on
/// \param val The object to copy to the new node
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t insert(size_t parent, bool side, const value_t& val) {
return this->_insert(parent, side, val);
}
@@ -460,6 +586,10 @@ public:
/// \param side The side to insert on
/// \param args The arguments to construct the new node with
/// \returns The id of the new node
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
constexpr size_t emplace(size_t parent, bool side, ArgsT&&...args) {
return this->_insert(parent, side, fennec::forward(args)...);
@@ -467,6 +597,10 @@ public:
///
/// \brief Clears the tree, destroying all elements
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void clear() {
list queue;
@@ -500,6 +634,35 @@ public:
/// \name Traversal
/// @{
+ ///
+ /// \details
+ /// The visitor should accept a reference to a value of type \f$TypeT\f$ and a \f$size_t\f$ which contains the node's id.
+ /// 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 VisitorT The visitor, should fulfill the signature \f$uint8_t visit(TypeT&, size_t)\f$
+ /// \param visit The visiting object
+ /// \param i The node to start at
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ template
+ constexpr void traverse(VisitorT&& visit, size_t i) {
+ OrderT order;
+ i = order(*this, i);
+ while (i != npos) {
+ uint8_t mode = traversal_control_continue;
+ if (_table[i].value) {
+ mode = visit(_table[i].value, i);
+ }
+ if (mode == traversal_control_break) {
+ break;
+ }
+ i = order[*this, i, mode];
+ }
+ }
+
///
/// \brief Traverse the tree using a specified order and visiting functor
///
@@ -511,8 +674,12 @@ public:
/// \tparam VisitorT The visitor, should fulfill the signature \f$uint8_t visit(TypeT&, size_t)\f$
/// \param visit The visiting object
/// \param i The node to start at
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
- constexpr void traverse(VisitorT&& visit, size_t i) {
+ constexpr void traverse(VisitorT&& visit, size_t i) const {
OrderT order;
i = order(*this, i);
while (i != npos) {
@@ -918,6 +1085,10 @@ public:
///
/// \returns an iterator at the first element in pre-order traversal
+ ///
+ /// \par Complexity
+ /// \f$O(\log N)\f$
+ ///
iterator begin() {
return iterator(this, _root);
}
@@ -925,12 +1096,20 @@ public:
///
/// \brief C++ Iterator Specification \f$begin()\f$
/// \returns an iterator at the first element in pre-order traversal
+ ///
+ /// \par Complexity
+ /// \f$O(\log N)\f$
+ ///
const_iterator begin() const {
return iterator(this, _root);
}
///
/// \returns an iterator at the first element in pre-order traversal
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
iterator end() {
return iterator(this, _root, nullid);
}
@@ -938,20 +1117,26 @@ public:
///
/// \brief C++ Iterator Specification \f$end()\f$
/// \returns an iterator at the first element in pre-order traversal
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
const_iterator end() const {
return iterator(this, _root, nullid);
}
/// @}
-// Fields ==============================================================================================================
+
+// Private Member Variables ============================================================================================
private:
table_t _table;
freed_t _freed;
size_t _root, _size;
-// Helpers =============================================================================================================
+// Private Helpers =====================================================================================================
+private:
constexpr size_t _next_free() {
size_t i = _size;
if (not _freed.is_empty()) {
@@ -959,7 +1144,7 @@ private:
_freed.pop_front();
}
if (i >= _table.capacity()) {
- _table.creallocate(2 * fennec::max(_table.capacity(), size_t(4)));
+ _table.reallocate(2 * fennec::max(_table.capacity(), size_t(4)));
}
++_size;
return i;
@@ -1047,6 +1232,35 @@ private:
bool d = i == _right(p);
return _child(p, !d);
}
+
+// Private Definitions =================================================================================================
+private:
+ struct node {
+ value_t value;
+ size_t parent;
+ size_t child[2];
+
+ constexpr node()
+ : value()
+ , parent(npos), child{ npos, npos } {
+ }
+
+ template
+ constexpr node(size_t p, size_t l, size_t r, ArgsT&&...args)
+ : value(fennec::forward(args)...)
+ , parent(p), child{ l, r } {
+ }
+
+ constexpr ~node() {
+ parent = npos;
+ child[0] = npos;
+ child[1] = npos;
+ }
+
+ size_t& operator[](bool d) {
+ return child[d];
+ }
+ };
};
}
diff --git a/include/fennec/containers/bitfield.h b/include/fennec/containers/bitfield.h
index 26fb289..77e9385 100644
--- a/include/fennec/containers/bitfield.h
+++ b/include/fennec/containers/bitfield.h
@@ -42,19 +42,20 @@ namespace fennec
/// \brief Bitfield Container with basic Bit Ops
///
/// \details
-/// | Property | Value |
-/// |:-----------:|:------------------------------:|
-/// | stable | Elements cannot be referenced. |
-/// | dynamic | ⛔ |
-/// | homogeneous | ✅ |
-/// | distinct | ⛔ |
-/// | ordered | ⛔ |
-/// | space | \f$O(N)\f$ |
-/// | linear | ✅ |
-/// | access | \f$O(1)\f$ |
-/// | find | \f$O(N)\f$ |
-/// | insertion | ⛔ |
-/// | deletion | ⛔ |
+/// | Property | Value |
+/// |:-----------:|:----------:|
+/// | stable | ⛔ |
+/// | dynamic | ⛔ |
+/// | homogeneous | ✅ |
+/// | distinct | ⛔ |
+/// | ordered | ⛔ |
+/// | space | \f$O(N)\f$ |
+/// | linear | ✅ |
+/// | access | \f$O(1)\f$ |
+/// | find | \f$O(N)\f$ |
+/// | insertion | ⛔ |
+/// | deletion | ⛔ |
+/// | space | \f$O(N)\f$ |
///
/// \tparam N The number of bits in the bitfield
template
@@ -62,21 +63,41 @@ struct bitfield {
// Constants ===========================================================================================================
public:
+
+ /// \name Constants
+ /// @{
+
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 ========================================================================================================
+
+// Constructors & Destructor ===========================================================================================
public:
+
+ /// \name Constructors & Destructor
+ /// @{
+
+ ///
+ /// \brief Default constructor.
+ /// \details Initializes all bits with \f$0\f$.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
///
- /// \brief default constructor, initializes with \f$0\f$
constexpr bitfield()
: _bytes() {
}
///
- /// \brief boolean array constructor
+ /// \brief Boolean array constructor.
/// \param arr An array of boolean values resembling each bit.
+ /// \details Initializes each bit with the respective boolean value in \f$arr\f$
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
explicit constexpr bitfield(const bool (&arr)[N])
: _bytes() {
for (size_t i = 0; i < arr; ++i) {
@@ -85,8 +106,13 @@ public:
}
///
- /// \brief index array constructor
- /// \param arr An array of indices values resembling which bits to set.
+ /// \brief Index array constructor.
+ /// \param arr An array of indices.
+ /// \details Sets the bits of each index provided in \f$arr\f$.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
explicit constexpr bitfield(const size_t (&arr)[I])
: _bytes() {
@@ -96,8 +122,13 @@ public:
}
///
- /// \brief variadic array constructor
- /// \param args A set of indices values resembling which bits to set.
+ /// \param args A set of indices.
+ /// \details This substitution assumes \f$ArgsT\ldots\f$ can be taken as an array of indices.
+ /// Sets the bits of each index provided in \f$args\ldots\f$.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr bitfield(ArgsT&&...args)
: _bytes() {
@@ -105,7 +136,15 @@ public:
}
///
- /// \param args A set of boolean values resembling each bit.
+ /// \brief Variadic array constructor
+ /// \param args A set of boolean values.
+ /// \details This substitution assumes \f$ArgsT\ldots\f$ can be taken as an array of booleans.
+ /// Initializes each bit with the respective boolean in \f$args\ldots\f$.
+ /// Does not necessitate the number of arguments be equal to the number of bits.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template requires((is_bool_v or is_convertible_v) and ...)
constexpr bitfield(ArgsT&&...args)
: _bytes() {
@@ -116,6 +155,10 @@ public:
///
/// \brief copy constructor
/// \param bf bitfield to copy
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
bitfield(const bitfield& bf)
: _bytes(bf._bytes) {
}
@@ -123,6 +166,10 @@ public:
///
/// \brief move constructor
/// \param bf bitfield to move
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
bitfield(bitfield&& bf) noexcept
: _bytes(bf._bytes) {
}
@@ -131,22 +178,52 @@ public:
/// \brief destructor
constexpr ~bitfield() = default;
+ /// @}
+
+
+// Assignment ==========================================================================================================
+public:
+
+ /// \name Assignment Operators
+ /// @{
+
///
/// \brief copy assignment
/// \param bf bitfield to copy
/// \returns a reference to self
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
bitfield& operator=(const bitfield& bf) = default;
///
/// \brief move assignment
/// \param bf bitfield to move
/// \returns a reference to self
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
bitfield& operator=(bitfield&& bf) noexcept = default;
+ /// @}
+
+
+// Access & Modifiers ==================================================================================================
+public:
+
+ /// \name Access & Modifiers
+ /// @{
+
///
/// \brief test a bit
/// \param i the index of the bit
/// \returns the value stored in the bit as a boolean
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
bool test(size_t i) const {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
@@ -157,6 +234,10 @@ public:
///
/// \brief set a bit
/// \param i the index of the bit
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void set(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
@@ -167,6 +248,10 @@ public:
///
/// \brief clear a bit
/// \param i the index of the bit
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void clear(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
@@ -177,6 +262,10 @@ public:
///
/// \brief toggle a bit
/// \param i the index of the bit
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void toggle(size_t i) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
@@ -186,8 +275,12 @@ public:
///
/// \brief store \f$v\f$ in bit \f$i\f$
- /// \param i
- /// \param v
+ /// \param i the index of the bit
+ /// \param v the value to store
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void store(size_t i, bool v) {
assertd(i < bits, "Index out of Bounds!");
size_t b = i / 8;
@@ -198,15 +291,26 @@ public:
///
/// \brief not operator
/// \returns a bitfield containing the bit-wise inverse
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
bitfield operator~() const {
bitfield res = *this;
res._inv_helper(make_index_metasequence_t{});
return res;
}
+ /// @}
+
+
+// Private Member Variables ============================================================================================
private:
array _bytes;
+
+// Private Helpers =====================================================================================================
+private:
template
void _inv_helper(index_metasequence) {
((_bytes[I] = ~_bytes[I]), ...);
diff --git a/include/fennec/containers/containers.h b/include/fennec/containers/containers.h
index 5b6dcb0..f1e0a8f 100644
--- a/include/fennec/containers/containers.h
+++ b/include/fennec/containers/containers.h
@@ -42,19 +42,20 @@
///
/// \section fennec_containers_container_section_properties Container Properties
///
-/// | Property | Meaning |
-/// |:-----------:|:----------------------------------------------------------------------------------------------:|
-/// | stable | Any pointer reference to an element remains constant for the lifetime of the data structure. |
-/// | dynamic | Memory for this data structure is allocated on the heap. |
-/// | homogeneous | The types of all elements are either identical, or inherit the same base type. |
-/// | distinct | Elements are guaranteed to be unique in their value. |
-/// | ordered | Elements are guaranteed to be in order, such that for any index \f$i\f$, \f$E_i < E_{i + 1}\f$ |
-/// | space | The amount of memory allocated with respect to the number of elements, in big-O notation. |
-/// | linear | Each element is sequential in terms of access. |
-/// | access | The runtime of the access operators and functions, in big-O notation. |
-/// | find | The runtime of finding an element in the data structure, in big-O notation. |
-/// | insertion | The runtime of inserting an element in the data structure, in big-O notation. |
-/// | deletion | The runtime of erasing an element in the data structure, in big-O notation. |
+/// | Property | Meaning |
+/// |:----------------|:-----------------------------------------------------------------------------------------------|
+/// | **stable** | Any pointer reference to an element remains constant for the lifetime of the container. |
+/// | **dynamic** | Memory for this container is allocated on the heap. |
+/// | **homogeneous** | The types of all elements are either identical, or inherit the same base type. |
+/// | **distinct** | Elements are guaranteed to be unique in their value. |
+/// | **ordered** | Elements are guaranteed to be in order, such that for any index \f$i\f$, \f$E_i < E_{i + 1}\f$ |
+/// | **space** | The amount of memory allocated with respect to the number of elements, in big-O notation. |
+/// | **linear** | Each element is sequential in terms of access. |
+/// | **access** | The runtime of the access operators and functions, in big-O notation. |
+/// | **find** | The runtime of finding an element in the container, in big-O notation. |
+/// | **insertion** | The runtime of inserting an element in the container, in big-O notation. |
+/// | **deletion** | The runtime of erasing an element in the container, in big-O notation. |
+/// | **space** | The space complexity of the container. |
///
///
/// \section fennec_containers_section_cppstdlib C++ Standard Template Library
diff --git a/include/fennec/containers/deque.h b/include/fennec/containers/deque.h
index 1dfd232..41870bb 100644
--- a/include/fennec/containers/deque.h
+++ b/include/fennec/containers/deque.h
@@ -59,34 +59,30 @@ namespace fennec
/// | find | \f$O(N)\f$ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
+/// | space | \f$O(N)\f$ |
///
/// \tparam TypeT value type
template>
struct deque {
// Definitions =========================================================================================================
-public:
- using value_t = TypeT; ///< Alias for the value type
- class iterator;
-
private:
- struct node {
- value_t value;
- node *prev, *next;
-
- template
- node(node* prev, node* next, ArgsT&&...args)
- : value(fennec::forward(args)...)
- , prev(prev), next(next) {
- }
-
- ~node() = default;
- };
+ struct node;
public:
+
+ /// \name Definitions
+ /// @{
+
+ using value_t = TypeT; //!< Alias for the value type
using alloc_t = allocator_traits::template rebind; //!< The underlying allocator type
using elem_t = node*; //!< The underlying element type
+ /// @}
+
+
+ class iterator;
+
// Constructors ========================================================================================================
@@ -95,6 +91,10 @@ public:
///
/// \brief Default Constructor, initializes an empty deque
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
deque()
: _alloc()
, _first(nullptr)
@@ -105,6 +105,10 @@ public:
///
/// \brief Alloc Constructor, initializes an empty deque with the specified allocator
/// \param alloc the allocator to copy
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
deque(const alloc_t& alloc)
: _alloc(alloc)
, _first(nullptr)
@@ -115,6 +119,10 @@ public:
///
/// \brief Copy Constructor
/// \param deque the deque to copy
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
deque(const deque& deque)
: _alloc(deque._alloc)
, _first(nullptr)
@@ -130,6 +138,10 @@ public:
///
/// \brief Deque Move Constructor
/// \param deque the deque to move
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
deque(deque&& deque) noexcept
: _alloc(deque._alloc)
, _first(deque._first)
@@ -141,6 +153,10 @@ public:
///
/// \brief Destructor, calls deque::clear
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
~deque() {
clear();
}
@@ -154,12 +170,20 @@ public:
///
/// \returns \f$true\f$ when the deque is empty, \f$false\f$ otherwise
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr bool is_empty() const {
return _size == 0;
}
///
- /// \returns the number of elements in size()
+ /// \returns the number of elements in the deque
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t size() const {
return _size;
}
@@ -174,6 +198,10 @@ public:
///
/// \returns a reference to the first element in the deque
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
value_t& front() {
assert(not is_empty(), "Attempted to access an empty deque.");
return _first->value;
@@ -181,6 +209,10 @@ public:
///
/// \returns a const-qualified reference to the first element in the deque
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
const value_t& front() const {
assert(not is_empty(), "Attempted to access an empty deque.");
return _first->value;
@@ -188,6 +220,10 @@ public:
///
/// \returns a reference to the last element in the deque
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
value_t& back() {
assert(not is_empty(), "Attempted to access an empty deque.");
return _last->value;
@@ -195,6 +231,10 @@ public:
///
/// \returns a const-qualified reference to the last element in the deque
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
const value_t& back() const {
assert(not is_empty(), "Attempted to access an empty deque.");
return _last->value;
@@ -211,6 +251,10 @@ public:
///
/// \brief Push Front Move, moves a value to the front of the deque
/// \param elem the value to move
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void push_front(value_t&& elem) {
this->_push_front(elem);
}
@@ -218,6 +262,10 @@ public:
///
/// \brief Push Front Copy, copies a value to the front of the deque
/// \param elem the value to copy
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void push_front(const value_t& elem) {
this->_push_front(elem);
}
@@ -226,6 +274,10 @@ public:
/// \brief Emplace Front, constructs a new value at the front of the deque
/// \tparam ArgsT Argument types
/// \param args Arguments used to construct the value
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
void emplace_front(ArgsT&&...args) {
this->_push_front(fennec::forward(args)...);
@@ -235,6 +287,10 @@ public:
///
/// \brief Push Back Move, moves a value to the back of the deque
/// \param elem the value to move
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void push_back(value_t&& elem) {
this->_push_back(elem);
}
@@ -242,6 +298,10 @@ public:
///
/// \brief Push Back Copy, copies a value to the back of the deque
/// \param elem the value to copy
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void push_back(const value_t& elem) {
this->_push_back(elem);
}
@@ -250,6 +310,10 @@ public:
/// \brief Emplace Back, constructs a new value at the back of the deque
/// \tparam ArgsT Argument types
/// \param args Arguments used to construct the value
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
void emplace_back(ArgsT&&...args) {
this->_push_back(fennec::forward(args)...);
@@ -257,6 +321,10 @@ public:
///
/// \brief Clears the contents of the deque
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
void clear() {
elem_t it = _first;
while (it) {
@@ -272,6 +340,10 @@ public:
///
/// \brief Erase the First Element
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void pop_front() {
if (_first == nullptr) {
return;
@@ -286,6 +358,10 @@ public:
///
/// \brief Erase the Last Element
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void pop_back() {
if (_last == nullptr) {
return;
@@ -307,11 +383,16 @@ public:
* TODO: Decide whether you should be able to iterate over a deque
*/
+
+// Private Member Variables ============================================================================================
private:
alloc_t _alloc;
node *_first, *_last;
size_t _size;
+
+// Private Helpers =====================================================================================================
+private:
template
void _push_front(ArgsT&&...args) {
elem_t next = _first;
@@ -337,6 +418,22 @@ private:
}
++_size;
}
+
+
+// Private Definitions =================================================================================================
+private:
+ struct node {
+ value_t value;
+ node *prev, *next;
+
+ template
+ node(node* prev, node* next, ArgsT&&...args)
+ : value(fennec::forward(args)...)
+ , prev(prev), next(next) {
+ }
+
+ ~node() = default;
+ };
};
diff --git a/include/fennec/containers/dynarray.h b/include/fennec/containers/dynarray.h
index 4c82379..8753697 100644
--- a/include/fennec/containers/dynarray.h
+++ b/include/fennec/containers/dynarray.h
@@ -56,6 +56,7 @@ namespace fennec
/// | find | \f$O(N)\f$ |
/// | insertion | \f$O(N)\f$ |
/// | deletion | \f$O(N)\f$ |
+/// | space | \f$O(N)\f$ |
///
/// This structure prefers shallow moves and deep copies.
///
@@ -65,8 +66,14 @@ struct dynarray {
// Definitions =========================================================================================================
public:
- using value_t = TypeT; ///< Alias for the value type
- using alloc_t = Alloc; ///< Alias for the allocator type
+
+ /// \name Definitions
+ /// @{
+
+ using value_t = TypeT; //!< Alias for the value type
+ using alloc_t = Alloc; //!< Alias for the allocator type
+
+ /// @}
// Constructors ========================================================================================================
@@ -77,6 +84,10 @@ public:
///
/// \brief Default Constructor, initializes an empty allocation.
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr dynarray()
: _alloc(8)
, _size(0) {
@@ -86,16 +97,11 @@ public:
/// \brief Alloc Constructor, initialize empty allocation with allocator instance.
/// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
/// data.
- explicit constexpr dynarray(const alloc_t& alloc)
- : _alloc(8, alloc)
- , _size(0) {
- }
-
///
- /// \brief Alloc Move Constructor, initialize empty allocation with allocator instance.
- /// \param alloc An allocator object to copy, for instances where the allocator needs to be initialized with some
- /// data.
- explicit constexpr dynarray(alloc_t&& alloc) noexcept
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ explicit constexpr dynarray(const alloc_t& alloc)
: _alloc(8, alloc)
, _size(0) {
}
@@ -103,6 +109,10 @@ public:
///
/// \brief Sized Allocation, initializes a dynarray with \f$n\f$ elements using the default constructor.
/// \param n The number of elements.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
explicit constexpr dynarray(size_t n)
: _alloc(n)
, _size(n)
@@ -118,21 +128,11 @@ public:
/// using the default constructor.
/// \param n The number of elements
/// \param alloc The allocator object to copy
- constexpr dynarray(size_t n, const alloc_t& alloc)
- : _alloc(n, alloc)
- , _size(n) {
- value_t* addr = _alloc.data();
- for(; n > 0; --n, ++addr) {
- fennec::construct(addr);
- }
- }
-
///
- /// \brief Sized Allocation Alloc Move Constructor, initializes a dynarray with allocator \f$alloc\f$ and \f$n\f$ elements
- /// using the default constructor.
- /// \param n The number of elements
- /// \param alloc The allocator object to copy
- constexpr dynarray(size_t n, alloc_t&& alloc)
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
+ constexpr dynarray(size_t n, const alloc_t& alloc)
: _alloc(n, alloc)
, _size(n) {
value_t* addr = _alloc.data();
@@ -146,6 +146,10 @@ public:
/// constructed using the copy constructor
/// \param n the number of elements
/// \param val the value to copy
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr dynarray(size_t n, const TypeT& val)
: _alloc(n)
, _size(n) {
@@ -155,15 +159,15 @@ public:
}
}
- // This constructor should not be invokable since moving is a single object operation and will cause undefined
- // behaviour when moving to multiple elements
- constexpr dynarray(size_t n, TypeT&& val) = delete;
-
///
/// \brief Emplace Constructor
/// \tparam ArgsT A sequence of argument types
/// \param n The number of objects to create
/// \param args The arguments to create each object with
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr explicit dynarray(size_t n, ArgsT&&...args)
: _alloc(n)
@@ -177,6 +181,10 @@ public:
/// \brief Array Copy Constructor
/// \tparam N The length of the array, automatically deduced
/// \param arr The array to copy
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr dynarray(const TypeT (&arr)[N])
: _alloc(N)
@@ -190,6 +198,10 @@ public:
/// \brief Array Move Constructor
/// \tparam N The length of the array, automatically deduced
/// \param arr The array to move
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr dynarray(TypeT (&&arr)[N])
: _alloc(N)
@@ -204,6 +216,10 @@ public:
/// \tparam OTypeT The other value type
/// \tparam OAlloc The other allocator type
/// \param conv The dynarray to convert
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr dynarray(const dynarray& conv)
: _alloc(conv.size())
@@ -218,6 +234,10 @@ public:
/// \brief Initializer List Constructor
/// \param l List of elements to initialize with
/// \param alloc An allocator object to copy
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr dynarray(initializer_list l, const alloc_t& alloc = alloc_t())
: _alloc(l.size(), alloc)
, _size(l.size()) {
@@ -230,6 +250,10 @@ public:
///
/// \brief Copy Constructor, uses the copy constructor to copy each element
/// \param arr the dynarray to copy
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr dynarray(const dynarray& arr)
: _alloc(arr._size)
, _size(arr._size) {
@@ -241,6 +265,10 @@ public:
///
/// \brief Move Constructor, takes ownership of the allocation
/// \param arr the dynarray to move
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr dynarray(dynarray&& arr) noexcept
: _alloc(fennec::move(arr._alloc))
, _size(arr._size) {
@@ -249,6 +277,10 @@ public:
///
/// \brief Default Destructor, destructs all elements and frees the underlying allocation
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr ~dynarray() {
value_t* addr = _alloc.data();
if (addr == nullptr) return;
@@ -259,6 +291,13 @@ public:
/// @}
+
+private:
+ // This constructor should not be invokable since moving is a single object operation and will cause undefined
+ // behaviour when moving to multiple elements
+ constexpr dynarray(size_t n, TypeT&& val) = delete;
+
+
// Assignment ==========================================================================================================
public:
@@ -269,9 +308,13 @@ public:
/// \brief Copy Assignment Operator
/// \param arr the array to copy
/// \returns A dynarray after having copied each element of \f$arr\f$
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr dynarray& operator=(const dynarray& arr) {
this->clear();
- _alloc.creallocate(_size = arr._size);
+ _alloc.reallocate(_size = arr._size);
for (size_t i = 0; i < _size; ++i) {
fennec::construct(&_alloc[i], fennec::copy(arr[i]));
}
@@ -282,6 +325,10 @@ public:
/// \brief Move Assignment Operator
/// \param arr the array to move
/// \returns A dynarray after having taken ownership of the contents of \f$arr\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr dynarray& operator=(dynarray&& arr) noexcept {
this->clear();
_alloc = fennec::move(arr._alloc);
@@ -295,10 +342,14 @@ public:
/// \tparam N the length of the array
/// \param arr the array to copy
/// \returns A dynarray after having copied each element of \f$arr\f$
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr dynarray& operator=(const TypeT (&arr)[N]) {
this->clear();
- _alloc.creallocate(_size = N);
+ _alloc.reallocate(_size = N);
for (size_t i = 0; i < _size; ++i) {
fennec::construct(&_alloc[i], fennec::copy(arr[i]));
}
@@ -310,10 +361,14 @@ public:
/// \tparam N the length of the array
/// \param arr the array to copy
/// \returns A dynarray after having moved each element of \f$arr\f$
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr dynarray& operator=(TypeT (&&arr)[N]) {
this->clear();
- _alloc.creallocate(_size = N);
+ _alloc.reallocate(_size = N);
for (size_t i = 0; i < _size; ++i) {
fennec::construct(&_alloc[i], fennec::move(arr[i]));
}
@@ -330,18 +385,30 @@ public:
///
/// \returns The size of the dynarray in elements
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t size() const {
return _size;
}
///
/// \returns The current capacity, in elements, of the underlying allocation
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr size_t capacity() const {
return _alloc.capacity();
}
///
/// \returns True when there are no elements active, otherwise false
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr bool is_empty() const {
return _size == 0;
}
@@ -359,6 +426,10 @@ public:
/// \brief Array Access Operator
/// \param i The index to access
/// \returns A reference to the element at index \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr TypeT& operator[](size_t i) {
assertd(i < _size, "Array Out of Bounds");
return _alloc[i];
@@ -368,6 +439,10 @@ public:
/// \brief Array Access Operator (const)
/// \param i The index to access
/// \returns A const qualified reference to the element at index \f$i\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const TypeT& operator[](size_t i) const {
assertd(i < _size, "Array Out of Bounds");
return _alloc[i];
@@ -375,36 +450,60 @@ public:
///
/// \returns Reference to the first element in the dynarray
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr TypeT& front() {
return this->operator[](0);
}
///
/// \returns A const-qualified reference to the first element in the dynarray
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const TypeT& front() const {
return this->operator[](0);
}
///
/// \returns A reference to the last element in the dynarray
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr TypeT& back() {
return this->operator[](size() - 1);
}
///
/// \returns A const-qualified reference to the last element in the dynarray
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const TypeT& back() const {
return this->operator[](size() - 1);
}
///
/// \returns A pointer to the underlying allocation
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr TypeT* data() {
return _alloc.data();
}
///
/// \returns A pointer to the underlying allocation
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const TypeT* data() const {
return _alloc.data();
}
@@ -422,6 +521,10 @@ public:
/// \brief Move Insertion
/// \param i index to insert at
/// \param val the value to initialize with
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void insert(size_t i, TypeT&& val) {
// Grow if the size has reached the capacity of the allocation
@@ -446,6 +549,10 @@ public:
/// \brief Copy Insertion
/// \param i index to insert at
/// \param val the value to initialize with
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void insert(size_t i, const TypeT& val) {
// Grow if the size has reached the capacity of the allocation
@@ -472,6 +579,10 @@ public:
/// \param i index to insert at
/// \param args Arguments to construct with
/// \tparam ArgsT Argument types
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
template
constexpr void emplace(size_t i, ArgsT&&...args) {
@@ -496,6 +607,10 @@ public:
///
/// \brief Push Back Copy
/// \param val Value to initialize with
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr void push_back(const TypeT& val) {
dynarray::insert(_size, val);
}
@@ -503,6 +618,10 @@ public:
///
/// \brief Push Back Move
/// \param val Value to initialize with
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr void push_back(TypeT&& val) {
dynarray::insert(_size, fennec::forward(val));
}
@@ -511,6 +630,10 @@ public:
/// \brief Emplace Back
/// \tparam ArgsT Argument Types
/// \param args Arguments to construct with
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
constexpr void emplace_back(ArgsT...args) {
dynarray::emplace(_size, fennec::forward(args)...);
@@ -518,6 +641,10 @@ public:
///
/// \brief Erase last element
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr void pop_back() {
fennec::destruct(&_alloc[--_size]);
}
@@ -525,9 +652,15 @@ public:
///
/// \brief Resize the dynarray, invoking the default constructor for all new elements
/// \param n The new size in elements
+ ///
+ /// \details if \f$n\f$ is less than the current size, any elements that would be removed are destructed
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void resize(size_t n) {
_reduce(n);
- _alloc.creallocate(n);
+ _alloc.reallocate(n);
for (size_t i = _size; i < n; ++i) {
fennec::construct(&_alloc[i]);
@@ -542,9 +675,13 @@ public:
/// \param val The value to fill with
///
/// \details if \f$n\f$ is less than the current size, any elements that would be removed are destructed
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void resize(size_t n, const TypeT& val) {
_reduce(n);
- _alloc.creallocate(n);
+ _alloc.reallocate(n);
for (size_t i = _size; i < n; ++i) {
fennec::construct(&_alloc[i], val);
@@ -558,13 +695,21 @@ public:
/// \param n The new capacity in elements
///
/// \details if \f$n\f$ is less than the current size, any elements that would be removed are destructed
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void reserve(size_t n) {
_reduce(n);
- _alloc.creallocate(n);
+ _alloc.reallocate(n);
}
///
/// \brief Clears the contents of the dynarray, destructing all elements and releasing the allocation.
+ ///
+ /// \par Complexity
+ /// \f$O(N)\f$
+ ///
constexpr void clear() {
_reduce(0);
_alloc.deallocate();
@@ -581,26 +726,42 @@ public:
///
/// \returns A pointer to the first element in the dynarray
- constexpr TypeT* begin() { return _alloc.data(); }
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ constexpr TypeT* begin() { return _alloc; }
///
/// \brief C++ Iterator Specification \f$begin()\f$
/// \returns A const qualified pointer to the first element in the dynarray
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
constexpr const TypeT* begin() const { return _alloc; }
///
/// \return A pointer to the address after the last element in the dynarray
- constexpr TypeT* end() { return begin() + _size; }
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ constexpr TypeT* end() { return begin() + _size; }
///
/// \brief C++ Iterator Specification \f$end()\f$
/// \return A const qualified pointer to the address after the last element in the dynarray
- constexpr const TypeT* end() const { return begin() + _size; }
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
+ constexpr const TypeT* end() const { return begin() + _size; }
/// @}
-// Private Members =====================================================================================================
+// Public Member Variables =============================================================================================
private:
allocation _alloc;
size_t _size;
@@ -611,7 +772,7 @@ private:
// helper to double the capacity of the allocation
constexpr void _grow() {
- _alloc.creallocate(_alloc.capacity() * 2);
+ _alloc.reallocate(_alloc.capacity() * 2);
}
// helper to destruct elements past n
diff --git a/include/fennec/containers/generic.h b/include/fennec/containers/generic.h
index df26742..ad55500 100644
--- a/include/fennec/containers/generic.h
+++ b/include/fennec/containers/generic.h
@@ -53,6 +53,7 @@ namespace fennec
/// | find | ⛔ |
/// | insertion | \f$O(1)\f$ |
/// | deletion | \f$O(1)\f$ |
+/// | space | \f$O(1)\f$ |
struct generic {
// Definitions =========================================================================================================
@@ -68,11 +69,18 @@ private:
using manager_t = void* (*)(uint8_t, void*);
-// Constructors ========================================================================================================
+// Constructors & Destructor ===========================================================================================
public:
+ /// \name Constructors & Destructor
+ /// @{
+
///
/// \brief Default Constructor
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
generic()
: _handle(nullptr)
, _manage(nullptr) {
@@ -81,6 +89,10 @@ public:
///
/// \brief Copy Constructor
/// \param gen The generic object to copy
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
generic(const generic& gen)
: _handle(nullptr)
, _manage(gen._manage) {
@@ -92,6 +104,10 @@ public:
///
/// \brief Move Constructor
/// \param gen The generic object to move
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
generic(generic&& gen)
: _handle(gen._handle)
, _manage(gen._manage) {
@@ -103,6 +119,10 @@ public:
/// \brief Value Constructor
/// \tparam T The type of the value
/// \param x The value
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
generic(T&& x)
: _handle(new T(fennec::forward(x)))
@@ -114,6 +134,10 @@ public:
/// \tparam T The type to construct
/// \tparam ArgsT The argument types
/// \param args The argument values
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
generic(type_identity, ArgsT&&...args)
: _handle(new T(fennec::forward(args)...))
@@ -126,31 +150,53 @@ public:
reset();
}
+ /// @}
+
// Properties ==========================================================================================================
public:
+ /// \name Properties
+ /// @{
+
///
/// \brief runtime type acquisition
/// \returns a runtime type struct referencing the held type
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
type type() const {
return *static_cast(_manage(op_type, nullptr));
}
///
/// \returns \f$true\f$ if there is a held value, \f$false\f$ otherwise
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
bool has_value() const {
return _handle != nullptr;
}
+ /// @}
+
// Assignment ==========================================================================================================
public:
+ /// \name Assignment Operators
+ /// @{
+
///
/// \brief copy assignment
/// \param gen the generic to copy
/// \returns a reference to self after copying the contents of \f$gen\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
generic& operator=(const generic& gen) {
if (this == &gen) { // self-assignment case
return *this;
@@ -166,6 +212,10 @@ public:
/// \brief move assignment
/// \param gen the generic to move
/// \returns a reference to self after swapping contents with \f$gen\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
generic& operator=(generic&& gen) noexcept {
swap(gen);
return *this;
@@ -176,6 +226,10 @@ public:
/// \tparam T the type of the value
/// \param x the value to assign
/// \returns a reference to self after having assigned \f$x\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
generic& operator=(T&& x) {
reset();
@@ -184,17 +238,26 @@ public:
return *this;
}
+ /// @}
-// Insertion & Deletion ================================================================================================
+
+// Modifiers ===========================================================================================================
public:
+ /// \name Modifiers
+ /// @{
+
///
/// \brief emplace value
///
- /// \details constructs a new value of type \f$T\f$ using \f$args...\f$
+ /// \details constructs a new value of type \f$T\f$ using \f$args\ldots\f$
/// \tparam T the type to construct
/// \tparam ArgsT the argument types
/// \param args the argument values
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template
void emplace(ArgsT&&...args) {
reset();
@@ -205,6 +268,10 @@ public:
///
/// \brief reset value
/// \details clears the held value using the appropriate destructor
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void reset() {
if (_manage) {
_handle = _manage(op_destroy, _handle);
@@ -212,24 +279,37 @@ public:
}
}
-
-// Utility =============================================================================================================
-public:
-
///
/// \brief C++ 11 Swap Specification
/// \param gen the generic to swap with
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
void swap(generic& gen) noexcept {
fennec::swap(_handle, gen._handle);
fennec::swap(_manage, gen._manage);
}
+ /// @}
+
+
+// Casting =============================================================================================================
+public:
+
+ /// \name Casting
+ /// @{
+
///
/// \brief cast value
///
/// \details equivalent to \f$reinterpret_cast\f$
/// \tparam T The type to cast to
/// \returns The contents of generic after having cast to \f$T\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template>
T cast() {
return static_cast(*static_cast(_handle));
@@ -239,19 +319,25 @@ public:
/// \details equivalent to \f$reinterpret_cast\f$
/// \tparam T The type to cast to
/// \returns The contents of generic after having cast to \f$T\f$
+ ///
+ /// \par Complexity
+ /// \f$O(1)\f$
+ ///
template>
T cast() const {
return static_cast(*static_cast(_handle));
}
+ /// @}
-// Members =============================================================================================================
+
+// Private Member Variables ============================================================================================
private:
void* _handle;
manager_t _manage;
-// Helpers =============================================================================================================
+// Private Helpers =====================================================================================================
private:
template
static void* _manage_impl(uint8_t op, void* hnd) {
diff --git a/include/fennec/containers/graph.h b/include/fennec/containers/graph.h
index d799852..d9f87f3 100644
--- a/include/fennec/containers/graph.h
+++ b/include/fennec/containers/graph.h
@@ -55,19 +55,20 @@ namespace fennec
/// \brief Graph Data Structure, describes sets of arbitrarily connected vertices
///
/// \details
-/// | Property | Value |
-/// |:-----------:|:----------:|
-/// | stable | ⛔ |
-/// | dynamic | ✅ |
-/// | homogeneous | ✅ |
-/// | distinct | ⛔ |
-/// | ordered | ⛔ |
-/// | space | \f$O(N)\f$ |
-/// | linear | ✅ |
-/// | access | \f$O(1)\f$ |
-/// | find | \f$O(1)\f$ |
-/// | insertion | \f$O(1)\f$ |
-/// | deletion | \f$O(M)\f$ |
+/// | Property | Value |
+/// |:-----------:|:--------------:|
+/// | stable | ⛔ |
+/// | dynamic | ✅ |
+/// | homogeneous | ✅ |
+/// | distinct | ⛔ |
+/// | ordered | ⛔ |
+/// | space | \f$O(N)\f$ |
+/// | linear | ✅ |
+/// | access | \f$O(1)\f$ |
+/// | find | \f$O(1)\f$ |
+/// | insertion | \f$O(1)\f$ |
+/// | deletion | \f$O(M)\f$ |
+/// | space | \f$O(N + M)\f$ |
///
/// Graphs contain vertices and edges. Graphs are either directed
/// or undirected. This structure allows the creation of both directed and undirected edges. As
@@ -92,13 +93,24 @@ struct graph {
public:
// Definitions =========================================================================================================
- using edge_t = EdgeT; ///< Alias for the edge type
- using vertex_t = VertexT; ///< Alias for the vertex type
- using vertex_pool_t = object_pool; ///< Alias for a pool of vertices
- using edge_map_t = dynarray