Created
June 14, 2015 09:27
-
-
Save khardix/261e240d0cbd4bf3bfd6 to your computer and use it in GitHub Desktop.
Storage tree with multiple possible views
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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