//
// Copyright 2016 Ettus Research
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
//
#ifndef INCLUDED_UHD_EXPERTS_EXPERT_FACTORY_HPP
#define INCLUDED_UHD_EXPERTS_EXPERT_FACTORY_HPP
#include "expert_container.hpp"
#include
#include
#include
#include
#include
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 boost::noncopyable {
public:
/*!
* 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
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(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
inline static property& 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& prop = subtree->create(path, property_tree::MANUAL_COERCE);
data_node_t* node_ptr =
new data_node_t(name, init_val, &container->resolve_mutex());
prop.set(init_val);
prop.add_desired_subscriber(boost::bind(&data_node_t::commit, node_ptr, _1));
prop.set_publisher(boost::bind(&data_node_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
inline static property& 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
inline static property& 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& prop = subtree->create(path, property_tree::MANUAL_COERCE);
data_node_t* desired_node_ptr =
new data_node_t(desired_name, init_val, &container->resolve_mutex());
data_node_t* coerced_node_ptr =
new data_node_t(coerced_name, init_val, &container->resolve_mutex());
prop.set(init_val);
prop.set_coerced(init_val);
prop.add_desired_subscriber(boost::bind(&data_node_t::commit, desired_node_ptr, _1));
prop.set_publisher(boost::bind(&data_node_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;
}
/*!
* 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
inline static property& 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
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
inline static void add_worker_node(
expert_container::sptr container,
arg1_t const & arg1
) {
container->add_worker(new worker_t(arg1));
}
template
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
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
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
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
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
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
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));
}
};
}}
#endif /* INCLUDED_UHD_EXPERTS_EXPERT_FACTORY_HPP */