diff options
Diffstat (limited to 'modules/core/tree.h')
-rw-r--r-- | modules/core/tree.h | 248 |
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); + } +}; +} |