DOM: Implemented DOM::Node object

This commit is contained in:
Paul Beckingham 2017-04-30 00:00:14 -04:00
parent eba68ac2ff
commit 4c53da5be1
2 changed files with 128 additions and 51 deletions

View file

@ -491,17 +491,19 @@ DOM::~DOM ()
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
void DOM::addSource ( void DOM::addSource (
const std::string&, const std::string& reference,
bool (*provider)(const std::string&, Variant&)) bool (*provider)(const std::string&, Variant&))
{ {
// TODO Implement. if (_node == nullptr)
_node = new DOM::Node ();
_node->addSource (reference, provider);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
bool DOM::valid (const std::string& reference) const bool DOM::valid (const std::string& reference) const
{ {
// TODO Implement. return _node && _node->find (reference) != nullptr;
return false;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -509,100 +511,161 @@ Variant DOM::get (const std::string& reference) const
{ {
Variant v (""); Variant v ("");
// Find the provider. if (_node)
// TODO Start at the root of the tree.
for (const auto& element : decomposeReference (reference))
{ {
// TODO If tree contains a named node 'element', capture the provider, if any. auto node = _node->find (reference);
if (node != nullptr &&
node->_provider != nullptr)
{
if (node->_provider (reference, v))
return v;
}
} }
return v; return v;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> DOM::decomposeReference (const std::string& reference) const int DOM::count () const
{
if (_node)
return _node->count ();
return 0;
}
////////////////////////////////////////////////////////////////////////////////
std::vector <std::string> DOM::decomposeReference (const std::string& reference)
{ {
return split (reference, '.'); return split (reference, '.');
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
int DOM::count () const std::string DOM::dump () const
{ {
// Recurse and count the branches. if (_node)
int total {0}; return _node->dump ();
for (auto& i : _branches)
total += i->count ();
return total; return "";
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::shared_ptr <DOM> DOM::find (const std::string& path) DOM::Node::~Node ()
{ {
std::vector <std::string> elements = split (path, '.'); for (auto& branch : _branches)
delete branch;
}
// Must start at the trunk. ////////////////////////////////////////////////////////////////////////////////
auto cursor = std::make_shared <DOM> (*this); void DOM::Node::addSource (
auto it = elements.begin (); const std::string& reference,
if (cursor->_name != *it) bool (*provider)(const std::string&, Variant&))
return nullptr; {
auto cursor = this;
// Perhaps the trunk is what is needed? for (const auto& element : DOM::decomposeReference (reference))
if (elements.size () == 1)
return cursor;
// Now look for the next branch.
for (++it; it != elements.end (); ++it)
{ {
bool found = false; auto found {false};
for (auto& branch : cursor->_branches)
// If the cursor has a branch that matches *it, proceed.
for (auto i = cursor->_branches.begin (); i != cursor->_branches.end (); ++i)
{ {
if ((*i)->_name == *it) if (branch->_name == element)
{ {
cursor = *i; cursor = branch;
found = true; found = true;
break; break;
} }
} }
if (! found) if (! found)
return nullptr; {
auto branch = new DOM::Node ();
branch->_name = element;
cursor->_branches.push_back (branch);
cursor = branch;
}
} }
return cursor; cursor->_provider = provider;
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string DOM::dumpNode ( // A valid reference is one that has a provider function.
const std::shared_ptr <DOM> t, bool DOM::Node::valid (const std::string& reference) const
{
return find (reference) != nullptr;
}
////////////////////////////////////////////////////////////////////////////////
const DOM::Node* DOM::Node::find (const std::string& reference) const
{
auto cursor = this;
for (const auto& element : DOM::decomposeReference (reference))
{
auto found {false};
for (auto& branch : cursor->_branches)
{
if (branch->_name == element)
{
cursor = branch;
found = true;
break;
}
}
if (! found)
break;
}
if (reference.length () && cursor != this)
return cursor;
return nullptr;
}
////////////////////////////////////////////////////////////////////////////////
int DOM::Node::count () const
{
// Recurse and count the branches.
int total {0};
for (auto& branch : _branches)
{
if (branch->_provider)
++total;
total += branch->count ();
}
return total;
}
////////////////////////////////////////////////////////////////////////////////
std::string DOM::Node::dumpNode (
const DOM::Node* node,
int depth) const int depth) const
{ {
std::stringstream out; std::stringstream out;
// Dump node // Indent.
for (int i = 0; i < depth; ++i) out << std::string (depth * 2, ' ');
out << " ";
out out << "\033[31m" << node->_name << "\033[0m";
// Useful for debugging tree node new/delete errors.
// << std::hex << t << " " if (node->_provider)
<< "\033[1m" << t->_name << "\033[0m\n"; out << " 0x" << std::hex << (long long) (void*) node->_provider;
out << '\n';
// Recurse for branches. // Recurse for branches.
for (auto& b : t->_branches) for (auto& b : node->_branches)
out << dumpNode (b, depth + 1); out << dumpNode (b, depth + 1);
return out.str (); return out.str ();
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
std::string DOM::dump () const std::string DOM::Node::dump () const
{ {
std::stringstream out; std::stringstream out;
out << "DOM (" << count () << " nodes)\n" out << "DOM::Node (" << count () << " nodes)\n"
<< dumpNode (std::make_shared <DOM> (*this), 1); << dumpNode (this, 1);
return out.str (); return out.str ();
} }

View file

@ -41,10 +41,13 @@ public:
~DOM (); ~DOM ();
void addSource (const std::string&, bool (*)(const std::string&, Variant&)); void addSource (const std::string&, bool (*)(const std::string&, Variant&));
bool valid (const std::string&) const; bool valid (const std::string&) const;
/*
// TODO Task object should register a generic provider.
Variant get (const Task&, const std::string&) const; Variant get (const Task&, const std::string&) const;
*/
Variant get (const std::string&) const; Variant get (const std::string&) const;
int count () const; int count () const;
std::shared_ptr <DOM> find (const std::string&); static std::vector <std::string> decomposeReference (const std::string&);
std::string dump () const; std::string dump () const;
private: private:
@ -52,6 +55,17 @@ private:
{ {
public: public:
~Node (); ~Node ();
void addSource (const std::string&, bool (*)(const std::string&, Variant&));
bool valid (const std::string&) const;
const DOM::Node* find (const std::string&) const;
int count () const;
std::string dumpNode (const DOM::Node*, int) const;
std::string dump () const;
public:
std::string _name {"Unknown"};
bool (*_provider)(const std::string&, Variant&) {nullptr};
std::vector <DOM::Node*> _branches {};
}; };
private: private: