summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gras/block.hpp36
-rw-r--r--include/gras/detail/block.hpp18
-rw-r--r--include/gras/detail/property.hpp8
-rw-r--r--lib/block_props.cpp28
-rw-r--r--tests/CMakeLists.txt32
-rw-r--r--tests/block_props_test.cpp66
6 files changed, 160 insertions, 28 deletions
diff --git a/include/gras/block.hpp b/include/gras/block.hpp
index d3e9848..477ad8d 100644
--- a/include/gras/block.hpp
+++ b/include/gras/block.hpp
@@ -106,8 +106,9 @@ struct GRAS_API OutputPortConfig
size_t maximum_items;
};
-struct GRAS_API Block : Element
+class GRAS_API Block : public Element
{
+public:
//! Contruct an empty/null block
Block(void);
@@ -254,30 +255,43 @@ struct GRAS_API Block : Element
* that is of the exact type associated with this property.
* Otherwise, set_property with throw a type error.
*
- * Example with template argument to be type explicit:
- * my_block->set_property<size_t>("foo", 42);
+ * Examples with explicit argument types:
+ * my_block->set<size_t>("foo", 42);
+ * my_block->set("foo", size_t(42));
*
* \param key the string to identify this property
* \param value the new value to set to this property
*/
template <typename ValueType>
- void set_property(const std::string &key, const ValueType &value);
+ void set(const std::string &key, const ValueType &value);
/*!
- * Get the value of a registered property.
+ * Get the value of a registered property with reference semantics.
*
- * Note: the user must specify the correct value type
+ * Note: the user must be careful to only use a value
* that is of the exact type associated with this property.
* Otherwise, get_property with throw a type error.
*
- * Example with template argument to be type explicit:
- * const size_t foo = my_block->get_property<size_t>("foo");
+ * Example getting property with reference semantics:
+ * size_t foo; my_block->get("foo", foo);
+ *
+ * \param key the string to identify this property
+ * \param value a reference to set to the result
+ */
+ template <typename ValueType>
+ void get(const std::string &key, ValueType &value);
+
+ /*!
+ * Get the value of a registered property with return semantics.
+ *
+ * Example getting property with return value semantics:
+ * const size_t foo = my_block->get<size_t>("foo");
*
* \param key the string to identify this property
* \return the value of this property
*/
template <typename ValueType>
- ValueType get_property(const std::string &key);
+ ValueType get(const std::string &key);
/*******************************************************************
* Work related routines and fail states
@@ -429,9 +443,6 @@ struct GRAS_API Block : Element
* This method is called by the scheduler to allocate output buffers.
* The user may overload this method to create a custom allocator.
*
- * Example use case:
- * //TODO code example
- *
* \param which_output the output port index number
* \param config holds token and recommended length
* \return a shared ptr to a new buffer queue object
@@ -461,6 +472,7 @@ struct GRAS_API Block : Element
/*******************************************************************
* private implementation guts for template support
******************************************************************/
+private:
void _register_property(const std::string &, PropertyRegistrySptr);
void _set_property(const std::string &, const PMCC &);
PMCC _get_property(const std::string &);
diff --git a/include/gras/detail/block.hpp b/include/gras/detail/block.hpp
index a8bc2b1..c464446 100644
--- a/include/gras/detail/block.hpp
+++ b/include/gras/detail/block.hpp
@@ -6,6 +6,10 @@
namespace gras
{
+/*!
+ * The following functions implement the templated methods in Block
+ */
+
template <typename ClassType, typename ValueType>
GRAS_FORCE_INLINE void Block::register_property(
const std::string &key,
@@ -14,18 +18,24 @@ GRAS_FORCE_INLINE void Block::register_property(
)
{
PropertyRegistrySptr pr;
- pr.reset(new PropertyRegistryImpl<ClassType, ValueType>(this, get, set));
+ pr.reset(new PropertyRegistryImpl<ClassType, ValueType>((ClassType *)this, get, set));
this->_register_property(key, pr);
}
template <typename ValueType>
-GRAS_FORCE_INLINE void Block::set_property(const std::string &key, const ValueType &value)
+GRAS_FORCE_INLINE void Block::set(const std::string &key, const ValueType &value)
+{
+ this->_set_property(key, PMC_M(value));
+}
+
+template <typename ValueType>
+GRAS_FORCE_INLINE void Block::get(const std::string &key, ValueType &value)
{
- return this->_set_property(key, PMC_M(value));
+ value = this->_get_property(key).as<ValueType>();
}
template <typename ValueType>
-GRAS_FORCE_INLINE ValueType Block::get_property(const std::string &key)
+GRAS_FORCE_INLINE ValueType Block::get(const std::string &key)
{
return this->_get_property(key).as<ValueType>();
}
diff --git a/include/gras/detail/property.hpp b/include/gras/detail/property.hpp
index fd13025..2fcdca0 100644
--- a/include/gras/detail/property.hpp
+++ b/include/gras/detail/property.hpp
@@ -21,8 +21,9 @@ struct GRAS_API PropertyRegistry
typedef boost::shared_ptr<PropertyRegistry> PropertyRegistrySptr;
template <typename ClassType, typename ValueType>
-struct PropertyRegistryImpl : PropertyRegistry
+class PropertyRegistryImpl : public PropertyRegistry
{
+public:
PropertyRegistryImpl(
ClassType *my_class,
ValueType(ClassType::*getter)(void),
@@ -36,14 +37,15 @@ struct PropertyRegistryImpl : PropertyRegistry
void set(const PMCC &value)
{
- return _setter(_my_class, value.as<ValueType>());
+ (_my_class->*_setter)(value.as<ValueType>());
}
PMCC get(void)
{
- return PMC_M(_getter(_my_class));
+ return PMC_M((_my_class->*_getter)());
}
+private:
ClassType *_my_class;
ValueType(ClassType::*_getter)(void);
void(ClassType::*_setter)(const ValueType &);
diff --git a/lib/block_props.cpp b/lib/block_props.cpp
index bba9441..99edce7 100644
--- a/lib/block_props.cpp
+++ b/lib/block_props.cpp
@@ -8,18 +8,20 @@ using namespace gras;
PropertyRegistry::PropertyRegistry(void){}
PropertyRegistry::~PropertyRegistry(void){}
+/***********************************************************************
+ * The actual thread-safe implementation of property handling
+ **********************************************************************/
void BlockActor::handle_prop_access(
const PropAccessMessage &message,
const Theron::Address from
)
{
- ASSERT(this->prio_count.Load() != 0);
- this->prio_count.Decrement();
-
+ //setup reply
PropAccessMessage reply;
reply.set = not message.set;
reply.key = message.key;
+ //try to call the property bound method
PropertyRegistrySptr pr = prop_registry[message.key];
if (not pr) reply.error = "no property registered for key: " + message.key;
else try
@@ -36,14 +38,14 @@ void BlockActor::handle_prop_access(
reply.error = "unknown error";
}
+ //send the reply
this->Send(reply, from); //ACK
+ this->highPrioAck();
}
-void Block::_register_property(const std::string &key, PropertyRegistrySptr pr)
-{
- (*this)->block->prop_registry[key] = pr;
-}
-
+/***********************************************************************
+ * A special receiver to handle the property access result
+ **********************************************************************/
struct PropAccessReceiver : Theron::Receiver
{
PropAccessReceiver(void)
@@ -59,6 +61,9 @@ struct PropAccessReceiver : Theron::Receiver
PropAccessMessage message;
};
+/***********************************************************************
+ * Handle the get and set calls from the user's call-stack
+ **********************************************************************/
PMCC BlockActor::prop_access_dispatcher(const std::string &key, const PMCC &value, const bool set)
{
PropAccessReceiver receiver;
@@ -67,7 +72,7 @@ PMCC BlockActor::prop_access_dispatcher(const std::string &key, const PMCC &valu
message.key = key;
message.value = value;
this->Push(message, receiver.GetAddress());
- this->prio_count.Increment();
+ this->highPrioPreNotify();
receiver.Wait();
if (not receiver.message.error.empty())
{
@@ -76,6 +81,11 @@ PMCC BlockActor::prop_access_dispatcher(const std::string &key, const PMCC &valu
return receiver.message.value;
}
+void Block::_register_property(const std::string &key, PropertyRegistrySptr pr)
+{
+ (*this)->block->prop_registry[key] = pr;
+}
+
void Block::_set_property(const std::string &key, const PMCC &value)
{
(*this)->block->prop_access_dispatcher(key, value, true);
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
index 27a2965..23a834e 100644
--- a/tests/CMakeLists.txt
+++ b/tests/CMakeLists.txt
@@ -4,6 +4,38 @@
include(GrTest)
+########################################################################
+# unit test suite
+########################################################################
+find_package(Boost COMPONENTS unit_test_framework)
+
+if (NOT Boost_FOUND)
+ return()
+endif()
+
+set(test_sources
+ block_props_test.cpp
+)
+
+include_directories(${GRAS_INCLUDE_DIRS})
+include_directories(${Boost_INCLUDE_DIRS})
+link_directories(${Boost_LIBRARY_DIRS})
+
+#turn each test cpp file into an executable with an int main() function
+add_definitions(-DBOOST_TEST_DYN_LINK -DBOOST_TEST_MAIN)
+
+#for each source: build an executable, register it as a test
+foreach(test_source ${test_sources})
+ get_filename_component(test_name ${test_source} NAME_WE)
+ add_executable(${test_name} ${test_source})
+ target_link_libraries(${test_name} ${Boost_LIBRARIES} ${GRAS_LIBRARIES})
+ set(GR_TEST_LIBRARY_DIRS ${Boost_LIBRARY_DIRS})
+ GR_ADD_TEST(${test_name} ${test_name})
+endforeach(test_source)
+
+########################################################################
+# Python unit tests
+########################################################################
include(GrPython)
set(PYTHON_EXECUTABLE ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B})
diff --git a/tests/block_props_test.cpp b/tests/block_props_test.cpp
new file mode 100644
index 0000000..ded4273
--- /dev/null
+++ b/tests/block_props_test.cpp
@@ -0,0 +1,66 @@
+// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information.
+
+#include <boost/test/unit_test.hpp>
+#include <iostream>
+
+#include <gras/block.hpp>
+
+struct MyBlock : gras::Block
+{
+ MyBlock(void):
+ gras::Block("MyBlock")
+ {
+ foo = 0;
+ this->register_property("foo", &MyBlock::get_foo, &MyBlock::set_foo);
+ }
+
+ //dummy work
+ void work(const InputItems &, const OutputItems &){}
+
+ size_t get_foo(void)
+ {
+ return foo;
+ }
+
+ void set_foo(const size_t &new_foo)
+ {
+ foo = new_foo;
+ }
+
+ size_t foo;
+};
+
+BOOST_AUTO_TEST_CASE(test_property_set_get_with_return)
+{
+ MyBlock my_block;
+ BOOST_CHECK_EQUAL(my_block.foo, size_t(0));
+
+ my_block.set("foo", size_t(42));
+ BOOST_CHECK_EQUAL(my_block.foo, size_t(42));
+
+ const size_t my_foo = my_block.get<size_t>("foo");
+ BOOST_CHECK_EQUAL(my_foo, size_t(42));
+}
+
+BOOST_AUTO_TEST_CASE(test_property_set_get_with_reference)
+{
+ MyBlock my_block;
+ BOOST_CHECK_EQUAL(my_block.foo, size_t(0));
+
+ my_block.set("foo", size_t(42));
+ BOOST_CHECK_EQUAL(my_block.foo, size_t(42));
+
+ size_t my_foo; my_block.get("foo", my_foo);
+ BOOST_CHECK_EQUAL(my_foo, size_t(42));
+}
+
+BOOST_AUTO_TEST_CASE(test_property_errors)
+{
+ MyBlock my_block;
+
+ //property does not exist
+ BOOST_CHECK_THROW(my_block.get<size_t>("bar"), std::exception);
+
+ //wrong type for property
+ BOOST_CHECK_THROW(my_block.set("foo", double(42)), std::exception);
+}