From 27a08ccddc94c4945d48445b14c23fe6d186f9ef Mon Sep 17 00:00:00 2001 From: Ashish Chaudhari Date: Tue, 25 Aug 2015 21:09:06 -0700 Subject: prop_tree: Multiple API enhancements to uhd::property - Added desired and coerced values and accessors to property - Added support to register desired subscribers - set APIs don't reallocate storage for a property value - Renamed callback method registration APIs - Registering 2 coercers or publishers for a property will throw - Registering a coercer and a publisher for the same property will throw --- host/include/uhd/property_tree.hpp | 28 +++++++++++---- host/include/uhd/property_tree.ipp | 70 +++++++++++++++++++++++++++++++------- 2 files changed, 78 insertions(+), 20 deletions(-) (limited to 'host/include') diff --git a/host/include/uhd/property_tree.hpp b/host/include/uhd/property_tree.hpp index a92654ba2..ec65c73a0 100644 --- a/host/include/uhd/property_tree.hpp +++ b/host/include/uhd/property_tree.hpp @@ -42,31 +42,38 @@ public: * Register a coercer into the property. * A coercer is a special subscriber that coerces the value. * Only one coercer may be registered per property. - * Registering a coercer replaces the previous coercer. * \param coercer the coercer callback function * \return a reference to this property for chaining */ - virtual property &coerce(const coercer_type &coercer) = 0; + virtual property &set_coercer(const coercer_type &coercer) = 0; /*! * Register a publisher into the property. * A publisher is a special callback the provides the value. * Publishers are useful for creating read-only properties. * Only one publisher may be registered per property. - * Registering a publisher replaces the previous publisher. * \param publisher the publisher callback function * \return a reference to this property for chaining */ - virtual property &publish(const publisher_type &publisher) = 0; + virtual property &set_publisher(const publisher_type &publisher) = 0; /*! * Register a subscriber into the property. - * All subscribers are called when the value changes. + * All desired subscribers are called when the value changes. * Once a subscriber is registered, it cannot be unregistered. * \param subscriber the subscriber callback function * \return a reference to this property for chaining */ - virtual property &subscribe(const subscriber_type &subscriber) = 0; + virtual property &add_desired_subscriber(const subscriber_type &subscriber) = 0; + + /*! + * Register a subscriber into the property. + * All coerced subscribers are called when the value changes. + * Once a subscriber is registered, it cannot be unregistered. + * \param subscriber the subscriber callback function + * \return a reference to this property for chaining + */ + virtual property &add_coerced_subscriber(const subscriber_type &subscriber) = 0; /*! * Update calls all subscribers w/ the current value. @@ -89,7 +96,14 @@ public: * otherwise an internal shadow is used for the value. * \return the current value in the property */ - virtual T get(void) const = 0; + virtual const T get(void) const = 0; + + /*! + * Get the current desired value of this property. + * A desired value does not defined if a property has a publisher. + * \return the current desired value in the property + */ + virtual const T get_desired(void) const = 0; /*! * A property is empty if it has never been set. diff --git a/host/include/uhd/property_tree.ipp b/host/include/uhd/property_tree.ipp index 93962c963..171437450 100644 --- a/host/include/uhd/property_tree.ipp +++ b/host/include/uhd/property_tree.ipp @@ -20,6 +20,7 @@ #include #include +#include #include /*********************************************************************** @@ -34,18 +35,29 @@ public: /* NOP */ } - property &coerce(const typename property::coercer_type &coercer){ + property &set_coercer(const typename property::coercer_type &coercer){ + if (not _coercer.empty()) uhd::assertion_error("cannot register more than one coercer for a property"); + if (not _publisher.empty()) uhd::assertion_error("cannot register a coercer and publisher for the same property"); + _coercer = coercer; return *this; } - property &publish(const typename property::publisher_type &publisher){ + property &set_publisher(const typename property::publisher_type &publisher){ + if (not _publisher.empty()) uhd::assertion_error("cannot register more than one publisher for a property"); + if (not _coercer.empty()) uhd::assertion_error("cannot register a coercer and publisher for the same property"); + _publisher = publisher; return *this; } - property &subscribe(const typename property::subscriber_type &subscriber){ - _subscribers.push_back(subscriber); + property &add_desired_subscriber(const typename property::subscriber_type &subscriber){ + _desired_subscribers.push_back(subscriber); + return *this; + } + + property &add_coerced_subscriber(const typename property::subscriber_type &subscriber){ + _coerced_subscribers.push_back(subscriber); return *this; } @@ -55,16 +67,33 @@ public: } property &set(const T &value){ - _value = boost::shared_ptr(new T(_coercer.empty()? value : _coercer(value))); - BOOST_FOREACH(typename property::subscriber_type &subscriber, _subscribers){ - subscriber(*_value); //let errors propagate + init_or_set_value(_value, value); + BOOST_FOREACH(typename property::subscriber_type &dsub, _desired_subscribers){ + dsub(get_value_ref(_value)); //let errors propagate + } + if (not _coercer.empty()) { + init_or_set_value(_coerced_value, _coercer(get_value_ref(_value))); + } + BOOST_FOREACH(typename property::subscriber_type &csub, _coerced_subscribers){ + csub(get_value_ref(_coercer.empty() ? _value : _coerced_value)); //let errors propagate } return *this; } - T get(void) const{ + const T get(void) const{ if (empty()) throw uhd::runtime_error("Cannot get() on an empty property"); - return _publisher.empty()? *_value : _publisher(); + if (not _publisher.empty()) { + return _publisher(); + } else { + return get_value_ref(_coercer.empty() ? _value : _coerced_value); + } + } + + const T get_desired(void) const{ + if (_value.get() == NULL) throw uhd::runtime_error("Cannot get_desired() on an empty property"); + if (not _publisher.empty()) throw uhd::runtime_error("Cannot get_desired() on a property with a publisher"); + + return get_value_ref(_value); } bool empty(void) const{ @@ -72,10 +101,25 @@ public: } private: - std::vector::subscriber_type> _subscribers; - typename property::publisher_type _publisher; - typename property::coercer_type _coercer; - boost::shared_ptr _value; + static void init_or_set_value(boost::scoped_ptr& scoped_value, const T& init_val) { + if (scoped_value.get() == NULL) { + scoped_value.reset(new T(init_val)); + } else { + *scoped_value = init_val; + } + } + + static const T& get_value_ref(const boost::scoped_ptr& scoped_value) { + if (scoped_value.get() == NULL) throw uhd::assertion_error("Cannot use uninitialized property data"); + return *static_cast(scoped_value.get()); + } + + std::vector::subscriber_type> _desired_subscribers; + std::vector::subscriber_type> _coerced_subscribers; + typename property::publisher_type _publisher; + typename property::coercer_type _coercer; + boost::scoped_ptr _value; + boost::scoped_ptr _coerced_value; }; }} //namespace uhd::/*anon*/ -- cgit v1.2.3