- Rough First Pass implementation for format.h
- Started 2D Transform Component and relevant math extensions - Switched sequence to use pointers instead of arrays
This commit is contained in:
@@ -244,6 +244,8 @@ add_library(fennec STATIC
|
|||||||
# EXTRA SOURCES ========================================================================================================
|
# EXTRA SOURCES ========================================================================================================
|
||||||
|
|
||||||
${FENNEC_EXTRA_SOURCES}
|
${FENNEC_EXTRA_SOURCES}
|
||||||
|
include/fennec/langproc/strings/format.h
|
||||||
|
include/fennec/scene/components/transform2d.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_dependencies(fennec metaprogramming fennec-dependencies)
|
add_dependencies(fennec metaprogramming fennec-dependencies)
|
||||||
|
|||||||
@@ -524,6 +524,65 @@ class BinTreePrinter:
|
|||||||
return self.Iterator(self.tree, self.root, self.capacity)
|
return self.Iterator(self.tree, self.root, self.capacity)
|
||||||
|
|
||||||
|
|
||||||
|
# SEQUENCE =============================================================================================================
|
||||||
|
|
||||||
|
class SequencePrinter:
|
||||||
|
"""Print a fennec::sequence"""
|
||||||
|
|
||||||
|
class Iterator:
|
||||||
|
def __init__(self, node):
|
||||||
|
self.visit = deque()
|
||||||
|
|
||||||
|
if node is not None:
|
||||||
|
self.visit.append((node, 0, 0))
|
||||||
|
|
||||||
|
def __iter__(self):
|
||||||
|
return self
|
||||||
|
|
||||||
|
def __next__(self):
|
||||||
|
if len(self.visit) == 0:
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
node = self.visit[0][0]
|
||||||
|
i = self.visit[0][1]
|
||||||
|
depth = self.visit[0][2]
|
||||||
|
self.visit.popleft()
|
||||||
|
|
||||||
|
value = node['key']
|
||||||
|
left = node['child'][0]
|
||||||
|
right = node['child'][1]
|
||||||
|
print("it: ", node, " ", left, " ", right);
|
||||||
|
|
||||||
|
if right != 0:
|
||||||
|
self.visit.appendleft((right, 1, depth + 1))
|
||||||
|
if left != 0:
|
||||||
|
self.visit.appendleft((left, 0, depth + 1))
|
||||||
|
|
||||||
|
index = '⠀' * depth * 2 # Uses Braille Space, otherwise it would get eaten as whitespace by parsers
|
||||||
|
if i == 0:
|
||||||
|
index += '├'
|
||||||
|
else:
|
||||||
|
index += '└'
|
||||||
|
|
||||||
|
index += '─'
|
||||||
|
index += '[{}]'.format(node)
|
||||||
|
return index, value
|
||||||
|
|
||||||
|
|
||||||
|
def __init__(self, val):
|
||||||
|
self.size = val['_size']
|
||||||
|
self.root = val['_root']
|
||||||
|
|
||||||
|
def to_string(self):
|
||||||
|
if self.size == 0:
|
||||||
|
return "{ empty }"
|
||||||
|
return "{ size = " + str(self.size) + " }"
|
||||||
|
|
||||||
|
def children(self):
|
||||||
|
print("root: ", self.root)
|
||||||
|
return self.Iterator(self.root)
|
||||||
|
|
||||||
|
|
||||||
# Graph ================================================================================================================
|
# Graph ================================================================================================================
|
||||||
|
|
||||||
class GraphPrinter:
|
class GraphPrinter:
|
||||||
@@ -611,7 +670,7 @@ def register_printers():
|
|||||||
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
|
pp.add_printer('fennec::set', '^fennec::set<.*>$', SetPrinter)
|
||||||
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
|
pp.add_printer('fennec::rdtree', '^fennec::rdtree<.*>$', RDTreePrinter)
|
||||||
pp.add_printer('fennec::bintree', '^fennec::bintree<.*>$', BinTreePrinter)
|
pp.add_printer('fennec::bintree', '^fennec::bintree<.*>$', BinTreePrinter)
|
||||||
pp.add_printer('fennec::sequence', '^fennec::sequence<.*>$', BinTreePrinter)
|
pp.add_printer('fennec::sequence', '^fennec::sequence<.*>$', SequencePrinter)
|
||||||
pp.add_printer('fennec::priority_queue', '^fennec::priority_queue<.*>$', PriorityQueuePrinter)
|
pp.add_printer('fennec::priority_queue', '^fennec::priority_queue<.*>$', PriorityQueuePrinter)
|
||||||
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
|
pp.add_printer('fennec::tuple', '^fennec::tuple<.*>$', TuplePrinter)
|
||||||
return pp
|
return pp
|
||||||
|
|||||||
@@ -38,6 +38,8 @@
|
|||||||
#include <fennec/math/exponential.h>
|
#include <fennec/math/exponential.h>
|
||||||
#include <fennec/memory/allocator.h>
|
#include <fennec/memory/allocator.h>
|
||||||
|
|
||||||
|
// TODO: this should probably be refactored to use pointers over tables
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -579,8 +581,8 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct in_order {
|
struct in_order {
|
||||||
size_t head;
|
|
||||||
list<size_t> visit;
|
list<size_t> visit;
|
||||||
|
size_t head;
|
||||||
|
|
||||||
constexpr size_t operator()(const bintree& tree, size_t start) {
|
constexpr size_t operator()(const bintree& tree, size_t start) {
|
||||||
head = start;
|
head = start;
|
||||||
@@ -683,8 +685,9 @@ public:
|
|||||||
|
|
||||||
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(root)
|
, _order()
|
||||||
, _n(node) {
|
, _n(node) {
|
||||||
|
_order.head = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t index() const {
|
size_t index() const {
|
||||||
|
|||||||
@@ -445,10 +445,7 @@ public:
|
|||||||
|
|
||||||
// prefix operator
|
// prefix operator
|
||||||
constexpr friend iterator& operator++(iterator& rhs) {
|
constexpr friend iterator& operator++(iterator& rhs) {
|
||||||
if (rhs._list->_next(rhs._n) < rhs._list->capacity()) {
|
rhs._n = rhs._list->_next(rhs._n);
|
||||||
return rhs;
|
|
||||||
}
|
|
||||||
rhs._n = npos;
|
|
||||||
return rhs;
|
return rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,9 @@
|
|||||||
#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/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>
|
||||||
|
|
||||||
@@ -47,6 +50,9 @@
|
|||||||
// but now in the higher end it remains consistent. Something I was doing was disturbing both the rb-tree and bst tree
|
// but now in the higher end it remains consistent. Something I was doing was disturbing both the rb-tree and bst tree
|
||||||
// properties, now that is fixed. I'll see about optimizing more in the future.
|
// properties, now that is fixed. I'll see about optimizing more in the future.
|
||||||
|
|
||||||
|
// I realized that the way bintree is setup makes some insert calls O(n + log n) = O(n), so I switched to a pointer based model.
|
||||||
|
// This increased performance overall maintaining O(log n).
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
@@ -74,50 +80,138 @@ namespace fennec
|
|||||||
/// \tparam CompareT Function for comparing two values
|
/// \tparam CompareT Function for comparing two values
|
||||||
/// \tparam AllocT An allocator class
|
/// \tparam AllocT An allocator class
|
||||||
template<typename TypeT, typename CompareT = less<TypeT>, class AllocT = allocator<pair<TypeT, bool>>>
|
template<typename TypeT, typename CompareT = less<TypeT>, class AllocT = allocator<pair<TypeT, bool>>>
|
||||||
struct sequence : protected bintree<pair<TypeT, bool>, AllocT> {
|
struct sequence {
|
||||||
|
|
||||||
// Definitions =========================================================================================================
|
// Definitions =========================================================================================================
|
||||||
protected:
|
protected:
|
||||||
struct node;
|
struct _node;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using value_t = TypeT;
|
using value_t = TypeT;
|
||||||
using node_t = pair<TypeT, bool>;
|
using node_t = pair<TypeT, bool>;
|
||||||
using alloc_t = allocator_traits<AllocT>::template rebind<node>;
|
using alloc_t = allocator_traits<AllocT>::template rebind<_node>;
|
||||||
using base_t = bintree<pair<TypeT, bool>, AllocT>;
|
|
||||||
using compare_t = CompareT;
|
using compare_t = CompareT;
|
||||||
static constexpr size_t npos = -1;
|
|
||||||
|
|
||||||
enum color_ : bool {
|
enum color_ : bool {
|
||||||
black = false,
|
black = false,
|
||||||
red = true,
|
red = true,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum dir_ : bool {
|
||||||
|
dir_left = false,
|
||||||
|
dir_right = true,
|
||||||
|
};
|
||||||
|
|
||||||
class iterator;
|
class iterator;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
using typename base_t::in_order;
|
using node = _node*;
|
||||||
|
|
||||||
using base_t::left;
|
struct _node {
|
||||||
using base_t::right;
|
node parent;
|
||||||
using base_t::child;
|
node child[2];
|
||||||
using base_t::direction;
|
value_t key;
|
||||||
using base_t::parent;
|
bool color;
|
||||||
using base_t::grandparent;
|
|
||||||
using base_t::sibling;
|
|
||||||
|
|
||||||
using base_t::left_most;
|
template<typename...ArgsT>
|
||||||
using base_t::right_most;
|
constexpr _node(ArgsT&&...args)
|
||||||
|
: parent(nullptr)
|
||||||
|
, child { nullptr, nullptr }
|
||||||
|
, key(fennec::forward<ArgsT>(args)...)
|
||||||
|
, color(red) {
|
||||||
|
}
|
||||||
|
|
||||||
using base_t::emplace_left;
|
template<typename...ArgsT>
|
||||||
using base_t::emplace_right;
|
constexpr _node(node p, node l, node r, ArgsT&&...args)
|
||||||
|
: parent(p)
|
||||||
|
, child { l, r }
|
||||||
|
, key(fennec::forward<ArgsT>(args)...)
|
||||||
|
, color(red) {
|
||||||
|
}
|
||||||
|
|
||||||
using base_t::rotate;
|
constexpr ~_node() {
|
||||||
|
parent = nullptr;
|
||||||
|
child[0] = nullptr;
|
||||||
|
child[1] = nullptr;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
using base_t::_table;
|
|
||||||
using base_t::_freed;
|
// Member Access Helpers
|
||||||
using base_t::_root;
|
|
||||||
using base_t::_size;
|
constexpr value_t& _key(node n) {
|
||||||
|
return n->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool& _color(node n) {
|
||||||
|
return n->color;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node& _parent(node n) {
|
||||||
|
return n->parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node& _child(node n, bool dir) {
|
||||||
|
return n->child[dir];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node& _left(node n) {
|
||||||
|
return n->child[dir_left];
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node& _right(node n) {
|
||||||
|
return n->child[dir_right];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Safe Member Access Helpers
|
||||||
|
|
||||||
|
|
||||||
|
constexpr const value_t& key(node n) const {
|
||||||
|
return n->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool color(node n) {
|
||||||
|
return n ? n->color : (bool)black;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node parent(node n) {
|
||||||
|
return n ? n->parent : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node child(node n, bool dir) {
|
||||||
|
return n ? n->child[dir] : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node left(node n) {
|
||||||
|
return n ? n->child[dir_left] : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node right(node n) {
|
||||||
|
return n ? n->child[dir_right] : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node leftmost(node n) {
|
||||||
|
if (n == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this->_left(n)) {
|
||||||
|
n = this->_left(n);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr node rightmost(node n) {
|
||||||
|
if (n == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (this->_right(n)) {
|
||||||
|
n = this->_right(n);
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
// Constructors & Destructors ==========================================================================================
|
// Constructors & Destructors ==========================================================================================
|
||||||
public:
|
public:
|
||||||
@@ -126,7 +220,9 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Default Constructor, initializes an empty sequence
|
/// \brief Default Constructor, initializes an empty sequence
|
||||||
constexpr sequence() = default;
|
constexpr sequence()
|
||||||
|
: _root(nullptr), _size(0) {
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Move Constructor, takes ownership of a sequence
|
/// \brief Move Constructor, takes ownership of a sequence
|
||||||
@@ -154,11 +250,11 @@ public:
|
|||||||
/// \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) {
|
||||||
size_t node = _root;
|
node node = _root;
|
||||||
while (node != npos) {
|
while (node) {
|
||||||
if (_compare(val, _value(node))) {
|
if (_compare(val, _key(node))) {
|
||||||
node = _left(node);
|
node = _left(node);
|
||||||
} else if (_compare(_value(node), val)) {
|
} else if (_compare(_key(node), val)) {
|
||||||
node = _right(node);
|
node = _right(node);
|
||||||
} else {
|
} else {
|
||||||
return sequence::iterator(this, _root, node);
|
return sequence::iterator(this, _root, node);
|
||||||
@@ -185,15 +281,15 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \returns The number of elements in the sequence
|
/// \returns The number of elements in the sequence
|
||||||
using base_t::size;
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
///
|
}
|
||||||
/// \returns The capacity of the underlying allocation
|
|
||||||
using base_t::capacity;
|
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \returns `true` when there are no elements in the sequence, `false` otherwise.
|
/// \returns `true` when there are no elements in the sequence, `false` otherwise.
|
||||||
using base_t::empty;
|
constexpr bool empty() const {
|
||||||
|
return _size == 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
@@ -206,7 +302,7 @@ public:
|
|||||||
/// \brief Move Insertion, moves `val` into the sequence
|
/// \brief Move Insertion, moves `val` 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) {
|
||||||
size_t i = _insert_bst(fennec::forward<value_t>(val));
|
node i = _insert_bst(fennec::forward<value_t>(val));
|
||||||
_fix_insert(i);
|
_fix_insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -214,7 +310,7 @@ public:
|
|||||||
/// \brief Copy Insertion, inserts a copy of `val` into the sequence
|
/// \brief Copy Insertion, inserts a copy of `val` 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) {
|
||||||
size_t i = _insert_bst(val);
|
node i = _insert_bst(val);
|
||||||
_fix_insert(i);
|
_fix_insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -224,24 +320,25 @@ public:
|
|||||||
/// \param args The arguments to construct with
|
/// \param args The arguments to construct with
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr void emplace(ArgsT&&...args) {
|
constexpr void emplace(ArgsT&&...args) {
|
||||||
size_t i = _insert_bst(fennec::forward<ArgsT>(args)...);
|
node i = _insert_bst(fennec::forward<ArgsT>(args)...);
|
||||||
_fix_insert(i);
|
_fix_insert(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void erase(const value_t& val) {
|
constexpr void erase(const value_t& val) {
|
||||||
_erase(find(val).index());
|
_erase(find(val)._node);
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Destructs all elements, *in-order*, contained in the sequence
|
/// \brief Destructs all elements, *in-order*, contained in the sequence
|
||||||
constexpr void clear() {
|
constexpr void clear() {
|
||||||
in_order order;
|
list<node> visit;
|
||||||
size_t node = order(*this, _root);
|
for (iterator it = begin(); it != end(); ++it) {
|
||||||
while (node != npos) {
|
visit.push_back(it._node);
|
||||||
size_t erase = node;
|
|
||||||
node = order[*this, node, traversal_control_continue];
|
|
||||||
fennec::destruct(&_table[erase]);
|
|
||||||
}
|
}
|
||||||
|
for (node n : visit) {
|
||||||
|
_free_node(n);
|
||||||
|
}
|
||||||
|
_root = nullptr;
|
||||||
_size = 0;
|
_size = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,67 +355,127 @@ public:
|
|||||||
///
|
///
|
||||||
/// \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, npos);
|
return sequence::iterator(this, _root, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
class iterator : public base_t::iterator {
|
class iterator {
|
||||||
protected:
|
protected:
|
||||||
using base_t::iterator::_n;
|
sequence* _seq;
|
||||||
using base_t::iterator::_tree;
|
node _head;
|
||||||
|
node _node;
|
||||||
|
list<node> _visit;
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using base_t::iterator::iterator;
|
constexpr iterator(sequence* seq, node start)
|
||||||
|
: _seq(seq)
|
||||||
|
, _head(start)
|
||||||
|
, _node(seq->leftmost(start)) {
|
||||||
|
}
|
||||||
|
|
||||||
value_t& operator*() {
|
constexpr iterator(sequence* seq, node root, node start)
|
||||||
return base_t::iterator::operator*().first;
|
: _seq(seq)
|
||||||
|
, _head(root)
|
||||||
|
, _node(start) {
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator++() {
|
||||||
|
if (_node == nullptr) {
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
node parent = _seq->_parent(_node);
|
||||||
|
node pright = _seq->right(parent);
|
||||||
|
node next = _seq->leftmost(_seq->right(_node));
|
||||||
|
|
||||||
|
if (_node != pright && parent != nullptr) {
|
||||||
|
_visit.push_front(parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (next != nullptr) {
|
||||||
|
_visit.push_front(next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (not _visit.empty()) {
|
||||||
|
_node = _visit.front();
|
||||||
|
_visit.pop_front();
|
||||||
|
} else {
|
||||||
|
_node = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int) {
|
||||||
|
iterator prev = *this;
|
||||||
|
this->operator++();
|
||||||
|
return prev;
|
||||||
}
|
}
|
||||||
|
|
||||||
const value_t& operator*() const {
|
const value_t& operator*() const {
|
||||||
return base_t::iterator::operator*().first;
|
return _node->key;
|
||||||
}
|
|
||||||
|
|
||||||
value_t* operator->() {
|
|
||||||
return &base_t::iterator::operator*().first;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const value_t* operator->() const {
|
const value_t* operator->() const {
|
||||||
return &base_t::iterator::operator*().firstf;
|
return &_node->key;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr friend bool operator==(const iterator& lhs, const iterator& rhs) {
|
||||||
|
return lhs._node == rhs._node;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend struct sequence;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Fields ==============================================================================================================
|
// Fields ==============================================================================================================
|
||||||
protected:
|
protected:
|
||||||
|
alloc_t _alloc;
|
||||||
|
node _root;
|
||||||
compare_t _compare;
|
compare_t _compare;
|
||||||
inline static bool color_sink = red;
|
size_t _size;
|
||||||
inline static value_t value_sink;
|
|
||||||
|
|
||||||
// Helpers =============================================================================================================
|
// Helpers =============================================================================================================
|
||||||
protected:
|
protected:
|
||||||
using base_t::_left;
|
|
||||||
using base_t::_right;
|
|
||||||
using base_t::_parent;
|
|
||||||
using base_t::_child;
|
|
||||||
|
|
||||||
constexpr value_t& _value(size_t i) {
|
template<typename...ArgsT>
|
||||||
return _table[i].value.first;
|
constexpr node _make_node(ArgsT&&...args) {
|
||||||
|
node res = _alloc.allocate(1);
|
||||||
|
fennec::construct(res, fennec::forward<ArgsT>(args)...);
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const value_t& _value(size_t i) const {
|
constexpr void _free_node(node n) {
|
||||||
return _table[i].value.first;
|
fennec::destruct(n);
|
||||||
|
_alloc.deallocate(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool& _color(size_t i) {
|
constexpr node _rotate(node sub, bool dir) {
|
||||||
return _table[i].value.second;
|
if (sub == nullptr) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
node sub_parent = _parent(sub);
|
||||||
|
node new_root = _child(sub, not dir);
|
||||||
|
node new_child = _child(new_root, dir);
|
||||||
|
|
||||||
|
_child(sub, not dir) = new_child;
|
||||||
|
if (new_child != nullptr) {
|
||||||
|
_parent(new_child) = sub;
|
||||||
|
}
|
||||||
|
_child(new_root, dir) = sub;
|
||||||
|
|
||||||
|
_parent(new_root) = sub_parent;
|
||||||
|
_parent(sub) = new_root;
|
||||||
|
if (sub_parent != nullptr) {
|
||||||
|
_child(sub_parent, sub == _right(sub_parent)) = new_root;
|
||||||
|
} else {
|
||||||
|
_root = new_root;
|
||||||
|
}
|
||||||
|
return new_root;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool color(size_t i) const {
|
constexpr void _recolor(node n) {
|
||||||
return i == npos ? false : _table[i].value.second;
|
bool c = color(n) == black;
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void _recolor(size_t n) {
|
|
||||||
bool c = !color(n);
|
|
||||||
if (n == _root) { // Only recolor if not the root node
|
if (n == _root) { // Only recolor if not the root node
|
||||||
_color(n) = c;
|
_color(n) = c;
|
||||||
}
|
}
|
||||||
@@ -328,45 +485,53 @@ protected:
|
|||||||
|
|
||||||
// run-of-the-mill bst insert
|
// run-of-the-mill bst insert
|
||||||
template<typename...ArgsT>
|
template<typename...ArgsT>
|
||||||
constexpr size_t _insert_bst(ArgsT&&...args) {
|
constexpr node _insert_bst(ArgsT&&...args) {
|
||||||
value_t val(fennec::forward<ArgsT>(args)...);
|
node res = _make_node(fennec::forward<ArgsT>(args)...);
|
||||||
|
|
||||||
if (_root == npos) {
|
if (_root == nullptr) {
|
||||||
return _root = base_t::emplace(npos, false, fennec::move(val), red);
|
++_size;
|
||||||
|
_color(res) = black;
|
||||||
|
return _root = res;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t i = _root;
|
node i = _root;
|
||||||
size_t p = npos;
|
node p = nullptr;
|
||||||
while (i != npos) {
|
bool d = dir_left;
|
||||||
|
while (i != nullptr) {
|
||||||
p = i;
|
p = i;
|
||||||
|
|
||||||
if (_compare(val, _value(i))) {
|
if (_compare(_key(res), _key(i))) {
|
||||||
i = _left(i);
|
i = _left(i);
|
||||||
} else if (_compare(_value(i), val)) {
|
d = dir_left;
|
||||||
|
} else if (_compare(_key(i), _key(res))) {
|
||||||
i = _right(i);
|
i = _right(i);
|
||||||
|
d = dir_right;
|
||||||
} else {
|
} else {
|
||||||
return npos;
|
_free_node(res);
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool d = _compare(val, _value(p));
|
++_size;
|
||||||
return base_t::emplace(p, !d, fennec::move(val), red);
|
_child(p, d) = res;
|
||||||
|
_parent(res) = p;
|
||||||
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// This makes some cheats given that the structure is modified only by internal functions
|
// This makes some cheats given that the structure is modified only by internal functions
|
||||||
// If such is the case, ONLY LL, LR, RL, and RR will show up
|
// If such is the case, ONLY LL, LR, RL, and RR will show up
|
||||||
// Then we just need to handle splitting a 4-node
|
// Then we just need to handle splitting a 4-node
|
||||||
constexpr void _fix_insert(size_t n) {
|
constexpr void _fix_insert(node n) {
|
||||||
if (n == npos) {
|
if (n == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t p = _parent(n);
|
node p = _parent(n);
|
||||||
while (n != _root && color(n) == red && color(p) == red) {
|
while (n != _root && color(n) == red && color(p) == red) {
|
||||||
size_t g = _parent(p);
|
node g = _parent(p);
|
||||||
bool d = n == _right(p);
|
bool d = n == _right(p);
|
||||||
bool r = p == _right(g);
|
bool r = p == _right(g);
|
||||||
size_t u = _child(g, !r);
|
node u = _child(g, !r);
|
||||||
|
|
||||||
if (color(u) == red) {
|
if (color(u) == red) {
|
||||||
_recolor(g);
|
_recolor(g);
|
||||||
@@ -376,12 +541,12 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (d != r) {
|
if (d != r) {
|
||||||
rotate(p, r);
|
_rotate(p, r);
|
||||||
n = p;
|
n = p;
|
||||||
p = _parent(n);
|
p = _parent(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
rotate(g, not r);
|
_rotate(g, not r);
|
||||||
fennec::swap(_color(p), _color(g));
|
fennec::swap(_color(p), _color(g));
|
||||||
n = p;
|
n = p;
|
||||||
p = _parent(n);
|
p = _parent(n);
|
||||||
@@ -389,13 +554,13 @@ protected:
|
|||||||
_color(_root) = black;
|
_color(_root) = black;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void _swap_val(size_t a, size_t b) {
|
constexpr void _swap_val(node a, node b) {
|
||||||
fennec::swap(_value(a), _value(b));
|
fennec::swap(_key(a), _key(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr size_t _red_child(size_t x) {
|
constexpr node _red_child(node x) {
|
||||||
size_t l = _left(x);
|
node l = _left(x);
|
||||||
size_t r = _right(x);
|
node r = _right(x);
|
||||||
|
|
||||||
if (color(l) == red) {
|
if (color(l) == red) {
|
||||||
return l;
|
return l;
|
||||||
@@ -405,32 +570,32 @@ protected:
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return npos;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void _fix_erase(size_t n) {
|
constexpr void _fix_erase(node n) {
|
||||||
if (n == npos) {
|
if (n == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (n == _root) {
|
if (n == _root) {
|
||||||
_root = npos;
|
_root = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t o = n;
|
node o = n;
|
||||||
size_t p = _parent(n);
|
node p = _parent(n);
|
||||||
if (p == npos) {
|
if (p == nullptr) {
|
||||||
_root = npos;
|
_root = nullptr;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool d = n == _right(p);
|
bool d = n == _right(p);
|
||||||
size_t c = _red_child(n);
|
node c = _red_child(n);
|
||||||
size_t s = npos;
|
node s = nullptr;
|
||||||
if (_color(n) == red || c != npos) {
|
if (_color(n) == red || c != nullptr) {
|
||||||
_child(p, d) = c;
|
_child(p, d) = c;
|
||||||
if (c != npos) {
|
if (c != nullptr) {
|
||||||
_parent(c) = p;
|
_parent(c) = p;
|
||||||
}
|
}
|
||||||
_color(c) = black;
|
_color(c) = black;
|
||||||
@@ -442,19 +607,19 @@ protected:
|
|||||||
d = n == _right(p);
|
d = n == _right(p);
|
||||||
s = _child(p, !d);
|
s = _child(p, !d);
|
||||||
|
|
||||||
if (s == npos) {
|
if (s == nullptr) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_color(s) == red) {
|
if (_color(s) == red) {
|
||||||
_color(s) = black;
|
_color(s) = black;
|
||||||
_color(p) = red;
|
_color(p) = red;
|
||||||
rotate(p, d);
|
_rotate(p, d);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t nc = _child(s, d);
|
node nc = _child(s, d);
|
||||||
size_t nf = _child(s, !d);
|
node nf = _child(s, !d);
|
||||||
|
|
||||||
if (color(nc) == black && color(nf) == black) {
|
if (color(nc) == black && color(nf) == black) {
|
||||||
_color(s) = red;
|
_color(s) = red;
|
||||||
@@ -469,62 +634,61 @@ protected:
|
|||||||
if (color(nf) == black) {
|
if (color(nf) == black) {
|
||||||
_color(nc) = black;
|
_color(nc) = black;
|
||||||
_color(s) = red;
|
_color(s) = red;
|
||||||
rotate(s, !d);
|
_rotate(s, !d);
|
||||||
s = nc;
|
s = nc;
|
||||||
nf = s;
|
nf = s;
|
||||||
}
|
}
|
||||||
_color(s) = _color(p);
|
_color(s) = _color(p);
|
||||||
_color(p) = black;
|
_color(p) = black;
|
||||||
_color(nf) = black;
|
_color(nf) = black;
|
||||||
rotate(p, d);
|
_rotate(p, d);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
p = parent(o);
|
p = parent(o);
|
||||||
if (p != npos) {
|
if (p != nullptr) {
|
||||||
if (o == _left(p)) {
|
if (o == _left(p)) {
|
||||||
_left(p) = npos;
|
_left(p) = nullptr;
|
||||||
} else {
|
} else {
|
||||||
_right(p) = npos;
|
_right(p) = nullptr;
|
||||||
}
|
}
|
||||||
_color(_root) = black;
|
_color(_root) = black;
|
||||||
} else {
|
} else {
|
||||||
_root = npos;
|
_root = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr void _erase(size_t n) {
|
constexpr void _erase(node n) {
|
||||||
if (n == npos) {
|
if (n == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t l = _left(n);
|
node l = _left(n);
|
||||||
size_t r = _right(n);
|
node r = _right(n);
|
||||||
|
|
||||||
// 2 children
|
// 2 children
|
||||||
if (l != npos && r != npos) {
|
if (l != nullptr && r != nullptr) {
|
||||||
size_t s = left_most(r);
|
node s = leftmost(r);
|
||||||
_swap_val(n, s);
|
_swap_val(n, s);
|
||||||
n = s;
|
n = s;
|
||||||
l = _left(n);
|
l = _left(n);
|
||||||
r = _right(n);
|
r = _right(n);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t p = _parent(n);
|
node p = _parent(n);
|
||||||
bool d = n == right(p);
|
bool d = n == right(p);
|
||||||
size_t c = l != npos ? l : r;
|
node c = l != nullptr ? l : r;
|
||||||
|
|
||||||
// Single child
|
// Single child
|
||||||
if (c != npos) {
|
if (c != nullptr) {
|
||||||
_parent(c) = p;
|
_parent(c) = p;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handles root cases
|
// Handles root cases
|
||||||
if (p == npos) {
|
if (p == nullptr) {
|
||||||
_root = c;
|
_root = c;
|
||||||
if (c == npos) {
|
if (c == nullptr) {
|
||||||
fennec::destruct(&_table[n]);
|
_free_node(n);
|
||||||
_freed.push_back(n);
|
|
||||||
--_size;
|
--_size;
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
@@ -533,19 +697,17 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Single Child, Red, and Root cases
|
// Single Child, Red, and Root cases
|
||||||
if (p == npos || c != npos || _color(n) == red) {
|
if (p == nullptr || c != nullptr || _color(n) == red) {
|
||||||
if (p != npos) {
|
if (p != nullptr) {
|
||||||
_child(p, d) = c;
|
_child(p, d) = c;
|
||||||
}
|
}
|
||||||
fennec::destruct(&_table[n]);
|
_free_node(n);
|
||||||
_freed.push_back(n);
|
|
||||||
--_size;
|
--_size;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
_fix_erase(n);
|
_fix_erase(n);
|
||||||
fennec::destruct(&_table[n]);
|
_free_node(n);
|
||||||
_freed.push_back(n);
|
|
||||||
--_size;
|
--_size;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -27,20 +27,33 @@ namespace fennec
|
|||||||
|
|
||||||
struct event;
|
struct event;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Class outlining the interface for an object that listens for events
|
||||||
class event_listener {
|
class event_listener {
|
||||||
public:
|
public:
|
||||||
virtual ~event_listener() = default;
|
virtual ~event_listener() = default;
|
||||||
virtual void handle_event(event* event) = 0;
|
virtual void handle_event(event* event) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct event {
|
///
|
||||||
const uint64_t type;
|
/// \brief Main event interface, includes static methods for registering listeners and dispatching events
|
||||||
|
struct event : typed<event> {
|
||||||
|
|
||||||
|
// Delete default constructor to enforce type scheme
|
||||||
event() = delete;
|
event() = delete;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Event Constructor, stores the event type
|
||||||
|
/// \tparam EventT The type of the event
|
||||||
template<typename EventT>
|
template<typename EventT>
|
||||||
event() : type(typeuuid<EventT>()) { }
|
event(EventT* type)
|
||||||
|
: typed(type) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Registers a listener for the event type
|
||||||
|
/// \tparam EventT
|
||||||
|
/// \param listener
|
||||||
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>());
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ constexpr uint64_t nullid = 0;
|
|||||||
|
|
||||||
template<typename TypeT, typename RootT = void>
|
template<typename TypeT, typename RootT = void>
|
||||||
FENNEC_NO_INLINE uint64_t typeuuid() {
|
FENNEC_NO_INLINE uint64_t typeuuid() {
|
||||||
assertf(not is_constant_evaluated(), "Type UUIDs Cannot Be Obtained at Compile Time");
|
|
||||||
|
|
||||||
static bool init = false;
|
static bool init = false;
|
||||||
static uint64_t id = nullid;
|
static uint64_t id = nullid;
|
||||||
|
|
||||||
|
|||||||
@@ -67,26 +67,40 @@ struct tokenizer {
|
|||||||
string brackets; // characters that mark brackets
|
string brackets; // characters that mark brackets
|
||||||
string quotes; // characters that mark a string sequence, entire string sequence is treated as one token
|
string quotes; // characters that mark a string sequence, entire string sequence is treated as one token
|
||||||
escmap escapes; // characters that mark the start of an escape sequence and validate them
|
escmap escapes; // characters that mark the start of an escape sequence and validate them
|
||||||
|
bool numbers; // Anything that resembles a number
|
||||||
|
|
||||||
enum token_ : uint8_t {
|
enum token_ : uint8_t {
|
||||||
token_string = 0,
|
token_text = 0,
|
||||||
token_newline = 1,
|
token_integer,
|
||||||
token_escaped = 2,
|
token_string,
|
||||||
token_operator = 3,
|
token_newline,
|
||||||
token_bracket = 4,
|
token_escaped,
|
||||||
token_quoted = 5,
|
token_operator,
|
||||||
|
token_bracket,
|
||||||
|
token_quoted,
|
||||||
|
|
||||||
|
num_token_types
|
||||||
};
|
};
|
||||||
|
|
||||||
using token = pair<string, uint8_t>;
|
using token = pair<string, uint8_t>;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// list<token> operator()(const string& line) {
|
static constexpr uint8_t token_delimiter = num_token_types;
|
||||||
// list<token> res;
|
|
||||||
//
|
constexpr list<token> operator()(const string& line) {
|
||||||
// for (size_t i = 0; i < )
|
list<token> res;
|
||||||
//
|
priority_queue<pair<size_t, uint8_t>> idx;
|
||||||
// return res;
|
|
||||||
// }
|
for (size_t i = 0; i < line.size(); ++i) {
|
||||||
|
|
||||||
|
for (char c : delimiter) {
|
||||||
|
idx.emplace()
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -48,6 +48,12 @@ using ::ispunct;
|
|||||||
using ::tolower;
|
using ::tolower;
|
||||||
using ::toupper;
|
using ::toupper;
|
||||||
|
|
||||||
|
|
||||||
|
struct string_view {
|
||||||
|
const char* str;
|
||||||
|
size_t len;
|
||||||
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief This struct wraps c-style strings
|
/// \brief This struct wraps c-style strings
|
||||||
///
|
///
|
||||||
@@ -82,7 +88,9 @@ public:
|
|||||||
: _str(str)
|
: _str(str)
|
||||||
, _size(n - 1)
|
, _size(n - 1)
|
||||||
, _const(false) {
|
, _const(false) {
|
||||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
if constexpr(not is_constant_evaluated()) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -94,7 +102,9 @@ public:
|
|||||||
: _str(str)
|
: _str(str)
|
||||||
, _size(n - 1)
|
, _size(n - 1)
|
||||||
, _const(false) {
|
, _const(false) {
|
||||||
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
if constexpr(not is_constant_evaluated()) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -105,7 +115,9 @@ public:
|
|||||||
: _cstr(str)
|
: _cstr(str)
|
||||||
, _size(n - 1)
|
, _size(n - 1)
|
||||||
, _const(true) {
|
, _const(true) {
|
||||||
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
if constexpr(not is_constant_evaluated()) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -117,7 +129,9 @@ public:
|
|||||||
: _cstr(str)
|
: _cstr(str)
|
||||||
, _size(n - 1)
|
, _size(n - 1)
|
||||||
, _const(true) {
|
, _const(true) {
|
||||||
assert(_cstr[n - 1] == '\0', "Invalid NTBS.");
|
if constexpr(not is_constant_evaluated()) {
|
||||||
|
assert(_str[n - 1] == '\0', "Invalid NTBS.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -170,11 +184,15 @@ public:
|
|||||||
|
|
||||||
///
|
///
|
||||||
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
/// \returns the size of the string excluding its null terminator, i.e. `(*str)[size()] == '\0'`
|
||||||
constexpr size_t size() const { return _size; }
|
constexpr size_t size() const {
|
||||||
|
return _size;
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
|
/// \returns the size of the string including its null terminator, i.e. `(*str)[capacity() - 1] == '\0'`
|
||||||
constexpr size_t capacity() const { return _size + 1; }
|
constexpr size_t capacity() const {
|
||||||
|
return _size + 1;
|
||||||
|
}
|
||||||
|
|
||||||
constexpr bool empty() const {
|
constexpr bool empty() const {
|
||||||
return _cstr == nullptr || _size == 0;
|
return _cstr == nullptr || _size == 0;
|
||||||
|
|||||||
174
include/fennec/langproc/strings/format.h
Normal file
174
include/fennec/langproc/strings/format.h
Normal file
@@ -0,0 +1,174 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file format.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_LANGPROC_STRINGS_FORMAT_H
|
||||||
|
#define FENNEC_LANGPROC_STRINGS_FORMAT_H
|
||||||
|
#include <fennec/containers/pair.h>
|
||||||
|
#include <fennec/langproc/strings/cstring.h>
|
||||||
|
#include <fennec/langproc/strings/string.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename TypeT>
|
||||||
|
struct formatter {
|
||||||
|
constexpr string operator()(const string_view&, const TypeT&) {
|
||||||
|
static_assert(false, "Formatter not implemented for the provided type.");
|
||||||
|
return string{""};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<>
|
||||||
|
struct formatter<cstring> {
|
||||||
|
constexpr string operator()(const string_view&, const cstring& str) {
|
||||||
|
return string(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t N>
|
||||||
|
struct formatter<const char (&)[N]> {
|
||||||
|
constexpr string operator()(const string_view&, const char (&str)[N]) {
|
||||||
|
return string(str);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t N, typename...ArgsT>
|
||||||
|
struct format_string {
|
||||||
|
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
private:
|
||||||
|
static constexpr size_t npos = -1;
|
||||||
|
|
||||||
|
enum token_ : uint8_t {
|
||||||
|
token_text = 0,
|
||||||
|
token_param,
|
||||||
|
};
|
||||||
|
|
||||||
|
using token = pair<uint8_t, string_view>;
|
||||||
|
|
||||||
|
constexpr const char* find(const char* start, char c) {
|
||||||
|
while (*start != c && *start != '\0') {
|
||||||
|
++start;
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
public:
|
||||||
|
format_string() = delete;
|
||||||
|
|
||||||
|
format_string(const char (&str)[N])
|
||||||
|
: _tokens(), _num_tokens(0) {
|
||||||
|
static_assert(is_constant_evaluated(), "Runtime format strings are not supported.");
|
||||||
|
|
||||||
|
// TODO: Numbered Parameters
|
||||||
|
|
||||||
|
size_t params = 0;
|
||||||
|
for (size_t i = 0; i < N; ++i) {
|
||||||
|
size_t n = this->find(str + i, '{') - str;
|
||||||
|
|
||||||
|
// Push the current token
|
||||||
|
if (n - i > 0) {
|
||||||
|
_tokens[_num_tokens++] = { token_text, { &str[i], n - i } };
|
||||||
|
}
|
||||||
|
|
||||||
|
// no more braces, break
|
||||||
|
if (n >= N) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// escaped brace
|
||||||
|
if (str[n + 1] == '{') {
|
||||||
|
_tokens[_num_tokens++] = { token_text, { &str[n], 1 } };
|
||||||
|
i = n + 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t e = this->find(str + n, '}') - str;
|
||||||
|
//static_assert(e >= N, "Malformed format string, mismatched brace");
|
||||||
|
|
||||||
|
_tokens[_num_tokens++] = { token_param, { &str[n], e - n + 1 } };
|
||||||
|
++params;
|
||||||
|
i = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
//static_assert(params == sizeof...(ArgsT), "Malformed format string, parameter count does not match argument count.");
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr format_string(const format_string&) = default;
|
||||||
|
constexpr format_string(format_string&&) noexcept = default;
|
||||||
|
|
||||||
|
~format_string() = default;
|
||||||
|
|
||||||
|
string format(ArgsT&&...args) const {
|
||||||
|
return this->_format(0, fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
array<token, N> _tokens;
|
||||||
|
size_t _num_tokens;
|
||||||
|
|
||||||
|
string _format(size_t) const {
|
||||||
|
return string{""};
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename HeadT, typename...RestT>
|
||||||
|
string _format(size_t i, HeadT&& head, RestT&&...rest) const {
|
||||||
|
string res;
|
||||||
|
for (; i < _num_tokens; ++i) {
|
||||||
|
const auto& token = _tokens[i];
|
||||||
|
|
||||||
|
if (token.first == token_param) {
|
||||||
|
formatter<HeadT> fmt;
|
||||||
|
res += fmt(token.second, head);
|
||||||
|
res += this->_format(i + 1, fennec::forward<RestT>(rest)...);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
res += token.second;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template<size_t N, typename...ArgsT>
|
||||||
|
string _format(const format_string<N, ArgsT...>& str, ArgsT&&...args) {
|
||||||
|
return str.format(fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<size_t N, typename...ArgsT>
|
||||||
|
string format(const char (&str)[N], ArgsT&&...args) {
|
||||||
|
return fennec::_format<N, ArgsT...>(format_string<N, ArgsT...>(str), fennec::forward<ArgsT>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // FENNEC_LANGPROC_STRINGS_FORMAT_H
|
||||||
@@ -108,6 +108,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr _string(const string_view& view)
|
||||||
|
: _string(view.str, view.len) {
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief String Copy Constructor
|
/// \brief String Copy Constructor
|
||||||
/// \param str the string to copy
|
/// \param str the string to copy
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ namespace fennec
|
|||||||
/// \param x a vector containing the position
|
/// \param x a vector containing the position
|
||||||
/// \returns An identity matrix with the last column set to x
|
/// \returns An identity matrix with the last column set to x
|
||||||
template<typename genType>
|
template<typename genType>
|
||||||
constexpr mat<genType, 3, 3> translation(const vec<genType, 2>& x) {
|
constexpr mat<genType, 3, 3> translation(const vector<genType, 0, 1>& x) {
|
||||||
return mat<genType, 3, 3>(
|
return mat<genType, 3, 3>(
|
||||||
1, 0, 0,
|
1, 0, 0,
|
||||||
0, 1, 0,
|
0, 1, 0,
|
||||||
@@ -45,7 +45,7 @@ constexpr mat<genType, 3, 3> translation(const vec<genType, 2>& x) {
|
|||||||
/// \param x a vector containing the position
|
/// \param x a vector containing the position
|
||||||
/// \returns An identity matrix with the last column set to x
|
/// \returns An identity matrix with the last column set to x
|
||||||
template<typename genType>
|
template<typename genType>
|
||||||
constexpr mat<genType, 4, 4> translation(const vec<genType, 3>& x) {
|
constexpr mat<genType, 4, 4> translation(const vector<genType, 0, 1, 2>& x) {
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
1, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, 1, 0, 0,
|
0, 1, 0, 0,
|
||||||
@@ -59,7 +59,7 @@ constexpr mat<genType, 4, 4> translation(const vec<genType, 3>& x) {
|
|||||||
/// \param x a vector containing the scale for each axis
|
/// \param x a vector containing the scale for each axis
|
||||||
/// \returns A diagonal matrix with the terms of x
|
/// \returns A diagonal matrix with the terms of x
|
||||||
template<typename genType>
|
template<typename genType>
|
||||||
constexpr mat<genType, 3, 3> scaling(const vec<genType, 2>& x) {
|
constexpr mat<genType, 3, 3> scaling(const vector<genType, 0, 1>& x) {
|
||||||
return mat<genType, 3, 3>(
|
return mat<genType, 3, 3>(
|
||||||
x.x, 0, 0,
|
x.x, 0, 0,
|
||||||
0, x.y, 0,
|
0, x.y, 0,
|
||||||
@@ -72,7 +72,7 @@ constexpr mat<genType, 3, 3> scaling(const vec<genType, 2>& x) {
|
|||||||
/// \param x a vector containing the scale for each axis
|
/// \param x a vector containing the scale for each axis
|
||||||
/// \returns A diagonal matrix with the terms of x
|
/// \returns A diagonal matrix with the terms of x
|
||||||
template<typename genType>
|
template<typename genType>
|
||||||
constexpr mat<genType, 4, 4> scaling(const vec<genType, 3>& x) {
|
constexpr mat<genType, 4, 4> scaling(const vector<genType, 0, 1, 2>& x) {
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
x.x, 0, 0, 0,
|
x.x, 0, 0, 0,
|
||||||
0, x.y, 0, 0,
|
0, x.y, 0, 0,
|
||||||
@@ -81,6 +81,15 @@ constexpr mat<genType, 4, 4> scaling(const vec<genType, 3>& x) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename genType>
|
||||||
|
constexpr mat<genType, 3, 3> shear(const vector<genType, 0, 1>& x) {
|
||||||
|
return mat<genType, 3, 3>(
|
||||||
|
1, x.x, 0,
|
||||||
|
x.y, 1, 0,
|
||||||
|
0, 0, 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
/// \brief Create a 2d rotation matrix
|
/// \brief Create a 2d rotation matrix
|
||||||
/// \param a the angle of the rotation in radians
|
/// \param a the angle of the rotation in radians
|
||||||
@@ -106,7 +115,7 @@ constexpr mat<genType, 3, 3> rotation(const genType a) {
|
|||||||
/// \param a The rotation about the axis in radians
|
/// \param a The rotation about the axis in radians
|
||||||
/// \returns A rotation matrix about A
|
/// \returns A rotation matrix about A
|
||||||
template<typename genType>
|
template<typename genType>
|
||||||
constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
|
constexpr mat<genType, 4, 4> rotation(const vector<genType, 0, 1, 2>& A, genType a) {
|
||||||
// https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
|
// https://en.wikipedia.org/wiki/Rotation_matrix#Rotation_matrix_from_axis_and_angle
|
||||||
|
|
||||||
// Calculate sin and cos terms
|
// Calculate sin and cos terms
|
||||||
@@ -114,8 +123,8 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
|
|||||||
const genType s = fennec::sin(a);
|
const genType s = fennec::sin(a);
|
||||||
|
|
||||||
// Calculate axis term
|
// Calculate axis term
|
||||||
const vec<genType, 3> u = (fennec::one<genType>() - c) * A;
|
const vector<genType, 0, 1, 2> u = (fennec::one<genType>() - c) * A;
|
||||||
const vec<genType, 3> v = s * A;
|
const vector<genType, 0, 1, 2> v = s * A;
|
||||||
|
|
||||||
// Calculate the Matrix
|
// Calculate the Matrix
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
@@ -126,20 +135,20 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& A, genType a) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename genType>
|
// template<typename genType>
|
||||||
constexpr qua<genType> rotation(const vec<genType, 3>& axis, genType angle) {
|
// constexpr qua<genType> rotation(const vector<genType, 0, 1, 2>& axis, genType angle) {
|
||||||
vec<genType, 3> a = fennec::normalize(axis);
|
// vector<genType, 0, 1, 2> a = fennec::normalize(axis);
|
||||||
const genType s = fennec::sin(angle);
|
// const genType s = fennec::sin(angle);
|
||||||
|
//
|
||||||
return qua<genType>(fennec::cos(angle * genType(0.5)), s * a);
|
// return qua<genType>(fennec::cos(angle * genType(0.5)), s * a);
|
||||||
}
|
// }
|
||||||
|
|
||||||
/// \brief enum to denote the unit-axis of rotation
|
/// \brief enum to denote the unit-axis of rotation
|
||||||
enum rot_
|
enum rotation_
|
||||||
{
|
{
|
||||||
rot_x = 0
|
rotation_x = 0
|
||||||
, rot_y
|
, rotation_y
|
||||||
, rot_z
|
, rotation_z
|
||||||
};
|
};
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -147,7 +156,7 @@ enum rot_
|
|||||||
/// \tparam axis the unit axis to rotate around
|
/// \tparam axis the unit axis to rotate around
|
||||||
/// \param a the angle, in radians
|
/// \param a the angle, in radians
|
||||||
/// \returns a matrix that rotates vectors around a unit axis
|
/// \returns a matrix that rotates vectors around a unit axis
|
||||||
template<typename genType, rot_ axis>
|
template<typename genType, rotation_ axis>
|
||||||
constexpr mat<genType, 4, 4> rotation(genType a) {
|
constexpr mat<genType, 4, 4> rotation(genType a) {
|
||||||
// https://en.wikipedia.org/wiki/Rotation_matrix#Basic_3D_rotations
|
// https://en.wikipedia.org/wiki/Rotation_matrix#Basic_3D_rotations
|
||||||
|
|
||||||
@@ -156,7 +165,7 @@ constexpr mat<genType, 4, 4> rotation(genType a) {
|
|||||||
const genType s = fennec::sin(a);
|
const genType s = fennec::sin(a);
|
||||||
|
|
||||||
// Calculate the matrix
|
// Calculate the matrix
|
||||||
if constexpr(axis == rot_x) {
|
if constexpr(axis == rotation_x) {
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
1, 0, 0, 0,
|
1, 0, 0, 0,
|
||||||
0, c, -s, 0,
|
0, c, -s, 0,
|
||||||
@@ -164,7 +173,7 @@ constexpr mat<genType, 4, 4> rotation(genType a) {
|
|||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if constexpr(axis == rot_y) {
|
else if constexpr(axis == rotation_y) {
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
c, 0, s, 0,
|
c, 0, s, 0,
|
||||||
0, 0, 0, 0,
|
0, 0, 0, 0,
|
||||||
@@ -172,7 +181,7 @@ constexpr mat<genType, 4, 4> rotation(genType a) {
|
|||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else if constexpr(axis == rot_z) {
|
else if constexpr(axis == rotation_z) {
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
c, -s, 0, 0,
|
c, -s, 0, 0,
|
||||||
s, c, 0, 0,
|
s, c, 0, 0,
|
||||||
@@ -202,7 +211,7 @@ enum order_
|
|||||||
/// \param E the euler angles, taken as tait-bryan (pitch, yaw, roll)
|
/// \param E the euler angles, taken as tait-bryan (pitch, yaw, roll)
|
||||||
/// \returns a matrix that rotates vectors
|
/// \returns a matrix that rotates vectors
|
||||||
template<typename genType, order_ order = order_zxy>
|
template<typename genType, order_ order = order_zxy>
|
||||||
constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& E) {
|
constexpr mat<genType, 4, 4> rotation(const vector<genType, 0, 1, 2>& E) {
|
||||||
// expanded using a CAS
|
// expanded using a CAS
|
||||||
|
|
||||||
// Calculate sin and cos terms
|
// Calculate sin and cos terms
|
||||||
@@ -221,40 +230,35 @@ constexpr mat<genType, 4, 4> rotation(const vec<genType, 3>& E) {
|
|||||||
sa*sg - ca*cg*sb, ca*sb*sg + cg*sa, ca*cb, 0,
|
sa*sg - ca*cg*sb, ca*sb*sg + cg*sa, ca*cb, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
} else if constexpr(order == order_xzy) {
|
||||||
else if constexpr(order == order_xzy) {
|
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
cb*cg, -sg, cg*sb, 0,
|
cb*cg, -sg, cg*sb, 0,
|
||||||
ca*cb*sg + sa*sb, ca*cg, cb*sa*sg - ca*sb, 0,
|
ca*cb*sg + sa*sb, ca*cg, cb*sa*sg - ca*sb, 0,
|
||||||
cb*sa*sg - ca*sb, cg*sa, ca*cb + sa*sb*sg, 0,
|
cb*sa*sg - ca*sb, cg*sa, ca*cb + sa*sb*sg, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
} else if constexpr(order == order_yxz) {
|
||||||
else if constexpr(order == order_yxz) {
|
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
cb*cg + sa*sb*sg, cg*sa*sb - cb*sg, ca*sb, 0,
|
cb*cg + sa*sb*sg, cg*sa*sb - cb*sg, ca*sb, 0,
|
||||||
ca*sg, ca*cg, -sa, 0,
|
ca*sg, ca*cg, -sa, 0,
|
||||||
cb*sa*sg - cg*sb, cb*cg*sa + sb*sg, ca*cb, 0,
|
cb*sa*sg - cg*sb, cb*cg*sa + sb*sg, ca*cb, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
} else if constexpr(order == order_yzx) {
|
||||||
else if constexpr(order == order_yzx) {
|
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
cb*cg, sa*sb - ca*cb*sg, ca*sb + cb*sa*sg, 0,
|
cb*cg, sa*sb - ca*cb*sg, ca*sb + cb*sa*sg, 0,
|
||||||
sg, ca*cg, -cg*sa, 0,
|
sg, ca*cg, -cg*sa, 0,
|
||||||
-cg*sb, ca*sb*sg + cb*sa, ca*cb - sa*sb*sg, 0,
|
-cg*sb, ca*sb*sg + cb*sa, ca*cb - sa*sb*sg, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
} else if constexpr(order == order_zxy) {
|
||||||
else if constexpr(order == order_zxy) {
|
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
cb*cg - sa*sb*sg, -ca*sg, cb*sa*sg + cg*sb, 0,
|
cb*cg - sa*sb*sg, -ca*sg, cb*sa*sg + cg*sb, 0,
|
||||||
cb*sg + cg*sa*sb, ca*cg, sb*sg - cb*cg*sa, 0,
|
cb*sg + cg*sa*sb, ca*cg, sb*sg - cb*cg*sa, 0,
|
||||||
-ca*sb, sa, ca*cb, 0,
|
-ca*sb, sa, ca*cb, 0,
|
||||||
0, 0, 0, 1
|
0, 0, 0, 1
|
||||||
);
|
);
|
||||||
}
|
} else if constexpr(order == order_zyx) {
|
||||||
else if constexpr(order == order_zyx) {
|
|
||||||
return mat<genType, 4, 4>(
|
return mat<genType, 4, 4>(
|
||||||
cb*cg, cg*sa*sb - ca*sg, ca*cg*sb + sa*sg, 0,
|
cb*cg, cg*sa*sb - ca*sg, ca*cg*sb + sa*sg, 0,
|
||||||
cb*sg, ca*cg + sa*sb*sg, ca*sb*sg - cg*sa, 0,
|
cb*sg, ca*cg + sa*sb*sg, ca*sb*sg - cg*sa, 0,
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ struct matrix
|
|||||||
/// \param mat matrix to copy
|
/// \param mat matrix to copy
|
||||||
constexpr matrix(const matrix_t& mat)
|
constexpr matrix(const matrix_t& mat)
|
||||||
: data{ mat.data } {
|
: data{ mat.data } {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
///
|
///
|
||||||
@@ -261,7 +260,26 @@ struct matrix
|
|||||||
/// \param mat matrix to move
|
/// \param mat matrix to move
|
||||||
constexpr matrix(matrix_t&& mat) noexcept
|
constexpr matrix(matrix_t&& mat) noexcept
|
||||||
: data{ mat.data } {
|
: data{ mat.data } {
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OScalarT>
|
||||||
|
constexpr matrix(const matrix<OScalarT, RowsV, ColIndicesV...>& mat)
|
||||||
|
: matrix() {
|
||||||
|
for (size_t i = 0; i < columns; ++i) {
|
||||||
|
for (size_t j = 0; j < rows; ++j) {
|
||||||
|
data[i][j] = scalar_t(mat[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename OScalarT>
|
||||||
|
constexpr matrix(matrix<OScalarT, RowsV, ColIndicesV...>&& mat) noexcept
|
||||||
|
: matrix() {
|
||||||
|
for (size_t i = 0; i < columns; ++i) {
|
||||||
|
for (size_t j = 0; j < rows; ++j) {
|
||||||
|
data[i][j] = scalar_t(mat[i][j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -629,6 +647,11 @@ struct matrix
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<size_t ORowsV, size_t...OColIndicesV> requires(columns == ORowsV)
|
||||||
|
constexpr matrix<scalar_t, RowsV, OColIndicesV...>& operator*=(const matrix<scalar_t, ORowsV, OColIndicesV...>& rhs) {
|
||||||
|
return *this = *this * rhs;
|
||||||
|
}
|
||||||
|
|
||||||
/// @}
|
/// @}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1086,22 +1086,22 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV>
|
template<size_t OffsetV>
|
||||||
constexpr void _insert(ScalarT& x) {
|
constexpr void _insert(const ScalarT& x) {
|
||||||
data[OffsetV] = x;
|
data[OffsetV] = x;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV, typename OScalarT>
|
template<size_t OffsetV, typename OScalarT>
|
||||||
constexpr void _insert(OScalarT& x) {
|
constexpr void _insert(const OScalarT& x) {
|
||||||
data[OffsetV] = ScalarT(x);
|
data[OffsetV] = ScalarT(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
|
template<size_t OffsetV = 0, typename OScalarT, size_t... OIndicesV>
|
||||||
constexpr void _insert(vector<OScalarT, OIndicesV...>& vec) {
|
constexpr void _insert(const vector<OScalarT, OIndicesV...>& vec) {
|
||||||
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
|
((data[OffsetV + OIndicesV] = fennec::forward<OScalarT>(vec[OIndicesV])), ...);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
|
template<size_t OffsetV = 0, typename OVectorT, typename ODataT, typename OScalarT, size_t... OIndicesV>
|
||||||
constexpr void _insert(swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
|
constexpr void _insert(const swizzle<OVectorT, ODataT, OScalarT, OIndicesV...>& vec) {
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
((data[OffsetV + (i++)] = vec.data[OIndicesV]), ...);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
class component {
|
class component : typed<component> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// TYPEDEFS & CONSTANTS ================================================================================================
|
// TYPEDEFS & CONSTANTS ================================================================================================
|
||||||
@@ -196,8 +196,8 @@ public:
|
|||||||
const size_t node;
|
const size_t node;
|
||||||
|
|
||||||
template<typename ComponentT>
|
template<typename ComponentT>
|
||||||
component(size_t node)
|
component(ComponentT* type, size_t node)
|
||||||
: type(type_list()[uuid<ComponentT>()])
|
: typed(type)
|
||||||
, node(node) {
|
, node(node) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
154
include/fennec/scene/components/transform2d.h
Normal file
154
include/fennec/scene/components/transform2d.h
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
// =====================================================================================================================
|
||||||
|
// fennec, a free and open source game engine
|
||||||
|
// Copyright © 2025 Medusa Slockbower
|
||||||
|
//
|
||||||
|
// This program is free software: you can redistribute it and/or modify
|
||||||
|
// it under the terms of the GNU General Public License as published by
|
||||||
|
// the Free Software Foundation, either version 3 of the License, or
|
||||||
|
// (at your option) any later version.
|
||||||
|
//
|
||||||
|
// This program is distributed in the hope that it will be useful,
|
||||||
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
// GNU General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
// =====================================================================================================================
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \file transform2d.h
|
||||||
|
/// \brief
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// \details
|
||||||
|
/// \author Medusa Slockbower
|
||||||
|
///
|
||||||
|
/// \copyright Copyright © 2025 Medusa Slockbower ([GPLv3](https://www.gnu.org/licenses/gpl-3.0.en.html))
|
||||||
|
///
|
||||||
|
///
|
||||||
|
|
||||||
|
#ifndef FENNEC_SCENE_COMPONENTS_TRANSFORM2D_H
|
||||||
|
#define FENNEC_SCENE_COMPONENTS_TRANSFORM2D_H
|
||||||
|
|
||||||
|
#include <fennec/math/matrix.h>
|
||||||
|
#include <fennec/math/ext/transform.h>
|
||||||
|
#include <fennec/scene/component.h>
|
||||||
|
|
||||||
|
namespace fennec
|
||||||
|
{
|
||||||
|
|
||||||
|
struct transform2d : component {
|
||||||
|
// Definitions =========================================================================================================
|
||||||
|
|
||||||
|
enum mobility_ : bool {
|
||||||
|
mobility_static = false,
|
||||||
|
mobility_free = true
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Constructors & Destructor ===========================================================================================
|
||||||
|
public:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Default Constructor, initializes an identity matrix.
|
||||||
|
transform2d(size_t node)
|
||||||
|
: component(this, node)
|
||||||
|
, _position(0, 0)
|
||||||
|
, _scale(1, 1)
|
||||||
|
, _shear(0, 0)
|
||||||
|
, _rotation(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Component Constructor, composes the internal matrix using the components.
|
||||||
|
/// \param pos Position as vec2
|
||||||
|
/// \param scl Scale as vec2
|
||||||
|
/// \param rot Rotation as degrees
|
||||||
|
/// \param skw Skew as vec2
|
||||||
|
transform2d(size_t node, const vec2& pos, const vec2& scl, float rot, const vec2& skw = vec2(0, 0))
|
||||||
|
: component(this, node)
|
||||||
|
, _position(pos)
|
||||||
|
, _scale(scl)
|
||||||
|
, _shear(skw)
|
||||||
|
, _rotation(rot)
|
||||||
|
, _dirty(true)
|
||||||
|
, _local(matrix()) {
|
||||||
|
}
|
||||||
|
|
||||||
|
transform2d(const transform2d&) = default;
|
||||||
|
transform2d(transform2d&&) noexcept = default;
|
||||||
|
|
||||||
|
~transform2d() = default;
|
||||||
|
|
||||||
|
// Access ==============================================================================================================
|
||||||
|
|
||||||
|
constexpr const vec2& position() const {
|
||||||
|
return _position;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const vec2& scale() const {
|
||||||
|
return _scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr float rotation() const {
|
||||||
|
return _rotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const vec2& shear() const {
|
||||||
|
return _shear;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Modifiers ===========================================================================================================
|
||||||
|
|
||||||
|
constexpr void translate(const vec2& x) {
|
||||||
|
_position += x;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void scale(const vec2& s) {
|
||||||
|
_scale *= s;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void rotate(float r) {
|
||||||
|
_rotation += r;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void shear(const vec2& s) {
|
||||||
|
_shear += s;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr void commit() {
|
||||||
|
if (not _dirty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_local = fennec::rotation(_rotation);
|
||||||
|
_local *= fennec::shear(_shear);
|
||||||
|
_local *= fennec::scaling(_scale);
|
||||||
|
_local *= fennec::translation(_position);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const mat3& local() {
|
||||||
|
commit();
|
||||||
|
return _local;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr const mat3& global() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fields ==============================================================================================================
|
||||||
|
private:
|
||||||
|
vec2 _position;
|
||||||
|
vec2 _scale;
|
||||||
|
vec2 _shear;
|
||||||
|
float _rotation;
|
||||||
|
bool _dirty;
|
||||||
|
mat3 _local;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif // FENNEC_SCENE_COMPONENTS_TRANSFORM2D_H
|
||||||
@@ -25,8 +25,19 @@
|
|||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Main Scene Hierarchy
|
||||||
|
/// \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.
|
||||||
|
/// The hierarchy should be displayed using pre-order traversal.
|
||||||
class scene : public rdtree<string> {
|
class scene : public rdtree<string> {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Find a node by name.
|
||||||
|
/// \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
|
||||||
|
/// \returns The id of the node, `npos` if not found.
|
||||||
size_t operator[](const cstring& name) const {
|
size_t operator[](const cstring& name) const {
|
||||||
list<size_t> parse;
|
list<size_t> parse;
|
||||||
parse.push_back(root);
|
parse.push_back(root);
|
||||||
@@ -34,13 +45,20 @@ public:
|
|||||||
if (*_data[parse.front()].value == name) {
|
if (*_data[parse.front()].value == name) {
|
||||||
return parse.front();
|
return parse.front();
|
||||||
}
|
}
|
||||||
parse.push_back(child(parse.front()));
|
|
||||||
parse.push_back(next(parse.front()));
|
// Pre-Order traversal
|
||||||
|
parse.push_front(next(parse.front()));
|
||||||
|
parse.push_front(child(parse.front()));
|
||||||
parse.pop_front();
|
parse.pop_front();
|
||||||
}
|
}
|
||||||
return npos;
|
return npos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///
|
||||||
|
/// \brief Find a node by name.
|
||||||
|
/// \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
|
||||||
|
/// \returns The id of the node, `npos` if not found.
|
||||||
size_t operator[](const string& name) const {
|
size_t operator[](const string& name) const {
|
||||||
list<size_t> parse;
|
list<size_t> parse;
|
||||||
parse.push_back(root);
|
parse.push_back(root);
|
||||||
@@ -48,8 +66,10 @@ public:
|
|||||||
if (*_data[parse.front()].value == name) {
|
if (*_data[parse.front()].value == name) {
|
||||||
return parse.front();
|
return parse.front();
|
||||||
}
|
}
|
||||||
parse.push_back(child(parse.front()));
|
|
||||||
parse.push_back(next(parse.front()));
|
// Pre-Order traversal
|
||||||
|
parse.push_front(next(parse.front()));
|
||||||
|
parse.push_front(child(parse.front()));
|
||||||
parse.pop_front();
|
parse.pop_front();
|
||||||
}
|
}
|
||||||
return npos;
|
return npos;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
|
|
||||||
#ifndef FENNEC_TEST_LANGPROC_FORMAT_H
|
#ifndef FENNEC_TEST_LANGPROC_FORMAT_H
|
||||||
#define FENNEC_TEST_LANGPROC_FORMAT_H
|
#define FENNEC_TEST_LANGPROC_FORMAT_H
|
||||||
#include <fennec/langproc/compile/tokenizer.h>
|
#include <fennec/langproc/strings/format.h>
|
||||||
|
|
||||||
namespace fennec
|
namespace fennec
|
||||||
{
|
{
|
||||||
@@ -40,20 +40,7 @@ namespace test
|
|||||||
|
|
||||||
inline void fennec_test_langproc_format() {
|
inline void fennec_test_langproc_format() {
|
||||||
|
|
||||||
// tokenizer math = {
|
fennec_test_run(fennec::format("{}", "Hello World!"), string("Hello World!"));
|
||||||
// .delimiter { " " },
|
|
||||||
// .operators {"+-/*="},
|
|
||||||
// .braces { "()" },
|
|
||||||
// .escapes { "" },
|
|
||||||
// .terminator { "" },
|
|
||||||
// };
|
|
||||||
//
|
|
||||||
// const auto res = math.parse("1 + 2 = 3");
|
|
||||||
// fennec_test_run(res.size(), size_t(5));
|
|
||||||
//
|
|
||||||
// for (const auto& token : res) {
|
|
||||||
// std::cout << token.second << ", ";
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user