#pragma once #include #include #include #include template class Tree; template class Tree { protected: std::optional Value; std::vector> Children; public: bool has_value() const noexcept { return Value.has_value(); } bool has_children() const noexcept { return !Children.empty(); } size_t size() const noexcept { return Children.size(); } size_t recursive_size() const { size_t size_sum = 0; for(const Tree& Child : Children) size_sum += Child.recursive_size(); size_sum += size(); return size_sum + 1; } Tree& append(Tree item) { Children.push_back(std::move(item)); return *this; } Tree& erase(size_t position) { if(position >= Children.size()) Children.erase(); } Tree& insert(size_t position, Tree item) { if(position > Children.size()) throw std::out_of_range("Attempted inserting tree child out of range!"); Children.insert(Children.begin() + position, std::move(item)); return *this; } Tree& at(size_t index) { return Children.at(index); } const Tree& at(size_t index) const { return Children.at(index); } // Will throw std::bad_optional_access if Value doesn't exist operator T&() { return Value.value(); } operator const T&() const { return Value.value(); } operator std::optional&() { return Value; } operator const std::optional&() const { return Value; } Tree& operator[](size_t index) { return Children[index]; } const Tree& operator[](size_t index) const { return Children[index]; } Tree& operator+=(Tree item) { append(std::move(item)); return *this; } Tree& operator=(T value) { Value = std::move(value); return *this; } Tree& operator=(const Tree&) = default; Tree& operator=(Tree&&) = default; Tree(const Tree& other) : Value(other.Value), Children(other.Children) {} Tree(Tree&& other) : Value(std::move(other.Value)), Children(std::move(other.Children)) {} Tree() { } Tree(T Value) : Value(std::move(Value)) { } Tree(std::vector> Children) : Children(std::move(Children)) { } Tree(T Value, std::vector> Children) : Value(std::move(Value)), Children(std::move(Children)) { } };