summaryrefslogtreecommitdiff
path: root/modules/core/tree.h
diff options
context:
space:
mode:
authorClaudius "keldu" Holeksa <mail@keldu.de>2023-12-04 12:18:14 +0100
committerClaudius "keldu" Holeksa <mail@keldu.de>2023-12-04 12:18:14 +0100
commita14896f9ed209dd3f9597722e5a5697bd7dbf531 (patch)
tree089ca5cbbd206d1921f8f6b53292f5bc1902ca5c /modules/core/tree.h
parent84ecdcbca9e55b1f57fbb832e12ff4fdbb86e7c9 (diff)
meta: Renamed folder containing source
Diffstat (limited to 'modules/core/tree.h')
-rw-r--r--modules/core/tree.h248
1 files changed, 248 insertions, 0 deletions
diff --git a/modules/core/tree.h b/modules/core/tree.h
new file mode 100644
index 0000000..68fa20a
--- /dev/null
+++ b/modules/core/tree.h
@@ -0,0 +1,248 @@
+#pragma once
+
+#include <variant>
+#include <vector>
+
+#include "error.h"
+
+namespace saw {
+/**
+ * Container with a simplistic approach to a branch
+ */
+template<typename T, typename Tree>
+class branch;
+
+/**
+ * Tree object holding branches.
+ *
+ * The name comes from the fact a tree is acting as a node while the branch class is the
+ * edge to a leaf or other nodes. A tree holds the branches while the branch either has
+ * a leaf or another sub tree.
+ */
+template<typename T, typename Tree>
+class tree_container final {
+private:
+ /**
+ * Object holding the treeed branch instances
+ */
+ std::vector<branch<T,Tree>> children_;
+public:
+ /**
+ * Default constructor
+ */
+ tree_container() = default;
+
+ /**
+ * Destructor
+ */
+ ~tree_container() = default;
+
+ SAW_FORBID_COPY(tree_container);
+ SAW_DEFAULT_MOVE(tree_container);
+
+ /**
+ * Reserve space for siz elements
+ */
+ error_or<void> reserve(std::size_t siz){
+ try{
+ children_.reserve(siz);
+ }catch(const std::exception& e){
+ (void) e;
+
+ return make_error<err::out_of_memory>();
+ }
+
+ return void_t{};
+ }
+
+ /**
+ * Add a branch with a leaf attached to the tree
+ */
+ error_or<std::size_t> add(T leaf) {
+ std::size_t index = size();
+ try {
+ /**
+ * Technically we're adding a leaf on a branch
+ */
+ children_.emplace_back(std::move(leaf));
+ }catch(const std::exception& e){
+ (void)e;
+
+ return make_error<err::critical>();
+ }
+
+ return index;
+ }
+
+ /**
+ * Add a branch to the tree with a tree attached
+ */
+ error_or<std::size_t> add() {
+ std::size_t index = size();
+ try {
+
+ children_.emplace_back(Tree{});
+ }catch(const std::exception& e){
+ (void)e;
+
+ return make_error<err::critical>();
+ }
+
+ return index;
+ }
+
+ /**
+ * Returns the amount of branches contained within this tree level
+ */
+ std::size_t size() const {
+ return children_.size();
+ }
+
+ /**
+ * Returns the branch at i
+ */
+ branch<T,Tree>& at(std::size_t i){
+ return children_.at(i);
+ }
+
+ /**
+ * Returns the branch at i
+ */
+ const branch<T,Tree>& at(std::size_t i) const {
+ return children_.at(i);
+ }
+};
+
+template<typename T, typename Tree>
+class branch final {
+private:
+ using type = std::variant<Tree,T>;
+ type tov_;
+
+ /**
+ * We're friend classing the tree since it's way easier this way and the branch and tree
+ * class are intertwined heavily anyway.
+ */
+public:
+ /**
+ *
+ */
+ branch():tov_{Tree{}}{}
+
+ branch(Tree nd):tov_{std::move(nd)}{}
+
+ branch(T val):tov_{std::move(val)}{}
+
+ SAW_FORBID_COPY(branch);
+ SAW_DEFAULT_MOVE(branch);
+
+ template<typename NT>
+ bool is() const {
+ return std::holds_alternative<NT>(tov_);
+ }
+
+ bool is_tree() const {
+ return std::holds_alternative<Tree>(tov_);
+ }
+
+ bool is_value() const {
+ return std::holds_alternative<T>(tov_);
+ }
+
+ template<typename NT>
+ NT& get() {
+ return std::get<NT>(tov_);
+ }
+
+ template<typename NT>
+ const NT& get() const {
+ return std::get<NT>(tov_);
+ }
+
+ Tree& get_tree(){
+ return std::get<Tree>(tov_);
+ }
+
+ const Tree& get_tree() const {
+ return std::get<Tree>(tov_);
+ }
+
+ T& get_value(){
+ return std::get<T>(tov_);
+ }
+
+ const T& get_value() const {
+ return std::get<T>(tov_);
+ }
+
+ template<typename NT>
+ error_or<NT> extract(){
+ if(!is<NT>()){
+ return make_error<err::invalid_state>();
+ }
+
+ NT nd = std::move(std::get<NT>(tov_));
+ tov_ = Tree{};
+
+ return nd;
+ }
+
+ template<typename NT>
+ error_or<NT> replace(type nd){
+ auto eon = extract<NT>();
+ if(eon.is_error()){
+ return eon;
+ }
+
+ tov_ = std::move(nd);
+
+ return eon;
+ }
+
+ error_or<Tree> extract_tree() {
+ return extract<Tree>();
+ }
+
+ error_or<Tree> replace_tree(type nd){
+ return replace<Tree>(std::move(nd));
+ }
+
+ error_or<T> extract_value() {
+ return extract<T>();
+ }
+
+ error_or<T> replace_value(type nd){
+ return replace<T>(std::move(nd));
+ }
+};
+
+template<typename T>
+class tree {
+ private:
+ tree_container<T,tree<T>> data_;
+ public:
+ error_or<void> reserve(std::size_t size){
+ return data_.reserve(size);
+ }
+
+ size_t size() const {
+ return data_.size();
+ }
+
+ error_or<size_t> add() {
+ return data_.add();
+ }
+
+ error_or<size_t> add(T leaf){
+ return data_.add(std::move(leaf));
+ }
+
+ branch<T, tree<T>>& at(size_t i){
+ return data_.at(i);
+ }
+
+ const branch<T, tree<T>>& at(size_t i) const {
+ return data_.at(i);
+ }
+};
+}