#pragma once #include #include #include "error.h" namespace saw { /** * Container with a simplistic approach to a branch */ template 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 class tree final { private: /** * Object holding the treeed branch instances */ using branch = std::variant>; std::vector children_; public: /** * Default constructor */ tree() = default; /** * Destructor */ ~tree() = default; SAW_FORBID_COPY(tree); SAW_DEFAULT_MOVE(tree); /** * Reserve space for siz elements */ error_or reserve(std::size_t siz){ try{ children_.reserve(siz); }catch(const std::exception& e){ (void) e; return make_error(); } return void_t{}; } /** * Add a branch with a leaf attached to the tree */ error_or 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(); } return index; } /** * Add a branch to the tree with a tree attached */ error_or add() { std::size_t index = size(); try { children_.emplace_back(tree{}); }catch(const std::exception& e){ (void)e; return make_error(); } 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& at(std::size_t i){ return children_.at(i); } /** * Returns the branch at i */ const branch& at(std::size_t i) const { return children_.at(i); } }; template class branch final { private: using type = std::variant,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. */ friend class tree; 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 bool is() const { return std::holds_alternative(tov_); } bool is_tree() const { return std::holds_alternative(tov_); } bool is_value() const { return std::holds_alternative(tov_); } template NT& get() { return std::get(tov_); } template const NT& get() const { return std::get(tov_); } tree& get_tree(){ return std::get>(tov_); } const tree& get_tree() const { return std::get>(tov_); } T& get_value(){ return std::get(tov_); } const T& get_value() const { return std::get(tov_); } template error_or extract(){ if(!is()){ return make_error(); } NT nd = std::move(std::get(tov_)); tov_ = tree{}; return nd; } template error_or replace(type nd){ auto eon = extract(); if(eon.is_error()){ return eon; } tov_ = std::move(nd); return eon; } error_or> extract_tree() { return extract>(); } error_or> replace_tree(type nd){ return replace>(std::move(nd)); } error_or extract_value() { return extract(); } error_or replace_value(type nd){ return replace(std::move(nd)); } }; }