aboutsummaryrefslogtreecommitdiffstats
path: root/host/lib/include/uhdlib/experts
diff options
context:
space:
mode:
Diffstat (limited to 'host/lib/include/uhdlib/experts')
-rw-r--r--host/lib/include/uhdlib/experts/expert_container.hpp352
-rw-r--r--host/lib/include/uhdlib/experts/expert_factory.hpp596
-rw-r--r--host/lib/include/uhdlib/experts/expert_nodes.hpp964
3 files changed, 1009 insertions, 903 deletions
diff --git a/host/lib/include/uhdlib/experts/expert_container.hpp b/host/lib/include/uhdlib/experts/expert_container.hpp
index da52f6f4a..0beae5504 100644
--- a/host/lib/include/uhdlib/experts/expert_container.hpp
+++ b/host/lib/include/uhdlib/experts/expert_container.hpp
@@ -8,185 +8,189 @@
#ifndef INCLUDED_UHD_EXPERTS_EXPERT_CONTAINER_HPP
#define INCLUDED_UHD_EXPERTS_EXPERT_CONTAINER_HPP
-#include <uhdlib/experts/expert_nodes.hpp>
#include <uhd/config.hpp>
#include <uhd/utils/noncopyable.hpp>
-#include <memory>
+#include <uhdlib/experts/expert_nodes.hpp>
#include <boost/thread/recursive_mutex.hpp>
+#include <memory>
namespace uhd { namespace experts {
- enum auto_resolve_mode_t {
- AUTO_RESOLVE_OFF,
- AUTO_RESOLVE_ON_READ,
- AUTO_RESOLVE_ON_WRITE,
- AUTO_RESOLVE_ON_READ_WRITE
- };
-
- class UHD_API expert_container : private uhd::noncopyable, public node_retriever_t {
- public: //Methods
- typedef std::shared_ptr<expert_container> sptr;
-
- virtual ~expert_container() {};
-
- /*!
- * Return the name of this container
- */
- virtual const std::string& get_name() const = 0;
-
- /*!
- * Resolves all the nodes in this expert graph.
- *
- * Dependency analysis is performed on the graph and nodes
- * are resolved in a topologically sorted order to ensure
- * that no nodes receive stale data.
- * Nodes and their dependencies are resolved only if they are
- * dirty i.e. their contained values have changed since the
- * last resolve.
- * This call requires an acyclic expert graph.
- *
- * \param force If true then ignore dirty state and resolve all nodes
- * \throws uhd::runtime_error if graph cannot be resolved
- */
- virtual void resolve_all(bool force = false) = 0;
-
- /*!
- * Resolves all the nodes that depend on the specified node.
- *
- * Dependency analysis is performed on the graph and nodes
- * are resolved in a topologically sorted order to ensure
- * that no nodes receive stale data.
- * Nodes and their dependencies are resolved only if they are
- * dirty i.e. their contained values have changed since the
- * last resolve.
- * This call requires an acyclic expert graph.
- *
- * \param node_name Name of the node to start resolving from
- * \throws uhd::lookup_error if node_name not in container
- * \throws uhd::runtime_error if graph cannot be resolved
- *
- */
- virtual void resolve_from(const std::string& node_name) = 0;
-
- /*!
- * Resolves all the specified node and all of its dependencies.
- *
- * Dependency analysis is performed on the graph and nodes
- * are resolved in a topologically sorted order to ensure
- * that no nodes receive stale data.
- * Nodes and their dependencies are resolved only if they are
- * dirty i.e. their contained values have changed since the
- * last resolve.
- * This call requires an acyclic expert graph.
- *
- * \param node_name Name of the node to resolve
- * \throws uhd::lookup_error if node_name not in container
- * \throws uhd::runtime_error if graph cannot be resolved
- *
- */
- virtual void resolve_to(const std::string& node_name) = 0;
-
- /*!
- * Return a node retriever object for this container
- */
- virtual const node_retriever_t& node_retriever() const = 0;
-
- /*!
- * Returns a DOT (graph description language) representation
- * of the expert graph. The output has labels for the node
- * name, node type (data or worker) and the underlying
- * data type for each node.
- *
- */
- virtual std::string to_dot() const = 0;
-
- /*!
- * Runs several sanity checks on the underlying graph to
- * flag dependency issues. Outputs of the checks are
- * logged to the console so UHD_EXPERTS_VERBOSE_LOGGING
- * must be enabled to see the results
- *
- */
- virtual void debug_audit() const = 0;
-
- private:
- /*!
- * Lookup a node with the specified name in the contained graph
- *
- * If the node is found, a reference to the node is returned.
- * If the node is not found, uhd::lookup_error is thrown
- * lookup can return a data or a worker node
- * \implements uhd::experts::node_retriever_t
- *
- * \param name Name of the node to find
- *
- */
- virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
- virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
-
- /*!
- * expert_factory is a friend of expert_container and
- * handles all operations that change the structure of
- * the underlying dependency graph.
- * The expert_container instance owns all data and worker
- * nodes and is responsible for release storage on destruction.
- * However, the expert_factory allocates storage for the
- * node and passes them into the expert_container using the
- * following "protected" API calls.
- *
- */
- friend class expert_factory;
-
- /*!
- * Creates an empty instance of expert_container with the
- * specified name.
- *
- * \param name Name of the container
- */
- static sptr make(const std::string& name);
-
- /*!
- * Returns a reference to the resolver mutex.
- *
- * The resolver mutex guarantees that external operations
- * to data-nodes are serialized with resolves of this
- * container.
- *
- */
- virtual boost::recursive_mutex& resolve_mutex() = 0;
-
- /*!
- * Add a data node to the expert graph
- *
- * \param data_node Pointer to a fully constructed data node object
- * \resolve_mode Auto resolve options: Choose from "disabled" and resolve on "read", "write" or "both"
- * \throws uhd::runtime_error if node already exists or is of a wrong type (recoverable)
- * \throws uhd::assertion_error for other failures (unrecoverable. will clear the graph)
- *
- */
- virtual void add_data_node(dag_vertex_t* data_node, auto_resolve_mode_t resolve_mode = AUTO_RESOLVE_OFF) = 0;
-
- /*!
- * Add a worker node to the expert graph
- *
- * \param worker Pointer to a fully constructed worker object
- * \throws uhd::runtime_error if worker already exists or is of a wrong type (recoverable)
- * \throws uhd::assertion_error for other failures (unrecoverable. will clear the graph)
- *
- */
- virtual void add_worker(worker_node_t* worker) = 0;
-
- /*!
- * Release all storage for this object. This will delete all contained
- * data and worker nodes and remove all dependency relationship and
- * resolve callbacks.
- *
- * The object will be restored to its newly constructed state. Will not
- * throw.
- */
- virtual void clear() = 0;
- };
-
-}}
+enum auto_resolve_mode_t {
+ AUTO_RESOLVE_OFF,
+ AUTO_RESOLVE_ON_READ,
+ AUTO_RESOLVE_ON_WRITE,
+ AUTO_RESOLVE_ON_READ_WRITE
+};
+
+class UHD_API expert_container : private uhd::noncopyable, public node_retriever_t
+{
+public: // Methods
+ typedef std::shared_ptr<expert_container> sptr;
+
+ virtual ~expert_container(){};
+
+ /*!
+ * Return the name of this container
+ */
+ virtual const std::string& get_name() const = 0;
+
+ /*!
+ * Resolves all the nodes in this expert graph.
+ *
+ * Dependency analysis is performed on the graph and nodes
+ * are resolved in a topologically sorted order to ensure
+ * that no nodes receive stale data.
+ * Nodes and their dependencies are resolved only if they are
+ * dirty i.e. their contained values have changed since the
+ * last resolve.
+ * This call requires an acyclic expert graph.
+ *
+ * \param force If true then ignore dirty state and resolve all nodes
+ * \throws uhd::runtime_error if graph cannot be resolved
+ */
+ virtual void resolve_all(bool force = false) = 0;
+
+ /*!
+ * Resolves all the nodes that depend on the specified node.
+ *
+ * Dependency analysis is performed on the graph and nodes
+ * are resolved in a topologically sorted order to ensure
+ * that no nodes receive stale data.
+ * Nodes and their dependencies are resolved only if they are
+ * dirty i.e. their contained values have changed since the
+ * last resolve.
+ * This call requires an acyclic expert graph.
+ *
+ * \param node_name Name of the node to start resolving from
+ * \throws uhd::lookup_error if node_name not in container
+ * \throws uhd::runtime_error if graph cannot be resolved
+ *
+ */
+ virtual void resolve_from(const std::string& node_name) = 0;
+
+ /*!
+ * Resolves all the specified node and all of its dependencies.
+ *
+ * Dependency analysis is performed on the graph and nodes
+ * are resolved in a topologically sorted order to ensure
+ * that no nodes receive stale data.
+ * Nodes and their dependencies are resolved only if they are
+ * dirty i.e. their contained values have changed since the
+ * last resolve.
+ * This call requires an acyclic expert graph.
+ *
+ * \param node_name Name of the node to resolve
+ * \throws uhd::lookup_error if node_name not in container
+ * \throws uhd::runtime_error if graph cannot be resolved
+ *
+ */
+ virtual void resolve_to(const std::string& node_name) = 0;
+
+ /*!
+ * Return a node retriever object for this container
+ */
+ virtual const node_retriever_t& node_retriever() const = 0;
+
+ /*!
+ * Returns a DOT (graph description language) representation
+ * of the expert graph. The output has labels for the node
+ * name, node type (data or worker) and the underlying
+ * data type for each node.
+ *
+ */
+ virtual std::string to_dot() const = 0;
+
+ /*!
+ * Runs several sanity checks on the underlying graph to
+ * flag dependency issues. Outputs of the checks are
+ * logged to the console so UHD_EXPERTS_VERBOSE_LOGGING
+ * must be enabled to see the results
+ *
+ */
+ virtual void debug_audit() const = 0;
+
+private:
+ /*!
+ * Lookup a node with the specified name in the contained graph
+ *
+ * If the node is found, a reference to the node is returned.
+ * If the node is not found, uhd::lookup_error is thrown
+ * lookup can return a data or a worker node
+ * \implements uhd::experts::node_retriever_t
+ *
+ * \param name Name of the node to find
+ *
+ */
+ virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
+ virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
+
+ /*!
+ * expert_factory is a friend of expert_container and
+ * handles all operations that change the structure of
+ * the underlying dependency graph.
+ * The expert_container instance owns all data and worker
+ * nodes and is responsible for release storage on destruction.
+ * However, the expert_factory allocates storage for the
+ * node and passes them into the expert_container using the
+ * following "protected" API calls.
+ *
+ */
+ friend class expert_factory;
+
+ /*!
+ * Creates an empty instance of expert_container with the
+ * specified name.
+ *
+ * \param name Name of the container
+ */
+ static sptr make(const std::string& name);
+
+ /*!
+ * Returns a reference to the resolver mutex.
+ *
+ * The resolver mutex guarantees that external operations
+ * to data-nodes are serialized with resolves of this
+ * container.
+ *
+ */
+ virtual boost::recursive_mutex& resolve_mutex() = 0;
+
+ /*!
+ * Add a data node to the expert graph
+ *
+ * \param data_node Pointer to a fully constructed data node object
+ * \resolve_mode Auto resolve options: Choose from "disabled" and resolve on "read",
+ * "write" or "both" \throws uhd::runtime_error if node already exists or is of a
+ * wrong type (recoverable) \throws uhd::assertion_error for other failures
+ * (unrecoverable. will clear the graph)
+ *
+ */
+ virtual void add_data_node(
+ dag_vertex_t* data_node, auto_resolve_mode_t resolve_mode = AUTO_RESOLVE_OFF) = 0;
+
+ /*!
+ * Add a worker node to the expert graph
+ *
+ * \param worker Pointer to a fully constructed worker object
+ * \throws uhd::runtime_error if worker already exists or is of a wrong type
+ * (recoverable) \throws uhd::assertion_error for other failures (unrecoverable. will
+ * clear the graph)
+ *
+ */
+ virtual void add_worker(worker_node_t* worker) = 0;
+
+ /*!
+ * Release all storage for this object. This will delete all contained
+ * data and worker nodes and remove all dependency relationship and
+ * resolve callbacks.
+ *
+ * The object will be restored to its newly constructed state. Will not
+ * throw.
+ */
+ virtual void clear() = 0;
+};
+
+}} // namespace uhd::experts
#endif /* INCLUDED_UHD_EXPERTS_EXPERT_CONTAINER_HPP */
diff --git a/host/lib/include/uhdlib/experts/expert_factory.hpp b/host/lib/include/uhdlib/experts/expert_factory.hpp
index 9e07aa47f..47308d046 100644
--- a/host/lib/include/uhdlib/experts/expert_factory.hpp
+++ b/host/lib/include/uhdlib/experts/expert_factory.hpp
@@ -18,311 +18,333 @@
namespace uhd { namespace experts {
+/*!
+ * expert_factory is a friend of expert_container and
+ * handles all operations to create and change the structure of
+ * the an expert container.
+ * The expert_factory allocates storage for the nodes in the
+ * expert_container and passes allocated objects to the container
+ * using private APIs. The expert_container instance owns all
+ * data and workernodes and is responsible for releasing their
+ * storage on destruction.
+ *
+ */
+class UHD_API expert_factory : public uhd::noncopyable
+{
+public:
/*!
- * expert_factory is a friend of expert_container and
- * handles all operations to create and change the structure of
- * the an expert container.
- * The expert_factory allocates storage for the nodes in the
- * expert_container and passes allocated objects to the container
- * using private APIs. The expert_container instance owns all
- * data and workernodes and is responsible for releasing their
- * storage on destruction.
+ * Creates an empty instance of expert_container with the
+ * specified name.
*
+ * \param name Name of the container
*/
- class UHD_API expert_factory : public uhd::noncopyable {
- public:
+ static expert_container::sptr create_container(const std::string& name);
- /*!
- * Creates an empty instance of expert_container with the
- * specified name.
- *
- * \param name Name of the container
- */
- static expert_container::sptr create_container(
- const std::string& name
- );
-
- /*!
- * Add a data node to the expert graph.
- *
- * \param container A shared pointer to the container to add the node to
- * \param name The name of the data node
- * \param init_val The initial value of the data node
- * \param mode The auto resolve mode
- *
- * Requirements for data_t
- * - Must have a default constructor
- * - Must have a copy constructor
- * - Must have an assignment operator (=)
- * - Must have an equality operator (==)
- */
- template<typename data_t>
- inline static void add_data_node(
- expert_container::sptr container,
- const std::string& name,
- const data_t& init_val,
- const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF
- ) {
- container->add_data_node(new data_node_t<data_t>(name, init_val), mode);
- }
+ /*!
+ * Add a data node to the expert graph.
+ *
+ * \param container A shared pointer to the container to add the node to
+ * \param name The name of the data node
+ * \param init_val The initial value of the data node
+ * \param mode The auto resolve mode
+ *
+ * Requirements for data_t
+ * - Must have a default constructor
+ * - Must have a copy constructor
+ * - Must have an assignment operator (=)
+ * - Must have an equality operator (==)
+ */
+ template <typename data_t>
+ inline static void add_data_node(expert_container::sptr container,
+ const std::string& name,
+ const data_t& init_val,
+ const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF)
+ {
+ container->add_data_node(new data_node_t<data_t>(name, init_val), mode);
+ }
- /*!
- * Add a expert property to a property tree AND an expert graph
- *
- * \param container A shared pointer to the expert container to add the node to
- * \param subtree A shared pointer to subtree to add the property to
- * \param path The path of the property in the subtree
- * \param name The name of the data node in the expert graph
- * \param init_val The initial value of the data node
- * \param mode The auto resolve mode
- *
- * Requirements for data_t
- * - Must have a default constructor
- * - Must have a copy constructor
- * - Must have an assignment operator (=)
- * - Must have an equality operator (==)
- */
- template<typename data_t>
- inline static property<data_t>& add_prop_node(
- expert_container::sptr container,
- property_tree::sptr subtree,
- const fs_path &path,
- const std::string& name,
- const data_t& init_val,
- const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF
- ) {
- property<data_t>& prop = subtree->create<data_t>(path, property_tree::MANUAL_COERCE);
- data_node_t<data_t>* node_ptr =
- new data_node_t<data_t>(name, init_val, &container->resolve_mutex());
- prop.set(init_val);
- prop.add_desired_subscriber(std::bind(&data_node_t<data_t>::commit, node_ptr, std::placeholders::_1));
- prop.set_publisher(std::bind(&data_node_t<data_t>::retrieve, node_ptr));
- container->add_data_node(node_ptr, mode);
- return prop;
- }
+ /*!
+ * Add a expert property to a property tree AND an expert graph
+ *
+ * \param container A shared pointer to the expert container to add the node to
+ * \param subtree A shared pointer to subtree to add the property to
+ * \param path The path of the property in the subtree
+ * \param name The name of the data node in the expert graph
+ * \param init_val The initial value of the data node
+ * \param mode The auto resolve mode
+ *
+ * Requirements for data_t
+ * - Must have a default constructor
+ * - Must have a copy constructor
+ * - Must have an assignment operator (=)
+ * - Must have an equality operator (==)
+ */
+ template <typename data_t>
+ inline static property<data_t>& add_prop_node(expert_container::sptr container,
+ property_tree::sptr subtree,
+ const fs_path& path,
+ const std::string& name,
+ const data_t& init_val,
+ const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF)
+ {
+ property<data_t>& prop =
+ subtree->create<data_t>(path, property_tree::MANUAL_COERCE);
+ data_node_t<data_t>* node_ptr =
+ new data_node_t<data_t>(name, init_val, &container->resolve_mutex());
+ prop.set(init_val);
+ prop.add_desired_subscriber(
+ std::bind(&data_node_t<data_t>::commit, node_ptr, std::placeholders::_1));
+ prop.set_publisher(std::bind(&data_node_t<data_t>::retrieve, node_ptr));
+ container->add_data_node(node_ptr, mode);
+ return prop;
+ }
- /*!
- * Add a expert property to a property tree AND an expert graph.
- * The property is registered with the path as the identifier for
- * both the property subtree and the expert container
- *
- * \param container A shared pointer to the expert container to add the node to
- * \param subtree A shared pointer to subtree to add the property to
- * \param path The path of the property in the subtree
- * \param init_val The initial value of the data node
- * \param mode The auto resolve mode
- *
- */
- template<typename data_t>
- inline static property<data_t>& add_prop_node(
- expert_container::sptr container,
- property_tree::sptr subtree,
- const fs_path &path,
- const data_t& init_val,
- const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF
- ) {
- return add_prop_node(container, subtree, path, path, init_val, mode);
- }
+ /*!
+ * Add a expert property to a property tree AND an expert graph.
+ * The property is registered with the path as the identifier for
+ * both the property subtree and the expert container
+ *
+ * \param container A shared pointer to the expert container to add the node to
+ * \param subtree A shared pointer to subtree to add the property to
+ * \param path The path of the property in the subtree
+ * \param init_val The initial value of the data node
+ * \param mode The auto resolve mode
+ *
+ */
+ template <typename data_t>
+ inline static property<data_t>& add_prop_node(expert_container::sptr container,
+ property_tree::sptr subtree,
+ const fs_path& path,
+ const data_t& init_val,
+ const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF)
+ {
+ return add_prop_node(container, subtree, path, path, init_val, mode);
+ }
- /*!
- * Add a dual expert property to a property tree AND an expert graph.
- * A dual property is a desired and coerced value pair
- *
- * \param container A shared pointer to the expert container to add the node to
- * \param subtree A shared pointer to subtree to add the property to
- * \param path The path of the property in the subtree
- * \param desired_name The name of the desired data node in the expert graph
- * \param desired_name The name of the coerced data node in the expert graph
- * \param init_val The initial value of both the data nodes
- * \param mode The auto resolve mode
- *
- * Requirements for data_t
- * - Must have a default constructor
- * - Must have a copy constructor
- * - Must have an assignment operator (=)
- * - Must have an equality operator (==)
- */
- template<typename data_t>
- inline static property<data_t>& add_dual_prop_node(
- expert_container::sptr container,
- property_tree::sptr subtree,
- const fs_path &path,
- const std::string& desired_name,
- const std::string& coerced_name,
- const data_t& init_val,
- const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF
- ) {
- bool auto_resolve_desired = (mode==AUTO_RESOLVE_ON_WRITE or mode==AUTO_RESOLVE_ON_READ_WRITE);
- bool auto_resolve_coerced = (mode==AUTO_RESOLVE_ON_READ or mode==AUTO_RESOLVE_ON_READ_WRITE);
+ /*!
+ * Add a dual expert property to a property tree AND an expert graph.
+ * A dual property is a desired and coerced value pair
+ *
+ * \param container A shared pointer to the expert container to add the node to
+ * \param subtree A shared pointer to subtree to add the property to
+ * \param path The path of the property in the subtree
+ * \param desired_name The name of the desired data node in the expert graph
+ * \param desired_name The name of the coerced data node in the expert graph
+ * \param init_val The initial value of both the data nodes
+ * \param mode The auto resolve mode
+ *
+ * Requirements for data_t
+ * - Must have a default constructor
+ * - Must have a copy constructor
+ * - Must have an assignment operator (=)
+ * - Must have an equality operator (==)
+ */
+ template <typename data_t>
+ inline static property<data_t>& add_dual_prop_node(expert_container::sptr container,
+ property_tree::sptr subtree,
+ const fs_path& path,
+ const std::string& desired_name,
+ const std::string& coerced_name,
+ const data_t& init_val,
+ const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF)
+ {
+ bool auto_resolve_desired =
+ (mode == AUTO_RESOLVE_ON_WRITE or mode == AUTO_RESOLVE_ON_READ_WRITE);
+ bool auto_resolve_coerced =
+ (mode == AUTO_RESOLVE_ON_READ or mode == AUTO_RESOLVE_ON_READ_WRITE);
- property<data_t>& prop = subtree->create<data_t>(path, property_tree::MANUAL_COERCE);
- data_node_t<data_t>* desired_node_ptr =
- new data_node_t<data_t>(desired_name, init_val, &container->resolve_mutex());
- data_node_t<data_t>* coerced_node_ptr =
- new data_node_t<data_t>(coerced_name, init_val, &container->resolve_mutex());
- prop.set(init_val);
- prop.set_coerced(init_val);
- prop.add_desired_subscriber(std::bind(&data_node_t<data_t>::commit, desired_node_ptr, std::placeholders::_1));
- prop.set_publisher(std::bind(&data_node_t<data_t>::retrieve, coerced_node_ptr));
+ property<data_t>& prop =
+ subtree->create<data_t>(path, property_tree::MANUAL_COERCE);
+ data_node_t<data_t>* desired_node_ptr =
+ new data_node_t<data_t>(desired_name, init_val, &container->resolve_mutex());
+ data_node_t<data_t>* coerced_node_ptr =
+ new data_node_t<data_t>(coerced_name, init_val, &container->resolve_mutex());
+ prop.set(init_val);
+ prop.set_coerced(init_val);
+ prop.add_desired_subscriber(std::bind(
+ &data_node_t<data_t>::commit, desired_node_ptr, std::placeholders::_1));
+ prop.set_publisher(std::bind(&data_node_t<data_t>::retrieve, coerced_node_ptr));
- container->add_data_node(desired_node_ptr,
- auto_resolve_desired ? AUTO_RESOLVE_ON_WRITE : AUTO_RESOLVE_OFF);
- container->add_data_node(coerced_node_ptr,
- auto_resolve_coerced ? AUTO_RESOLVE_ON_READ : AUTO_RESOLVE_OFF);
- return prop;
- }
+ container->add_data_node(desired_node_ptr,
+ auto_resolve_desired ? AUTO_RESOLVE_ON_WRITE : AUTO_RESOLVE_OFF);
+ container->add_data_node(coerced_node_ptr,
+ auto_resolve_coerced ? AUTO_RESOLVE_ON_READ : AUTO_RESOLVE_OFF);
+ return prop;
+ }
- /*!
- * Add a dual expert property to a property tree AND an expert graph.
- * A dual property is a desired and coerced value pair
- * The property is registered with path/desired as the desired node
- * name and path/coerced as the coerced node name
- *
- * \param container A shared pointer to the expert container to add the node to
- * \param subtree A shared pointer to subtree to add the property to
- * \param path The path of the property in the subtree
- * \param init_val The initial value of both the data nodes
- * \param mode The auto resolve mode
- *
- */
- template<typename data_t>
- inline static property<data_t>& add_dual_prop_node(
- expert_container::sptr container,
- property_tree::sptr subtree,
- const fs_path &path,
- const data_t& init_val,
- const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF
- ) {
- return add_dual_prop_node(container, subtree, path, path + "/desired", path + "/coerced", init_val, mode);
- }
+ /*!
+ * Add a dual expert property to a property tree AND an expert graph.
+ * A dual property is a desired and coerced value pair
+ * The property is registered with path/desired as the desired node
+ * name and path/coerced as the coerced node name
+ *
+ * \param container A shared pointer to the expert container to add the node to
+ * \param subtree A shared pointer to subtree to add the property to
+ * \param path The path of the property in the subtree
+ * \param init_val The initial value of both the data nodes
+ * \param mode The auto resolve mode
+ *
+ */
+ template <typename data_t>
+ inline static property<data_t>& add_dual_prop_node(expert_container::sptr container,
+ property_tree::sptr subtree,
+ const fs_path& path,
+ const data_t& init_val,
+ const auto_resolve_mode_t mode = AUTO_RESOLVE_OFF)
+ {
+ return add_dual_prop_node(container,
+ subtree,
+ path,
+ path + "/desired",
+ path + "/coerced",
+ init_val,
+ mode);
+ }
- /*!
- * Add a worker node to the expert graph.
- * The expert_container owns and manages storage for the worker
- *
- * \tparam worker_t Data type of the worker class
- *
- * \param container A shared pointer to the container to add the node to
- *
- */
- template<typename worker_t>
- inline static void add_worker_node(
- expert_container::sptr container
- ) {
- container->add_worker(new worker_t());
- }
+ /*!
+ * Add a worker node to the expert graph.
+ * The expert_container owns and manages storage for the worker
+ *
+ * \tparam worker_t Data type of the worker class
+ *
+ * \param container A shared pointer to the container to add the node to
+ *
+ */
+ template <typename worker_t>
+ inline static void add_worker_node(expert_container::sptr container)
+ {
+ container->add_worker(new worker_t());
+ }
- /*!
- * Add a worker node to the expert graph.
- * The expert_container owns and manages storage for the worker
- *
- * \tparam worker_t Data type of the worker class
- * \tparam arg1_t Data type of the first argument to the constructor
- * \tparam ...
- * \tparam argN_t Data type of the Nth argument to the constructor
- *
- * \param container A shared pointer to the container to add the node to
- * \param arg1 First arg to ctor
- * \param ...
- * \param argN Nth arg to ctor
- *
- */
- template<typename worker_t, typename arg1_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1
- ) {
- container->add_worker(new worker_t(arg1));
- }
+ /*!
+ * Add a worker node to the expert graph.
+ * The expert_container owns and manages storage for the worker
+ *
+ * \tparam worker_t Data type of the worker class
+ * \tparam arg1_t Data type of the first argument to the constructor
+ * \tparam ...
+ * \tparam argN_t Data type of the Nth argument to the constructor
+ *
+ * \param container A shared pointer to the container to add the node to
+ * \param arg1 First arg to ctor
+ * \param ...
+ * \param argN Nth arg to ctor
+ *
+ */
+ template <typename worker_t, typename arg1_t>
+ inline static void add_worker_node(
+ expert_container::sptr container, arg1_t const& arg1)
+ {
+ container->add_worker(new worker_t(arg1));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2
- ) {
- container->add_worker(new worker_t(arg1, arg2));
- }
+ template <typename worker_t, typename arg1_t, typename arg2_t>
+ inline static void add_worker_node(
+ expert_container::sptr container, arg1_t const& arg1, arg2_t const& arg2)
+ {
+ container->add_worker(new worker_t(arg1, arg2));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2,
- arg3_t const & arg3
- ) {
- container->add_worker(new worker_t(arg1, arg2, arg3));
- }
+ template <typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t>
+ inline static void add_worker_node(expert_container::sptr container,
+ arg1_t const& arg1,
+ arg2_t const& arg2,
+ arg3_t const& arg3)
+ {
+ container->add_worker(new worker_t(arg1, arg2, arg3));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t, typename arg4_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2,
- arg3_t const & arg3,
- arg4_t const & arg4
- ) {
- container->add_worker(new worker_t(arg1, arg2, arg3, arg4));
- }
+ template <typename worker_t,
+ typename arg1_t,
+ typename arg2_t,
+ typename arg3_t,
+ typename arg4_t>
+ inline static void add_worker_node(expert_container::sptr container,
+ arg1_t const& arg1,
+ arg2_t const& arg2,
+ arg3_t const& arg3,
+ arg4_t const& arg4)
+ {
+ container->add_worker(new worker_t(arg1, arg2, arg3, arg4));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t, typename arg4_t,
- typename arg5_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2,
- arg3_t const & arg3,
- arg4_t const & arg4,
- arg5_t const & arg5
- ) {
- container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5));
- }
+ template <typename worker_t,
+ typename arg1_t,
+ typename arg2_t,
+ typename arg3_t,
+ typename arg4_t,
+ typename arg5_t>
+ inline static void add_worker_node(expert_container::sptr container,
+ arg1_t const& arg1,
+ arg2_t const& arg2,
+ arg3_t const& arg3,
+ arg4_t const& arg4,
+ arg5_t const& arg5)
+ {
+ container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t, typename arg4_t,
- typename arg5_t, typename arg6_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2,
- arg3_t const & arg3,
- arg4_t const & arg4,
- arg5_t const & arg5,
- arg6_t const & arg6
- ) {
- container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5, arg6));
- }
+ template <typename worker_t,
+ typename arg1_t,
+ typename arg2_t,
+ typename arg3_t,
+ typename arg4_t,
+ typename arg5_t,
+ typename arg6_t>
+ inline static void add_worker_node(expert_container::sptr container,
+ arg1_t const& arg1,
+ arg2_t const& arg2,
+ arg3_t const& arg3,
+ arg4_t const& arg4,
+ arg5_t const& arg5,
+ arg6_t const& arg6)
+ {
+ container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5, arg6));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t, typename arg4_t,
- typename arg5_t, typename arg6_t, typename arg7_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2,
- arg3_t const & arg3,
- arg4_t const & arg4,
- arg5_t const & arg5,
- arg6_t const & arg6,
- arg7_t const & arg7
- ) {
- container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5, arg6, arg7));
- }
+ template <typename worker_t,
+ typename arg1_t,
+ typename arg2_t,
+ typename arg3_t,
+ typename arg4_t,
+ typename arg5_t,
+ typename arg6_t,
+ typename arg7_t>
+ inline static void add_worker_node(expert_container::sptr container,
+ arg1_t const& arg1,
+ arg2_t const& arg2,
+ arg3_t const& arg3,
+ arg4_t const& arg4,
+ arg5_t const& arg5,
+ arg6_t const& arg6,
+ arg7_t const& arg7)
+ {
+ container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5, arg6, arg7));
+ }
- template<typename worker_t, typename arg1_t, typename arg2_t, typename arg3_t, typename arg4_t,
- typename arg5_t, typename arg6_t, typename arg7_t, typename arg8_t>
- inline static void add_worker_node(
- expert_container::sptr container,
- arg1_t const & arg1,
- arg2_t const & arg2,
- arg3_t const & arg3,
- arg4_t const & arg4,
- arg5_t const & arg5,
- arg6_t const & arg6,
- arg7_t const & arg7,
- arg7_t const & arg8
- ) {
- container->add_worker(new worker_t(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
- }
- };
-}}
+ template <typename worker_t,
+ typename arg1_t,
+ typename arg2_t,
+ typename arg3_t,
+ typename arg4_t,
+ typename arg5_t,
+ typename arg6_t,
+ typename arg7_t,
+ typename arg8_t>
+ inline static void add_worker_node(expert_container::sptr container,
+ arg1_t const& arg1,
+ arg2_t const& arg2,
+ arg3_t const& arg3,
+ arg4_t const& arg4,
+ arg5_t const& arg5,
+ arg6_t const& arg6,
+ arg7_t const& arg7,
+ arg7_t const& arg8)
+ {
+ container->add_worker(
+ new worker_t(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8));
+ }
+};
+}} // namespace uhd::experts
#endif /* INCLUDED_UHD_EXPERTS_EXPERT_FACTORY_HPP */
diff --git a/host/lib/include/uhdlib/experts/expert_nodes.hpp b/host/lib/include/uhdlib/experts/expert_nodes.hpp
index 665c0e579..b9a0f57bd 100644
--- a/host/lib/include/uhdlib/experts/expert_nodes.hpp
+++ b/host/lib/include/uhdlib/experts/expert_nodes.hpp
@@ -10,464 +10,544 @@
#include <uhd/config.hpp>
#include <uhd/exception.hpp>
+#include <uhd/types/time_spec.hpp>
#include <uhd/utils/dirty_tracked.hpp>
#include <uhd/utils/noncopyable.hpp>
-#include <uhd/types/time_spec.hpp>
-#include <functional>
-#include <boost/thread/recursive_mutex.hpp>
-#include <boost/thread.hpp>
+#include <stdint.h>
#include <boost/core/demangle.hpp>
-#include <memory>
+#include <boost/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
+#include <functional>
#include <list>
-#include <stdint.h>
+#include <memory>
namespace uhd { namespace experts {
- enum node_class_t { CLASS_WORKER, CLASS_DATA, CLASS_PROPERTY };
- enum node_access_t { ACCESS_READER, ACCESS_WRITER };
- enum node_author_t { AUTHOR_NONE, AUTHOR_USER, AUTHOR_EXPERT };
-
- /*!---------------------------------------------------------
- * class dag_vertex_t
- *
- * This serves as the base class for all nodes in the expert
- * graph. Data nodes and workers are derived from this class.
- * ---------------------------------------------------------
- */
- class dag_vertex_t : private uhd::noncopyable {
- public:
- typedef std::function<void(std::string)> callback_func_t;
-
- virtual ~dag_vertex_t() {}
-
- // Getters for basic info about the node
- inline node_class_t get_class() const {
- return _class;
- }
-
- inline const std::string& get_name() const {
- return _name;
- }
-
- virtual const std::string& get_dtype() const = 0;
-
- virtual std::string to_string() const = 0;
-
- // Graph resolution specific
- virtual bool is_dirty() const = 0;
- virtual void mark_clean() = 0;
- virtual void resolve() = 0;
-
- // External callbacks
- virtual void set_write_callback(const callback_func_t& func) = 0;
- virtual bool has_write_callback() const = 0;
- virtual void clear_write_callback() = 0;
- virtual void set_read_callback(const callback_func_t& func) = 0;
- virtual bool has_read_callback() const = 0;
- virtual void clear_read_callback() = 0;
-
- protected:
- dag_vertex_t(const node_class_t c, const std::string& n):
- _class(c), _name(n) {}
-
- private:
- const node_class_t _class;
- const std::string _name;
- };
-
- class data_node_printer {
- public:
- //Generic implementation
- template<typename data_t>
- static std::string print(const data_t& val) {
- std::ostringstream os;
- os << val;
- return os.str();
- }
-
- static std::string print(const uint8_t& val) {
- std::ostringstream os;
- os << int(val);
- return os.str();
- }
-
- static std::string print(const time_spec_t time) {
- std::ostringstream os;
- os << time.get_real_secs();
- return os.str();
- }
- };
-
- /*!---------------------------------------------------------
- * class data_node_t
- *
- * The data node class hold a passive piece of data in the
- * expert graph. A data node is clean if its underlying data
- * is clean. Access to the underlying data is provided using
- * two methods:
- * 1. Special accessor classes (for R/W enforcement)
- * 2. External clients (via commit and retrieve). This access
- * is protected by the callback mutex.
- *
- * Requirements for data_t
- * - Must have a default constructor
- * - Must have a copy constructor
- * - Must have an assignment operator (=)
- * - Must have an equality operator (==)
- * ---------------------------------------------------------
- */
- template<typename data_t>
- class data_node_t : public dag_vertex_t {
- public:
- // A data_node_t instance can have a type of CLASS_DATA or CLASS_PROPERTY
- // In general a data node is a property if it can be accessed and modified
- // from the outside world (of experts) using read and write callbacks. We
- // assume that if a callback mutex is passed into the data node that it will
- // be accessed from the outside and tag the data node as a PROPERTY.
- data_node_t(const std::string& name, boost::recursive_mutex* mutex = NULL) :
- dag_vertex_t(mutex?CLASS_PROPERTY:CLASS_DATA, name), _callback_mutex(mutex), _data(), _author(AUTHOR_NONE) {}
-
- data_node_t(const std::string& name, const data_t& value, boost::recursive_mutex* mutex = NULL) :
- dag_vertex_t(mutex?CLASS_PROPERTY:CLASS_DATA, name), _callback_mutex(mutex), _data(value), _author(AUTHOR_NONE) {}
-
- // Basic info
- virtual const std::string& get_dtype() const {
- static const std::string dtype(
- boost::core::demangle(typeid(data_t).name()));
- return dtype;
- }
-
- virtual std::string to_string() const {
- return data_node_printer::print(get());
- }
-
- inline node_author_t get_author() const {
- return _author;
- }
-
- // Graph resolution specific
- virtual bool is_dirty() const {
- return _data.is_dirty();
- }
-
- virtual void mark_clean() {
- _data.mark_clean();
- }
-
- void resolve() {
- //NOP
- }
-
- // Data node specific setters and getters (for the framework)
- void set(const data_t& value) {
- _data = value;
- _author = AUTHOR_EXPERT;
- }
-
- const data_t& get() const {
- return _data;
- }
-
- // Data node specific setters and getters (for external entities)
- void commit(const data_t& value) {
- if (_callback_mutex == NULL) throw uhd::assertion_error("node " + get_name() + " is missing the callback mutex");
- boost::lock_guard<boost::recursive_mutex> lock(*_callback_mutex);
- set(value);
- _author = AUTHOR_USER;
- if (is_dirty() and has_write_callback()) {
- _wr_callback(std::string(get_name())); //Put the name on the stack before calling
- }
- }
-
- const data_t retrieve() const {
- if (_callback_mutex == NULL) throw uhd::assertion_error("node " + get_name() + " is missing the callback mutex");
- boost::lock_guard<boost::recursive_mutex> lock(*_callback_mutex);
- if (has_read_callback()) {
- _rd_callback(std::string(get_name()));
- }
- return get();
- }
-
- private:
- // External callbacks
- virtual void set_write_callback(const callback_func_t& func) {
- _wr_callback = func;
- }
-
- virtual bool has_write_callback() const {
- return bool(_wr_callback);
- }
-
- virtual void clear_write_callback() {
- _wr_callback = nullptr;
- }
-
- virtual void set_read_callback(const callback_func_t& func) {
- _rd_callback = func;
- }
-
- virtual bool has_read_callback() const {
- return bool(_rd_callback);
- }
-
- virtual void clear_read_callback() {
- _rd_callback = nullptr;
- }
-
- boost::recursive_mutex* _callback_mutex;
- callback_func_t _rd_callback;
- callback_func_t _wr_callback;
- dirty_tracked<data_t> _data;
- node_author_t _author;
- };
-
- /*!---------------------------------------------------------
- * class node_retriever_t
- *
- * Node storage is managed by a framework class so we need
- * and interface to find and retrieve data nodes to associate
- * with accessors.
- * ---------------------------------------------------------
- */
- class node_retriever_t {
- public:
- virtual ~node_retriever_t() {}
- virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
- private:
- friend class data_accessor_t;
- virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
- };
-
- /*!---------------------------------------------------------
- * class data_accessor_t
- *
- * Accessors provide protected access to data nodes and help
- * establish dependency relationships.
- * ---------------------------------------------------------
- */
- class data_accessor_t {
- public:
- virtual ~data_accessor_t() {}
-
- virtual bool is_reader() const = 0;
- virtual bool is_writer() const = 0;
- virtual dag_vertex_t& node() const = 0;
- protected:
- data_accessor_t(const node_retriever_t& r, const std::string& n):
- _vertex(r.retrieve(n)) {}
- dag_vertex_t& _vertex;
- };
-
- template<typename data_t>
- class data_accessor_base : public data_accessor_t {
- public:
- virtual ~data_accessor_base() {}
-
- virtual bool is_reader() const {
- return _access == ACCESS_READER;
- }
-
- virtual bool is_writer() const {
- return _access == ACCESS_WRITER;
- }
-
- inline bool is_dirty() const {
- return _datanode->is_dirty();
- }
-
- inline node_class_t get_class() const {
- return _datanode->get_class();
- }
-
- inline node_author_t get_author() const {
- return _datanode->get_author();
- }
-
- protected:
- data_accessor_base(
- const node_retriever_t& r, const std::string& n, const node_access_t a) :
- data_accessor_t(r, n), _datanode(NULL), _access(a)
- {
- _datanode = dynamic_cast< data_node_t<data_t>* >(&node());
- if (_datanode == NULL) {
- throw uhd::type_error("Expected data type for node " + n +
- " was " + boost::core::demangle(typeid(data_t).name()) +
- " but got " + node().get_dtype());
- }
- }
-
- data_node_t<data_t>* _datanode;
- const node_access_t _access;
-
- private:
- virtual dag_vertex_t& node() const {
- return _vertex;
- }
- };
-
- /*!---------------------------------------------------------
- * class data_reader_t
- *
- * Accessor to read the value of a data node and to establish
- * a data node => worker node dependency
- * ---------------------------------------------------------
- */
- template<typename data_t>
- class data_reader_t : public data_accessor_base<data_t> {
- public:
- data_reader_t(const node_retriever_t& retriever, const std::string& node) :
- data_accessor_base<data_t>(
- retriever, node, ACCESS_READER) {}
-
- inline const data_t& get() const {
- return data_accessor_base<data_t>::_datanode->get();
- }
-
- inline operator const data_t&() const {
- return get();
- }
-
- inline bool operator==(const data_t& rhs) {
- return get() == rhs;
- }
-
- inline bool operator!=(const data_t& rhs) {
- return !(get() == rhs);
- }
- };
-
- /*!---------------------------------------------------------
- * class data_reader_t
- *
- * Accessor to read and write the value of a data node and
- * to establish a worker node => data node dependency
- * ---------------------------------------------------------
- */
- template<typename data_t>
- class data_writer_t : public data_accessor_base<data_t> {
- public:
- data_writer_t(const node_retriever_t& retriever, const std::string& node) :
- data_accessor_base<data_t>(
- retriever, node, ACCESS_WRITER) {}
-
- inline const data_t& get() const {
- return data_accessor_base<data_t>::_datanode->get();
- }
-
- inline operator const data_t&() const {
- return get();
- }
-
- inline bool operator==(const data_t& rhs) {
- return get() == rhs;
- }
-
- inline bool operator!=(const data_t& rhs) {
- return !(get() == rhs);
- }
-
- inline void set(const data_t& value) {
- data_accessor_base<data_t>::_datanode->set(value);
- }
-
- inline data_writer_t<data_t>& operator=(const data_t& value) {
- set(value);
- return *this;
- }
-
- inline data_writer_t<data_t>& operator=(const data_writer_t<data_t>& value) {
- set(value.get());
- return *this;
- }
+enum node_class_t { CLASS_WORKER, CLASS_DATA, CLASS_PROPERTY };
+enum node_access_t { ACCESS_READER, ACCESS_WRITER };
+enum node_author_t { AUTHOR_NONE, AUTHOR_USER, AUTHOR_EXPERT };
+
+/*!---------------------------------------------------------
+ * class dag_vertex_t
+ *
+ * This serves as the base class for all nodes in the expert
+ * graph. Data nodes and workers are derived from this class.
+ * ---------------------------------------------------------
+ */
+class dag_vertex_t : private uhd::noncopyable
+{
+public:
+ typedef std::function<void(std::string)> callback_func_t;
+
+ virtual ~dag_vertex_t() {}
+
+ // Getters for basic info about the node
+ inline node_class_t get_class() const
+ {
+ return _class;
+ }
+
+ inline const std::string& get_name() const
+ {
+ return _name;
+ }
+
+ virtual const std::string& get_dtype() const = 0;
+
+ virtual std::string to_string() const = 0;
+
+ // Graph resolution specific
+ virtual bool is_dirty() const = 0;
+ virtual void mark_clean() = 0;
+ virtual void resolve() = 0;
+
+ // External callbacks
+ virtual void set_write_callback(const callback_func_t& func) = 0;
+ virtual bool has_write_callback() const = 0;
+ virtual void clear_write_callback() = 0;
+ virtual void set_read_callback(const callback_func_t& func) = 0;
+ virtual bool has_read_callback() const = 0;
+ virtual void clear_read_callback() = 0;
+
+protected:
+ dag_vertex_t(const node_class_t c, const std::string& n) : _class(c), _name(n) {}
+
+private:
+ const node_class_t _class;
+ const std::string _name;
};
- /*!---------------------------------------------------------
- * class worker_node_t
- *
- * A node class to implement a function that consumes
- * zero or more input data nodes and emits zero or more output
- * data nodes. The worker can also operate on other non-expert
- * interfaces because worker_node_t is abstract and the client
- * is required to implement the "resolve" method in a subclass.
- * ---------------------------------------------------------
- */
- class worker_node_t : public dag_vertex_t {
- public:
- worker_node_t(const std::string& name) :
- dag_vertex_t(CLASS_WORKER, name) {}
-
- // Worker node specific
- std::list<std::string> get_inputs() const {
- std::list<std::string> retval;
- for(data_accessor_t* acc: _inputs) {
- retval.push_back(acc->node().get_name());
- }
- return retval;
- }
-
- std::list<std::string> get_outputs() const {
- std::list<std::string> retval;
- for(data_accessor_t* acc: _outputs) {
- retval.push_back(acc->node().get_name());
- }
- return retval;
- }
-
- protected:
- // This function is used to bind data accessors
- // to this worker. Accessors can be read/write
- // and the binding will ensure proper dependency
- // handling.
- void bind_accessor(data_accessor_t& accessor) {
- if (accessor.is_reader()) {
- _inputs.push_back(&accessor);
- } else if (accessor.is_writer()) {
- _outputs.push_back(&accessor);
- } else {
- throw uhd::assertion_error("Invalid accessor type");
- }
- }
+class data_node_printer
+{
+public:
+ // Generic implementation
+ template <typename data_t>
+ static std::string print(const data_t& val)
+ {
+ std::ostringstream os;
+ os << val;
+ return os.str();
+ }
+
+ static std::string print(const uint8_t& val)
+ {
+ std::ostringstream os;
+ os << int(val);
+ return os.str();
+ }
+
+ static std::string print(const time_spec_t time)
+ {
+ std::ostringstream os;
+ os << time.get_real_secs();
+ return os.str();
+ }
+};
- private:
- // Graph resolution specific
- virtual bool is_dirty() const {
- bool inputs_dirty = false;
- for(data_accessor_t* acc: _inputs) {
- inputs_dirty |= acc->node().is_dirty();
- }
- return inputs_dirty;
- }
+/*!---------------------------------------------------------
+ * class data_node_t
+ *
+ * The data node class hold a passive piece of data in the
+ * expert graph. A data node is clean if its underlying data
+ * is clean. Access to the underlying data is provided using
+ * two methods:
+ * 1. Special accessor classes (for R/W enforcement)
+ * 2. External clients (via commit and retrieve). This access
+ * is protected by the callback mutex.
+ *
+ * Requirements for data_t
+ * - Must have a default constructor
+ * - Must have a copy constructor
+ * - Must have an assignment operator (=)
+ * - Must have an equality operator (==)
+ * ---------------------------------------------------------
+ */
+template <typename data_t>
+class data_node_t : public dag_vertex_t
+{
+public:
+ // A data_node_t instance can have a type of CLASS_DATA or CLASS_PROPERTY
+ // In general a data node is a property if it can be accessed and modified
+ // from the outside world (of experts) using read and write callbacks. We
+ // assume that if a callback mutex is passed into the data node that it will
+ // be accessed from the outside and tag the data node as a PROPERTY.
+ data_node_t(const std::string& name, boost::recursive_mutex* mutex = NULL)
+ : dag_vertex_t(mutex ? CLASS_PROPERTY : CLASS_DATA, name)
+ , _callback_mutex(mutex)
+ , _data()
+ , _author(AUTHOR_NONE)
+ {
+ }
+
+ data_node_t(const std::string& name,
+ const data_t& value,
+ boost::recursive_mutex* mutex = NULL)
+ : dag_vertex_t(mutex ? CLASS_PROPERTY : CLASS_DATA, name)
+ , _callback_mutex(mutex)
+ , _data(value)
+ , _author(AUTHOR_NONE)
+ {
+ }
+
+ // Basic info
+ virtual const std::string& get_dtype() const
+ {
+ static const std::string dtype(boost::core::demangle(typeid(data_t).name()));
+ return dtype;
+ }
+
+ virtual std::string to_string() const
+ {
+ return data_node_printer::print(get());
+ }
+
+ inline node_author_t get_author() const
+ {
+ return _author;
+ }
+
+ // Graph resolution specific
+ virtual bool is_dirty() const
+ {
+ return _data.is_dirty();
+ }
+
+ virtual void mark_clean()
+ {
+ _data.mark_clean();
+ }
+
+ void resolve()
+ {
+ // NOP
+ }
+
+ // Data node specific setters and getters (for the framework)
+ void set(const data_t& value)
+ {
+ _data = value;
+ _author = AUTHOR_EXPERT;
+ }
+
+ const data_t& get() const
+ {
+ return _data;
+ }
+
+ // Data node specific setters and getters (for external entities)
+ void commit(const data_t& value)
+ {
+ if (_callback_mutex == NULL)
+ throw uhd::assertion_error(
+ "node " + get_name() + " is missing the callback mutex");
+ boost::lock_guard<boost::recursive_mutex> lock(*_callback_mutex);
+ set(value);
+ _author = AUTHOR_USER;
+ if (is_dirty() and has_write_callback()) {
+ _wr_callback(
+ std::string(get_name())); // Put the name on the stack before calling
+ }
+ }
+
+ const data_t retrieve() const
+ {
+ if (_callback_mutex == NULL)
+ throw uhd::assertion_error(
+ "node " + get_name() + " is missing the callback mutex");
+ boost::lock_guard<boost::recursive_mutex> lock(*_callback_mutex);
+ if (has_read_callback()) {
+ _rd_callback(std::string(get_name()));
+ }
+ return get();
+ }
+
+private:
+ // External callbacks
+ virtual void set_write_callback(const callback_func_t& func)
+ {
+ _wr_callback = func;
+ }
+
+ virtual bool has_write_callback() const
+ {
+ return bool(_wr_callback);
+ }
+
+ virtual void clear_write_callback()
+ {
+ _wr_callback = nullptr;
+ }
+
+ virtual void set_read_callback(const callback_func_t& func)
+ {
+ _rd_callback = func;
+ }
+
+ virtual bool has_read_callback() const
+ {
+ return bool(_rd_callback);
+ }
+
+ virtual void clear_read_callback()
+ {
+ _rd_callback = nullptr;
+ }
+
+ boost::recursive_mutex* _callback_mutex;
+ callback_func_t _rd_callback;
+ callback_func_t _wr_callback;
+ dirty_tracked<data_t> _data;
+ node_author_t _author;
+};
- virtual void mark_clean() {
- for(data_accessor_t* acc: _inputs) {
- acc->node().mark_clean();
- }
- }
+/*!---------------------------------------------------------
+ * class node_retriever_t
+ *
+ * Node storage is managed by a framework class so we need
+ * and interface to find and retrieve data nodes to associate
+ * with accessors.
+ * ---------------------------------------------------------
+ */
+class node_retriever_t
+{
+public:
+ virtual ~node_retriever_t() {}
+ virtual const dag_vertex_t& lookup(const std::string& name) const = 0;
+
+private:
+ friend class data_accessor_t;
+ virtual dag_vertex_t& retrieve(const std::string& name) const = 0;
+};
- virtual void resolve() = 0;
+/*!---------------------------------------------------------
+ * class data_accessor_t
+ *
+ * Accessors provide protected access to data nodes and help
+ * establish dependency relationships.
+ * ---------------------------------------------------------
+ */
+class data_accessor_t
+{
+public:
+ virtual ~data_accessor_t() {}
+
+ virtual bool is_reader() const = 0;
+ virtual bool is_writer() const = 0;
+ virtual dag_vertex_t& node() const = 0;
+
+protected:
+ data_accessor_t(const node_retriever_t& r, const std::string& n)
+ : _vertex(r.retrieve(n))
+ {
+ }
+ dag_vertex_t& _vertex;
+};
- // Basic type info
- virtual const std::string& get_dtype() const {
- static const std::string dtype = "<worker>";
- return dtype;
- }
+template <typename data_t>
+class data_accessor_base : public data_accessor_t
+{
+public:
+ virtual ~data_accessor_base() {}
+
+ virtual bool is_reader() const
+ {
+ return _access == ACCESS_READER;
+ }
+
+ virtual bool is_writer() const
+ {
+ return _access == ACCESS_WRITER;
+ }
+
+ inline bool is_dirty() const
+ {
+ return _datanode->is_dirty();
+ }
+
+ inline node_class_t get_class() const
+ {
+ return _datanode->get_class();
+ }
+
+ inline node_author_t get_author() const
+ {
+ return _datanode->get_author();
+ }
+
+protected:
+ data_accessor_base(
+ const node_retriever_t& r, const std::string& n, const node_access_t a)
+ : data_accessor_t(r, n), _datanode(NULL), _access(a)
+ {
+ _datanode = dynamic_cast<data_node_t<data_t>*>(&node());
+ if (_datanode == NULL) {
+ throw uhd::type_error("Expected data type for node " + n + " was "
+ + boost::core::demangle(typeid(data_t).name())
+ + " but got " + node().get_dtype());
+ }
+ }
+
+ data_node_t<data_t>* _datanode;
+ const node_access_t _access;
+
+private:
+ virtual dag_vertex_t& node() const
+ {
+ return _vertex;
+ }
+};
- virtual std::string to_string() const {
- return "<worker>";
- }
+/*!---------------------------------------------------------
+ * class data_reader_t
+ *
+ * Accessor to read the value of a data node and to establish
+ * a data node => worker node dependency
+ * ---------------------------------------------------------
+ */
+template <typename data_t>
+class data_reader_t : public data_accessor_base<data_t>
+{
+public:
+ data_reader_t(const node_retriever_t& retriever, const std::string& node)
+ : data_accessor_base<data_t>(retriever, node, ACCESS_READER)
+ {
+ }
+
+ inline const data_t& get() const
+ {
+ return data_accessor_base<data_t>::_datanode->get();
+ }
+
+ inline operator const data_t&() const
+ {
+ return get();
+ }
+
+ inline bool operator==(const data_t& rhs)
+ {
+ return get() == rhs;
+ }
+
+ inline bool operator!=(const data_t& rhs)
+ {
+ return !(get() == rhs);
+ }
+};
- // Workers don't have callbacks so implement stubs
- virtual void set_write_callback(const callback_func_t&) {}
- virtual bool has_write_callback() const { return false; }
- virtual void clear_write_callback() {}
- virtual void set_read_callback(const callback_func_t&) {}
- virtual bool has_read_callback() const { return false; }
- virtual void clear_read_callback() {}
+/*!---------------------------------------------------------
+ * class data_reader_t
+ *
+ * Accessor to read and write the value of a data node and
+ * to establish a worker node => data node dependency
+ * ---------------------------------------------------------
+ */
+template <typename data_t>
+class data_writer_t : public data_accessor_base<data_t>
+{
+public:
+ data_writer_t(const node_retriever_t& retriever, const std::string& node)
+ : data_accessor_base<data_t>(retriever, node, ACCESS_WRITER)
+ {
+ }
+
+ inline const data_t& get() const
+ {
+ return data_accessor_base<data_t>::_datanode->get();
+ }
+
+ inline operator const data_t&() const
+ {
+ return get();
+ }
+
+ inline bool operator==(const data_t& rhs)
+ {
+ return get() == rhs;
+ }
+
+ inline bool operator!=(const data_t& rhs)
+ {
+ return !(get() == rhs);
+ }
+
+ inline void set(const data_t& value)
+ {
+ data_accessor_base<data_t>::_datanode->set(value);
+ }
+
+ inline data_writer_t<data_t>& operator=(const data_t& value)
+ {
+ set(value);
+ return *this;
+ }
+
+ inline data_writer_t<data_t>& operator=(const data_writer_t<data_t>& value)
+ {
+ set(value.get());
+ return *this;
+ }
+};
- std::list<data_accessor_t*> _inputs;
- std::list<data_accessor_t*> _outputs;
- };
+/*!---------------------------------------------------------
+ * class worker_node_t
+ *
+ * A node class to implement a function that consumes
+ * zero or more input data nodes and emits zero or more output
+ * data nodes. The worker can also operate on other non-expert
+ * interfaces because worker_node_t is abstract and the client
+ * is required to implement the "resolve" method in a subclass.
+ * ---------------------------------------------------------
+ */
+class worker_node_t : public dag_vertex_t
+{
+public:
+ worker_node_t(const std::string& name) : dag_vertex_t(CLASS_WORKER, name) {}
+
+ // Worker node specific
+ std::list<std::string> get_inputs() const
+ {
+ std::list<std::string> retval;
+ for (data_accessor_t* acc : _inputs) {
+ retval.push_back(acc->node().get_name());
+ }
+ return retval;
+ }
+
+ std::list<std::string> get_outputs() const
+ {
+ std::list<std::string> retval;
+ for (data_accessor_t* acc : _outputs) {
+ retval.push_back(acc->node().get_name());
+ }
+ return retval;
+ }
+
+protected:
+ // This function is used to bind data accessors
+ // to this worker. Accessors can be read/write
+ // and the binding will ensure proper dependency
+ // handling.
+ void bind_accessor(data_accessor_t& accessor)
+ {
+ if (accessor.is_reader()) {
+ _inputs.push_back(&accessor);
+ } else if (accessor.is_writer()) {
+ _outputs.push_back(&accessor);
+ } else {
+ throw uhd::assertion_error("Invalid accessor type");
+ }
+ }
+
+private:
+ // Graph resolution specific
+ virtual bool is_dirty() const
+ {
+ bool inputs_dirty = false;
+ for (data_accessor_t* acc : _inputs) {
+ inputs_dirty |= acc->node().is_dirty();
+ }
+ return inputs_dirty;
+ }
+
+ virtual void mark_clean()
+ {
+ for (data_accessor_t* acc : _inputs) {
+ acc->node().mark_clean();
+ }
+ }
+
+ virtual void resolve() = 0;
+
+ // Basic type info
+ virtual const std::string& get_dtype() const
+ {
+ static const std::string dtype = "<worker>";
+ return dtype;
+ }
+
+ virtual std::string to_string() const
+ {
+ return "<worker>";
+ }
+
+ // Workers don't have callbacks so implement stubs
+ virtual void set_write_callback(const callback_func_t&) {}
+ virtual bool has_write_callback() const
+ {
+ return false;
+ }
+ virtual void clear_write_callback() {}
+ virtual void set_read_callback(const callback_func_t&) {}
+ virtual bool has_read_callback() const
+ {
+ return false;
+ }
+ virtual void clear_read_callback() {}
+
+ std::list<data_accessor_t*> _inputs;
+ std::list<data_accessor_t*> _outputs;
+};
-}}
+}} // namespace uhd::experts
#endif /* INCLUDED_UHD_EXPERTS_EXPERT_NODE_HPP */