Skip to content

Instantly share code, notes, and snippets.

@khardix
Created June 14, 2015 09:27
Show Gist options
  • Save khardix/261e240d0cbd4bf3bfd6 to your computer and use it in GitHub Desktop.
Save khardix/261e240d0cbd4bf3bfd6 to your computer and use it in GitHub Desktop.
Storage tree with multiple possible views
#include <memory>
#include <list>
#include <string>
#include <stdexcept>
#include <iostream>
class Node : public std::enable_shared_from_this<Node>
{
private:
const Node *m_parent; ///< Read-only reference to parent node, modified only on node insert or release
std::list<std::shared_ptr<Node>> m_children; ///< Managed children
std::string m_label; ///< Optional label of the node.
public:
/// Create new node, with optional label.
explicit Node(const std::string &label = std::string());
/// Free node and all managed children.
virtual ~Node() noexcept = default;
// ===== Modifying methods =====
/// Accept aand manage new child.
Node &accept(const std::shared_ptr<Node> &child);
/// Relese direct child, indicated by label. TODO: Release child anywhere in the tree.
std::shared_ptr<Node> release(const std::string &label);
/// Set new label for this node.
Node &label(const std::string &label) { m_label = label; return *this; }
// ===== Queries =====
/// Get node label.
const std::string &label() const noexcept { return m_label; }
/// Get shared pointer to node.
std::shared_ptr<Node> share() { return shared_from_this(); }
std::shared_ptr<const Node> share() const { return shared_from_this(); }
/// Get read access to node's parent, if it exists.
const Node * parent() const { return m_parent; }
/// Get read access to node's children.
const std::list<std::shared_ptr<Node>> &children() const noexcept { return m_children; }
/// Is this node root of the tree?
bool is_root() const noexcept { return !(m_parent); }
/// Is this node leaf of the tree?
bool is_leaf() const noexcept { return m_children.empty(); }
/// Has this node any children (alias for is_leaf)?
bool has_children() const noexcept { return !is_leaf(); }
};
template <class T> class ListView;
template <class T> ListView<T> List(const T &base) { return ListView<T>(base); }
template <> class ListView<Node>
{
private:
const std::list<std::shared_ptr<Node>> &m_items;
public:
typedef std::list<std::shared_ptr<Node>>::const_iterator const_iterator;
explicit ListView(const Node &node) : m_items(node.children()) {}
~ListView() noexcept = default;
const_iterator begin() const { return m_items.begin(); }
const_iterator end() const { return m_items.end(); }
};
int main(int, char **)
try {
auto root = std::make_shared<Node>("Root");
for (auto &&lbl: {"Eldest", "Middle", "Youngest"})
root->accept(std::make_shared<Node>(lbl));
for (auto &&node: List(*root)) {
std::cout << node->label();
if (node->parent())
std::cout << u8" → " << node->parent()->label() << std::endl;
else
std::cout << std::endl;
}
return 0;
}
catch (const std::exception &e) {
std::cerr << "Exception: " << e.what() << std::endl;
return 0xff;
}
Node::Node(const std::string &label)
: m_parent(nullptr), m_children(), m_label(label)
{}
Node &Node::accept(const std::shared_ptr<Node> &child)
{
m_children.push_back(child);
child->m_parent = this;
return *this;
}
std::shared_ptr<Node> Node::release(const std::string &label)
{
typedef std::list<std::shared_ptr<Node>>::iterator iterator;
std::shared_ptr<Node> out;
for (iterator it = m_children.begin(); it != m_children.end(); ++it) {
if ((*it)->label() == label) {
out = *it;
m_children.erase(it);
break;
}
}
return out;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment