// SPDX-License-Identifier: GPL-3.0-or-later #include #include #include #include "node.h" unsigned int node::node_id = 0; node::node(const std::string &name) : name(name) { node_id++; if (name.empty()) { std::stringstream node_sm; node_sm << "node_" << node_id; this->name = node_sm.str(); } } node::~node() { std::cout << "enter ~node() of \"" << get_name() << "\"" << std::endl; this->destroy = true; for (node *child : children) { if (!child->destroy) { delete child; } } std::cout << "leave ~node() of \"" << get_name() << "\"" << std::endl; } std::string node::get_name() const { return name; } void node::set_name(const std::string& new_name) { this->name = new_name; } std::size_t node::get_nr_children() const { return children.size(); } node *node::get_child(std::size_t i) const { return children[i]; } void node::add_child(node *child) { children.push_back(child); } void node::print(std::ostream &str, unsigned int depth) const { str << std::string(depth, '\t') << get_name() << std::endl; for (node *child : children) { child->print(str, depth + 1); } } std::string node::print_recursive(unsigned int depth, std::set visited) const { std::stringstream output; output << std::string(depth, '\t') << get_name(); visited.insert(this); for (const node *child : children) { // std::set::contains is only implemented in C++20 if (visited.find(child) == visited.end()) { output << std::endl << child->print_recursive(depth + 1, visited); } else { output << " [↝ " << child->get_name() << "]"; } } if (depth == 0) output << std::endl; return output.str(); } std::string node::print_iterative() const { std::stringstream output; std::stack> stack; stack.push({this, 0}); std::set visited = {}; while (!stack.empty()) { const node *n = nullptr; unsigned int depth; std::tie(n, depth) = stack.top(); stack.pop(); if (visited.find(n) == visited.end()) { if (n != this) output << std::endl; output << std::string(depth, '\t') << n->get_name(); // Complex iteration (not default vector iteration) is necessary, // to achieve the same output as the recursive approach. // Otherwise, the order of the children is reversed (due to LIFO). for (std::size_t i = n->get_nr_children(); i > 0; i--) { stack.push({n->get_child(i - 1), depth + 1}); } } else { output << " [↝ " << n->get_name() << "]"; } visited.insert(n); } output << std::endl; return output.str(); } std::ostream &operator<<(std::ostream &os, node &n) { n.print(os); return os; } node *create_complete_tree(std::size_t nr_child_nodes, unsigned int tree_depth) { node *n = new node(); if (tree_depth > 1) { for (std::size_t i = 0; i < nr_child_nodes; i++) { n->add_child(create_complete_tree(nr_child_nodes, tree_depth - 1)); } } return n; }