summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosh Blum2013-03-22 01:54:16 -0700
committerJosh Blum2013-03-22 01:54:16 -0700
commit9ea77e78ade12ed5402ed9f3df1f10d9d4d27559 (patch)
tree7355daec02ae124dfd89b821bd21723239f0f03a
parenta54708334425472d277e77c394688bab4cac607a (diff)
downloadsandhi-9ea77e78ade12ed5402ed9f3df1f10d9d4d27559.tar.gz
sandhi-9ea77e78ade12ed5402ed9f3df1f10d9d4d27559.tar.bz2
sandhi-9ea77e78ade12ed5402ed9f3df1f10d9d4d27559.zip
gras: we now have the element tree interface
-rw-r--r--include/gras/element.hpp31
-rw-r--r--include/gras/hier_block.hpp9
-rw-r--r--lib/block_props.cpp47
-rw-r--r--lib/element.cpp57
-rw-r--r--lib/element_impl.hpp6
-rw-r--r--lib/hier_block.cpp15
-rw-r--r--tests/block_props_test.py33
7 files changed, 119 insertions, 79 deletions
diff --git a/include/gras/element.hpp b/include/gras/element.hpp
index 3211ac3..13ebb7c 100644
--- a/include/gras/element.hpp
+++ b/include/gras/element.hpp
@@ -19,6 +19,8 @@ struct ElementImpl;
typedef boost::shared_ptr<ElementImpl> ElementBase;
+struct Block;
+
struct GRAS_API Element : ElementBase, boost::enable_shared_from_this<Element>
{
@@ -42,6 +44,35 @@ struct GRAS_API Element : ElementBase, boost::enable_shared_from_this<Element>
std::string to_string(void) const;
/*******************************************************************
+ * element tree interface
+ ******************************************************************/
+
+ /*!
+ * Adopt an element as a child under the given name.
+ *
+ * This API allows the user to structure a hierarchy of elements.
+ * This element will become the parent of the child element.
+ *
+ * \param name the name of the child node
+ * \param child an element to be adopted
+ */
+ void adopt_element(const std::string &name, const Element &child);
+
+ /*!
+ * Lookup a block in the element tree hierarchy.
+ *
+ * Paths are unix style, absolte and relatives paths are possible.
+ * This call throws an invalid argument when bad paths are given.
+ *
+ * Example path: /my_hier_block/my_block0
+ * Example path: ../my_block1
+ *
+ * \param path a path to a block (leaf) in the tree
+ * \return a pointer to the block
+ */
+ Block *lookup_block(const std::string &path);
+
+ /*******************************************************************
* Compatibility for dealing with shared ptrs of Elements
******************************************************************/
/*!
diff --git a/include/gras/hier_block.hpp b/include/gras/hier_block.hpp
index 25c1424..398024e 100644
--- a/include/gras/hier_block.hpp
+++ b/include/gras/hier_block.hpp
@@ -44,15 +44,6 @@ struct GRAS_API HierBlock : Element
*/
virtual void commit(void);
- /*******************************************************************
- * property tree interface
- ******************************************************************/
-
- /*!
- * Register a subelement's properties into this element.
- */
- void register_subelement(const std::string &node, const Element &subelem);
-
};
} //namespace gras
diff --git a/lib/block_props.cpp b/lib/block_props.cpp
index ab8b642..672200b 100644
--- a/lib/block_props.cpp
+++ b/lib/block_props.cpp
@@ -2,8 +2,6 @@
#include "element_impl.hpp"
#include <gras/block.hpp>
-#include <boost/foreach.hpp>
-#include <boost/algorithm/string.hpp>
using namespace gras;
@@ -76,51 +74,8 @@ struct PropAccessReceiver : Theron::Receiver
* Handle the get and set calls from the user's call-stack
**********************************************************************/
template <typename ActorType>
-static PMCC prop_access_dispatcher(ActorType &actor, const std::string &path, const PMCC &value, const bool set)
+static PMCC prop_access_dispatcher(ActorType &actor, const std::string &key, const PMCC &value, const bool set)
{
- //split the paths into nodes
- std::vector<std::string> nodes;
- boost::split(nodes, path, boost::is_any_of("/"));
-
- //iterate through the path to find the element
- std::string key;
- Element elem = *(actor->block_ptr);
- size_t i = 0;
- BOOST_FOREACH(const std::string &node, nodes)
- {
- i++;
- if (node == "" and i == 1) //find root
- {
- while (elem->_parent) elem = elem->_parent;
- continue;
- }
- if (node == ".") //this dir
- {
- continue;
- }
- if (node == "..") //up a dir
- {
- if (not elem->_parent) throw std::runtime_error(
- "Property tree lookup fail - null parent: " + path
- );
- elem = elem->_parent;
- continue;
- }
- if (i == nodes.size() or elem->block) //leaf
- {
- key = node;
- if (i != nodes.size() or not elem->block) throw std::runtime_error(
- "Property tree lookup fail - beyond leaf: " + path
- );
- continue;
- }
- if (elem->_subelems.count(node) == 0) throw std::runtime_error(
- "Property tree lookup fail - no such path: " + path
- );
- elem = elem->_subelems[node];
- }
-
- //now send a message to the actor to perform the action
PropAccessReceiver receiver;
PropAccessMessage message;
message.set = set;
diff --git a/lib/element.cpp b/lib/element.cpp
index 368dbea..e6c8499 100644
--- a/lib/element.cpp
+++ b/lib/element.cpp
@@ -4,6 +4,8 @@
#include <gras/element.hpp>
#include <boost/format.hpp>
#include <boost/detail/atomic_count.hpp>
+#include <boost/foreach.hpp>
+#include <boost/algorithm/string.hpp>
static boost::detail::atomic_count unique_id_pool(0);
@@ -45,3 +47,58 @@ std::string Element::to_string(void) const
{
return (*this)->id;
}
+
+void Element::adopt_element(const std::string &name, const Element &child)
+{
+ if (child->parent) throw std::invalid_argument(str(boost::format(
+ "Could not register child %s into %s.\n"
+ "The child %s already has parent %s.\n"
+ )
+ % child.to_string()
+ % this->to_string()
+ % child.to_string()
+ % child->parent.to_string()
+ ));
+ //TODO check name not already taken
+ child->parent = *this;
+ (*this)->children[name] = child;
+}
+
+Block *Element::lookup_block(const std::string &path)
+{
+ //split the paths into nodes
+ std::vector<std::string> nodes;
+ boost::split(nodes, path, boost::is_any_of("/"));
+
+ //iterate through the path to find the element
+ boost::shared_ptr<ElementImpl> elem = *this;
+ size_t i = 0;
+ BOOST_FOREACH(const std::string &node, nodes)
+ {
+ i++;
+ if (node == "" and i == 1) //find root
+ {
+ while (elem->parent) elem = elem->parent;
+ continue;
+ }
+ if (node == ".") //this dir
+ {
+ continue;
+ }
+ if (node == "..") //up a dir
+ {
+ if (not elem->parent) throw std::invalid_argument(
+ "Element tree lookup fail - null parent: " + path
+ );
+ elem = elem->parent;
+ continue;
+ }
+ if (elem->children.count(node) == 0) throw std::invalid_argument(
+ "Element tree lookup fail - no such path: " + path
+ );
+ elem = elem->children[node];
+ }
+
+ //return block ptr as result
+ return elem->block->block_ptr;
+}
diff --git a/lib/element_impl.hpp b/lib/element_impl.hpp
index ccdbb54..869006e 100644
--- a/lib/element_impl.hpp
+++ b/lib/element_impl.hpp
@@ -35,9 +35,9 @@ struct ElementImpl
Token token;
GlobalBlockConfig top_config;
- //hier block stuff
- Element _parent;
- std::map<std::string, Element> _subelems;
+ //element tree stuff
+ Element parent;
+ std::map<std::string, Element> children;
//things may be in this element
boost::shared_ptr<Apology::Topology> topology;
diff --git a/lib/hier_block.cpp b/lib/hier_block.cpp
index cfaca86..b7ffe4c 100644
--- a/lib/hier_block.cpp
+++ b/lib/hier_block.cpp
@@ -76,18 +76,3 @@ void HierBlock::commit(void)
{
(*this)->topology->commit();
}
-
-void HierBlock::register_subelement(const std::string &node, const Element &subelem)
-{
- if (subelem->_parent) throw std::runtime_error(str(boost::format(
- "Could not register subelement %s into %s.\n"
- "The subelement %s already has parent %s.\n"
- )
- % subelem.to_string()
- % this->to_string()
- % subelem.to_string()
- % subelem->_parent.to_string()
- ));
- subelem->_parent = *this;
- (*this)->_subelems[node] = subelem;
-}
diff --git a/tests/block_props_test.py b/tests/block_props_test.py
index ccc6dd2..b392693 100644
--- a/tests/block_props_test.py
+++ b/tests/block_props_test.py
@@ -47,19 +47,40 @@ class BlockPropsTest(unittest.TestCase):
except: threw = True
self.assertTrue(threw)
- def test_property_tree_paths(self):
+ def test_element_tree_paths(self):
my_block = MyBlock()
tb = gras.TopBlock()
hb = gras.HierBlock()
- tb.register_subelement("my_hier", hb)
- hb.register_subelement("my_block", my_block)
+ tb.adopt_element("my_hier", hb)
+ hb.adopt_element("my_block", my_block)
my_block.set("foo", 42)
-
self.assertEqual(my_block.get("foo"), 42)
- self.assertEqual(my_block.get("./../my_block/foo"), 42)
- self.assertEqual(my_block.get("/my_hier/my_block/foo"), 42)
+
+ my_block0 = tb.lookup_block('/my_hier/my_block')
+ self.assertEqual(my_block0.get("foo"), 42)
+
+ my_block1 = hb.lookup_block('my_block')
+ self.assertEqual(my_block1.get("foo"), 42)
+
+ my_block2 = hb.lookup_block('./../my_hier/my_block')
+ self.assertEqual(my_block2.get("foo"), 42)
+
+ threw = False
+ try: hb.lookup_block('../../my_hier/my_block')
+ except: threw = True
+ self.assertTrue(threw)
+
+ threw = False
+ try: hb.lookup_block('../../my_hier/my_block0')
+ except: threw = True
+ self.assertTrue(threw)
+
+ threw = False
+ try: hb.lookup_block('../../my_hier/my_block/test')
+ except: threw = True
+ self.assertTrue(threw)
if __name__ == '__main__':
unittest.main()