// // Copyright 2011,2014-2016 Ettus Research // Copyright 2018 Ettus Research, a National Instruments Company // Copyright 2019 Ettus Research, a National Instruments Brand // // SPDX-License-Identifier: GPL-3.0-or-later // #ifndef INCLUDED_UHD_PROPERTY_TREE_IPP #define INCLUDED_UHD_PROPERTY_TREE_IPP #include #include #include #include /*********************************************************************** * Implement templated property impl **********************************************************************/ namespace uhd { namespace /*anon*/ { template class property_impl : public property { public: property_impl(property_tree::coerce_mode_t mode) : _coerce_mode(mode) { if (_coerce_mode == property_tree::AUTO_COERCE) { _coercer = DEFAULT_COERCER; } } ~property_impl(void) { /* NOP */ } 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 (_coerce_mode == property_tree::MANUAL_COERCE) uhd::assertion_error( "cannot register coercer for a manually coerced property"); _coercer = coercer; return *this; } 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"); _publisher = publisher; return *this; } 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; } property& update(void) { this->set(this->get()); return *this; } void _set_coerced(const T& value) { init_or_set_value(_coerced_value, value); BOOST_FOREACH ( typename property::subscriber_type& csub, _coerced_subscribers) { csub(get_value_ref(_coerced_value)); // let errors propagate } } property& set(const T& value) { 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()) { _set_coerced(_coercer(get_value_ref(_value))); } else { if (_coerce_mode == property_tree::AUTO_COERCE) uhd::assertion_error("coercer missing for an auto coerced property"); } return *this; } property& set_coerced(const T& value) { if (_coerce_mode == property_tree::AUTO_COERCE) uhd::assertion_error("cannot set coerced value an auto coerced property"); _set_coerced(value); return *this; } const T get(void) const { if (empty()) { throw uhd::runtime_error("Cannot get() on an uninitialized (empty) property"); } if (not _publisher.empty()) { return _publisher(); } else { if (_coerced_value.get() == NULL and _coerce_mode == property_tree::MANUAL_COERCE) throw uhd::runtime_error( "uninitialized coerced value for manually coerced attribute"); return get_value_ref(_coerced_value); } } const T get_desired(void) const { if (_value.get() == NULL) throw uhd::runtime_error( "Cannot get_desired() on an uninitialized (empty) property"); return get_value_ref(_value); } bool empty(void) const { return _publisher.empty() and _value.get() == NULL; } private: static T DEFAULT_COERCER(const T& value) { return 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 *scoped_value.get(); } const property_tree::coerce_mode_t _coerce_mode; 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:: /*********************************************************************** * Implement templated methods for the property tree **********************************************************************/ namespace uhd { template property& property_tree::create(const fs_path& path, coerce_mode_t coerce_mode) { this->_create(path, typename boost::shared_ptr >(new property_impl(coerce_mode))); return this->access(path); } template property& property_tree::access(const fs_path& path) { return *boost::static_pointer_cast >(this->_access(path)); } template typename boost::shared_ptr > property_tree::pop(const fs_path& path) { return boost::static_pointer_cast >(this->_pop(path)); } } // namespace uhd #endif /* INCLUDED_UHD_PROPERTY_TREE_IPP */