Page MenuHomePhorge

DeluxeContext.hpp
No OneTemporary

Size
38 KB
Referenced Files
None
Subscribers
None

DeluxeContext.hpp

//===-- rosa/deluxe/DeluxeContext.hpp ---------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeContext.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Public interface for the *deluxe interface* for working with agent
/// systems.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXECONTEXT_HPP
#define ROSA_DELUXE_DELUXECONTEXT_HPP
#include "rosa/deluxe/DeluxeSystem.hpp"
#include "rosa/support/types.hpp"
#include <iterator>
#include <memory>
#include <set>
/// Local helper macro to log and return a
/// \c rosa::deluxe::DeluxeContext::ErrorCode value.
///
/// Creates a debug message with the stringified value and returns the value.
///
/// \param Err \c rosa::deluxe::DeluxeContext::ErrorCode value to log and
/// return
#define DCRETERROR(Err) \
{ \
LOG_DEBUG(#Err); \
return Err; \
}
namespace rosa {
namespace deluxe {
/// Defines the *deluxe interface*.
///
/// \todo The classes \c rosa::deluxe::DeluxeSensor and \c
/// rosa::deluxe::DeluxeAgent share some common features in relation to their
/// *slave* role in the *deluxe interface*. But their definitions are completely
/// independent. It could be investigated how to lift their common parts into a
/// new *deluxe slave* class, which would serve as base for both, to avoid code
/// duplication.
class DeluxeContext {
/// A system owned by \p this object.
///
/// \note The reference is kept in a \c std::shared_ptr because of the member
/// function \c rosa::deluxe::DeluxeContext::getSystem.
std::shared_ptr<DeluxeSystem> System;
/// References to all *sensors* and *agents* created by \p this object.
std::set<AgentHandle> DeluxeUnits;
public:
/// Errors that may be resulted by some of the member functions of the class.
enum struct ErrorCode {
NoError,
TypeMismatch,
NotSensor,
NotAgent,
NotUnit,
WrongPosition,
AlreadyHasSlave,
AlreadyHasMaster,
AlreadyHasValueStream,
UnsuitableExecutionPolicy
};
/// Returns a new instance of \c rosa::deluxe::DeluxeContext.
///
/// \param Name name of the underlying \c rosa::DeluxeSystem
///
/// \return \c std::unique_ptr for the new instance of
/// \c rosa::deluxe::DeluxeContext with a new, empty \c rosa::DeluxeSystem
static std::unique_ptr<DeluxeContext>
create(const std::string &Name) noexcept;
private:
/// Creates a new instance.
///
/// \note Private constructor restricts instantiation to member functions of
/// the class.
///
/// \param Name name of the underlying \c rosa::MessagingSystem
DeluxeContext(const std::string &Name) noexcept;
public:
/// Destroys \p this object.
~DeluxeContext(void) noexcept;
/// Returns a reference for the underlying \c rosa::MessagingSystem.
///
/// \note One cannot do much with a \c rosa::MessagingSystem currently, this
/// is for future use.
///
/// \return reference for the underlying \c rosa::MessagingSystem.
std::weak_ptr<MessagingSystem> getSystem(void) const noexcept;
private:
/// Creates a new *sensor* in the context of \p this object.
///
/// The new *sensor* handles master-input by \p MF.
///
/// \tparam MT type of master-input the new *sensor* handles
/// \tparam T type of data the new *sensor* operates on
///
/// \note Instantiation fails if any of the type arguments \p MT and \p T
/// is not an instance of \c rosa::deluxe::DeluxeTuple or \p T is \c
/// rosa::deluxe::EmptyDeluxeTuple.
///
/// \param Name name of the new *sensor*
/// \param MF function for the new *sensors* to process master-input
/// values with
/// \param F function for the new *sensor* to generate the next value with
/// during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to
/// register an alternative simulation data source with \c
/// rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \see \c rosa::deluxe::DeluxeSensor::DeluxeSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename MT, typename T,
typename =
std::enable_if<TypeListAllDeluxeTuple<TypeList<MT, T>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value>>
AgentHandle createSensorImpl(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept;
public:
/// Creates a new *sensor* in the context of \p this object.
///
/// The new *sensor* does not receive master-input.
///
/// \tparam T type of data the new *sensor* operates on
///
/// \note Instantiation fails if type argument \p T is neither a built-in type
/// nor an instance of \c rosa::deluxe::DeluxeTuple with at least one element.
///
/// \param Name name of the new *sensor*
/// \param F function for the new *sensor* to generate the next value with
/// during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to register
/// an alternative simulation data source with
/// \c rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \see \c rosa::deluxe::DeluxeSensor::DeluxeSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename T, typename = std::enable_if_t<
TypeListContains<BuiltinTypes, T>::Value ||
(IsDeluxeTuple<T>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value)>>
AgentHandle createSensor(
const std::string &Name,
std::function<T(void)> &&F = [](void) { return T(); }) noexcept;
/// Creates a new *sensor* in the context of \p this object.
///
/// The new *sensor* handles master-input by \p MF.
///
/// \tparam MT type of master-input the new *sensor* handles
/// \tparam T type of data the new *sensor* operates on
///
/// \note The type arguments \p MT and \p T must be either all built-in types
/// or all instances of \c rosa::deluxe::DeluxeTuple. Moreover, \p T cannot be
/// \c rosa::deluxe::EmptyDeluxeTuple. Instantiation fails if these conditions
/// do not hold.
///
/// \param Name name of the new *sensor*
/// \param MF function for the new *sensors* to process master-input
/// values with \param F function for the new *sensor* to generate
/// the next value with during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to
/// register an alternative simulation data source with \c
/// rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \see \c rosa::deluxe::DeluxeSensor::DeluxeSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename MT, typename T,
typename = std::enable_if<
TypeListSubsetOf<TypeList<MT, T>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<MT, T>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value)>>
AgentHandle createSensor(
const std::string &Name, std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F = [](void) { return T(); }) noexcept;
private:
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* receives master-input by \p MF and produces
/// master-output.
///
/// \tparam MT type of master-input the new *agent* handles
/// \tparam T type of data the new *agent* outputs
/// \tparam Ts types of master-output the new *agent* produces
/// \tparam As types of inputs the new *agent* takes
///
/// \note Instantiation fails if any of the type arguments \p MT, \p T, \p
/// Ts..., and \p As... is not an instance of \c rosa::deluxe::DeluxeTuple or
/// any of \p T and \p As... is \c rosa::deluxe::EmptyDeluxeTuple.
///
/// \param Name name of the new *agent*
/// \param MF function for the new *agent* to process master-input
/// values with \param F function for the new *agent* to process
/// input values and generate output with
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <typename MT, typename T, typename... Ts, typename... As,
typename = std::enable_if_t<
TypeListAllDeluxeTuple<TypeList<MT, T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value))>>
AgentHandle createAgentImpl(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept;
public:
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* neither receives master-input nor produces
/// master-output.
///
/// \tparam T type of data the new *agent* outputs
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p T and \p As... must be either all built-in
/// types or all instances of \c rosa::deluxe::DeluxeTuple. Moreover, none of
/// them can be \c rosa::deluxe::EmptyDeluxeTuple. Instantiation fails if
/// these conditions do not hold.
///
/// \param Name name of the new *agent*
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename T, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle
createAgent(const std::string &Name,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* receives master-input by \p MF but does not
/// produce master-output.
///
/// \tparam MT type of master-input the new *agent* handles
/// \tparam T type of data the new *agent* outputs
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p MT, \p T, and \p As... must be either all
/// built-in types or all instances of \c rosa::deluxe::DeluxeTuple. Moreover,
/// none of \p T and \p As... can be \c rosa::deluxe::EmptyDeluxeTuple.
/// Instantiation fails if these conditions do not hold.
///
/// \param Name name of the new *agent*
/// \param MF function for the new *agent* to process master-input
/// values with
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename MT, typename T, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<MT, T, As...>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<MT, T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle
createAgent(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* does not receive master-input but produces
/// master-output.
///
/// \tparam T type of data the new *agent* outputs
/// \tparam Ts types of master-output the new *agent* produces
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p T, \p Ts, and \p As... must be either all
/// built-in types or all instances of \c rosa::deluxe::DeluxeTuple. Moreover,
/// none of \p T and \p As... can be \c rosa::deluxe::EmptyDeluxeTuple.
/// Instantiation fails if these conditions do not hold.
///
/// \param Name name of the new *agent*
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \note \p F does not produce master-output for a given position if the
/// corresponding type is \c rosa::deluxe::EmptyDeluxeTuple. It is not
/// possible to disable master-output at any position by using built-in types.
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename T, typename... Ts, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<T, Ts..., As...>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle
createAgent(const std::string &Name,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* receives master-input by \p MF and produces
/// master-output.
///
/// \tparam MT type of master-input the new *agent* handles
/// \tparam T type of data the new *agent* outputs
/// \tparam Ts types of master-output the new *agent* produces
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p MT, \p T, \p Ts, and \p As... must be either
/// all built-in types or all instances of \c rosa::deluxe::DeluxeTuple.
/// Moreover, none of \p T and \p As... can be \c
/// rosa::deluxe::EmptyDeluxeTuple. Instantiation fails if these conditions
/// do not hold.
///
/// \param Name name of the new *agent*
/// \param MF function for the new *agent* to process master-input
/// values with
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \note \p F does not produce master-output for a given position if the
/// corresponding type is \c rosa::deluxe::EmptyDeluxeTuple. It is not
/// possible to disable master-output at any position by using built-in types.
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename MT, typename T, typename... Ts, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<MT, T, Ts..., As...>,
BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<MT, T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle createAgent(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept;
/// Returns the current execution policy of the referred \p Unit
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The referred \p Unit is either *sensor* or *agent*.
///
/// \note The returned reference is valid only as long as \c
/// rosa::deluxe::DeluxeContext::setExecutionPolicy() is not called with the
/// *unit* referred by \p Unit and the *unit* is not destroyed.
///
/// \param Unit the *unit* whose execution policy is to be obtained
///
/// \return the \c rosa::deluxe::DeluxeExecutionPolicy from \p Unit if \p Unit
/// is valid
Optional<const DeluxeExecutionPolicy &>
getExecutionPolicy(AgentHandle Unit) const noexcept;
/// Sets the current execution policy of the referred \p Unit to \p
/// ExecutionPolicy.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The referred \p Unit is either *sensor* or *agent*.
///
/// \param Unit the *unit* whose execution policy is to be set
/// \param ExecutionPolicy the new execution policy for \p Unit
///
/// \return how successful setting \p ExecutionPolicy for \p Unit was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotUnit` | Referred \p Unit is not valid
/// `UnsuitableExecutionPolicy` | \p ExecutionPolicy cannot handle \p Unit
ErrorCode setExecutionPolicy(
AgentHandle Unit,
std::unique_ptr<DeluxeExecutionPolicy> &&ExecutionPolicy) noexcept;
/// Connects a *sensor* to an *agent* in the context of \p this object.
///
/// \param Agent the *agent* to connect to
/// \param Pos the index of slot of \p Agent to connect \p Sensor to
/// \param Sensor the *sensor* to connect
/// \param Description optional textual description of the connection
///
/// \return how successfull connecting \p Sensor to \p Agent at slot
/// index \p Pos was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Agent is not \c rosa::deluxe::DeluxeAgent
/// `NotSensor` | Referred \p Sensor is not \c rosa::deluxe::DeluxeSensor
/// `WrongPosition` | \p Pos is not a valid input position of \p Agent
/// `TypeMismatch` | Expected input type at position \p Pos of \p Agent is other thanthe output type of \p Sensor or expected master-input of \p Sensor is other than master-output at position \p Pos of \p Agent if any
/// `AlreadyHasSlave` | \p Agent at position \p Pos already has a *slave* registered
/// `AlreadyHasMaster` | \p Sensor already has a *master* registered
ErrorCode connectSensor(AgentHandle Agent, const size_t Pos,
AgentHandle Sensor,
const std::string &Description = "") noexcept;
/// Connectes two *agents* in the context of \p this object.
///
/// \param Master the *agent* to connect to
/// \param Pos the index of slot of \p Master to connect \p Slave to
/// \param Slave the *agent* to connect
/// \param Description optional textual description of the connection
///
/// \return how succesfull connecting \p Slave to \p Master at slot
/// index \p Pos was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Master or \p Slave is not \c rosa::deluxe::DeluxeAgent
/// `WrongPosition` | \p Pos is not a valid input position of \p Master
/// `TypeMismatch` | Expected input type at position \p Pos of \p Master is other than the output type of \p Slave or expected master-input of \p Slave is other than master-output at position \p Pos of \p Master if any
/// `AlreadyHasSlave` | \p Master at position \p Pos already has a *slave* registered
/// `AlreadyHasMaster` | \p Slave already has a *master* registered
ErrorCode connectAgents(AgentHandle Master, const size_t Pos,
AgentHandle Slave,
const std::string &Description = "") noexcept;
/// Initializes \c this object and others managed by \p this object
/// for setting up and performing simulation.
///
/// \see \c rosa::deluxe::DeluxeContext::registerSensorValues,
/// \c rosa::deluxe::DeluxeContext::simulate
///
/// Need to clear simulation data sources from all the *sensors*.
void initializeSimulation(void) noexcept;
public:
/// Registers a stream providing values for a *sensor* during
/// simulation.
///
/// \tparam Iterator type of iterator providing values for \p Sensor
/// \tparam T type that can be matched to values \p Sensor is operating on,
/// always use default!
///
/// \note Instantiation fails if type argument \p T is neither a built-in type
/// nor a tuple (i.e., can be converted to \c rosa::deluxe::DeluxeTuple).
///
/// \param Sensor the *sensor* to register values for
/// \param Start provides values for \p Sensor
/// \param End denotes the end of stream of values
/// \param Default value to be used when input stream is depleted
/// during simulation
///
/// \return how successful registering \p Source for \p Sensor
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `TypeMismatch` | \p T does not match the type of values
/// generated by \p Sensor
/// `NotSensor` | Referred \p Sensor is not \c
/// rosa::deluxe::DeluxeSensor
/// `AlreadyHasValueStream` | \p Sensor already has simulation data source set
template <typename Iterator, typename T = typename Iterator::value_type,
typename = std::enable_if_t<
TypeListContains<BuiltinTypes, T>::Value || IsTuple<T>::Value>>
ErrorCode registerSensorValues(AgentHandle Sensor, Iterator &&Start,
const Iterator &End, T Default = {}) noexcept;
/// Performs the system contained by \p this object.
///
/// The function performs \p NumCycles cycle of simulation. In each
/// cycle, all the *agents* and *sensors* registered in \c
/// rosa::deluxe::DeluxeContext::DeluxeUnits are trigged for
/// execution.
///
/// \param NumCycles number of cycles to perform
///
/// \pre All the *sensors* in the system contained by \p this object
/// generate their output from simulation data sources.
void simulate(const size_t NumCycles) const noexcept;
};
/// Anonymous namespace with helper features for implementing
/// \c rosa::deluxe::DeluxeContext, consider it private.
namespace {
/// Maps any type \p T to \c rosa::deluxe::EmptyDeluxeTuple.
template <typename T> struct MapToEmptyDeluxeTuple {
using Type = EmptyDeluxeTuple;
};
/// Convenience template alias for \c MapToEmptyDeluxeTuple.
template <typename T>
using empty_deluxe_t = typename MapToEmptyDeluxeTuple<T>::Type;
/// Converts a \c std::tuple of \c rosa::Optional built-in types into a
/// corresponding \c std::tuple of \c rosa::Optional with each actual value
/// wrapped in \c rosa::deluxe::DeluxeTuple.
///
/// \tparam Ts types of the values
/// \tparam S0 indices for accessing values in \p Values
///
/// \param Values the \c std::tuple of \c rosa::Optional with built-in values
///
/// \note The second argument provides indices statically as template arguments
/// \p S0..., so its actual value is ignored.
///
/// \return a \c std::tuple of \c rosa::Optional corresponding to \p Values
/// with each actual value wrapped in \c rosa::deluxe::DeluxeTuple
///
/// \pre Statically, all type arguments \p Ts... are built-in types and the
/// provided indices \p S0... match the length of \p Ts...: \code
/// TypeListSubsetOf<TypeList<Ts...>, BuiltinTypes>::Value &&
/// sizeof...(Ts) == sizeof...(S0)
/// \endcode
template <typename... Ts, size_t... S0>
std::tuple<Optional<DeluxeTuple<Ts>>...>
wrapBuiltinInDeluxeTuple(const std::tuple<Optional<Ts>...> &Values,
Seq<S0...>) noexcept {
STATIC_ASSERT((TypeListSubsetOf<TypeList<Ts...>, BuiltinTypes>::Value),
"not built-in types");
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent type arguments");
return std::make_tuple(std::get<S0>(Values)
? Optional<DeluxeTuple<Ts>>(
make_deluxe_tuple<Ts>(*std::get<S0>(Values)))
: Optional<DeluxeTuple<Ts>>()...);
}
} // End namespace
template <typename MT, typename T, typename>
AgentHandle
DeluxeContext::createSensorImpl(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept {
AgentHandle H = System->createSensor(Name, std::move(MF), std::move(F));
DeluxeUnits.emplace(H);
return H;
}
template <typename T, typename>
AgentHandle DeluxeContext::createSensor(const std::string &Name,
std::function<T(void)> &&F) noexcept {
auto EmptyMF = std::function<void(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {});
if constexpr (TypeListContains<BuiltinTypes, T>::Value) {
using OutputType = DeluxeTuple<T>;
return createSensorImpl(
Name, std::move(EmptyMF),
std::function<OutputType(void)>(
[F{std::move(F)}](void) { return OutputType(F()); }));
} else if constexpr (IsDeluxeTuple<T>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value) {
return createSensorImpl(Name, std::move(EmptyMF), std::move(F));
} else {
ASSERT(false && "Unexpected type argument");
}
}
template <typename MT, typename T, typename>
AgentHandle
DeluxeContext::createSensor(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept {
if constexpr (TypeListSubsetOf<TypeList<MT, T>, BuiltinTypes>::Value) {
using MasterInputType = DeluxeTuple<MT>;
using OutputType = DeluxeTuple<T>;
return createSensorImpl(
Name,
std::function<void(std::pair<MasterInputType, bool>)>(
[MF{std::move(MF)}](std::pair<MasterInputType, bool> Arg) {
MF({std::get<0>(Arg.first), Arg.second});
}),
std::function<OutputType(void)>(
[F{std::move(F)}](void) { return OutputType(F()); }));
} else if constexpr (TypeListAllDeluxeTuple<TypeList<MT, T>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value) {
return createSensorImpl(Name, std::move(MF), std::move(F));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename MT, typename T, typename... Ts, typename... As, typename>
AgentHandle DeluxeContext::createAgentImpl(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept {
AgentHandle H = System->createAgent(Name, std::move(MF), std::move(F));
DeluxeUnits.emplace(H);
return H;
}
template <typename T, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept {
using NoMasterOutputType = std::tuple<Optional<empty_deluxe_t<As>>...>;
auto EmptyMF =
std::function<NoMasterOutputType(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {
return NoMasterOutputType();
});
if constexpr (TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value) {
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name, std::move(EmptyMF),
std::function<
std::tuple<Optional<OutputType>, Optional<empty_deluxe_t<As>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return std::tuple_cat(
wrapBuiltinInDeluxeTuple(std::tuple(Result), seq_t<1>()),
NoMasterOutputType());
}));
} else if constexpr (TypeListAllDeluxeTuple<TypeList<T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
return createAgentImpl(
Name, std::move(EmptyMF),
std::function<std::tuple<Optional<T>, Optional<empty_deluxe_t<As>>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Result = F(Args...);
return std::tuple_cat(std::tuple(Result), NoMasterOutputType());
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename MT, typename T, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name, std::function<void(std::pair<MT, bool>)> &&MF,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept {
using NoMasterOutputType = std::tuple<Optional<empty_deluxe_t<As>>...>;
if constexpr (TypeListSubsetOf<TypeList<MT, T, As...>, BuiltinTypes>::Value) {
using MasterInputType = DeluxeTuple<MT>;
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name,
std::function<NoMasterOutputType(std::pair<MasterInputType, bool>)>(
[MF{std::move(MF)}](std::pair<MasterInputType, bool> Arg) {
MF({std::get<0>(Arg.first), Arg.second});
return NoMasterOutputType();
}),
std::function<
std::tuple<Optional<OutputType>, Optional<empty_deluxe_t<As>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return std::tuple_cat(
wrapBuiltinInDeluxeTuple(std::tuple(Result), seq_t<1>()),
NoMasterOutputType());
}));
} else if constexpr (TypeListAllDeluxeTuple<TypeList<MT, T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
return createAgentImpl(
Name,
std::function<NoMasterOutputType(std::pair<MT, bool>)>(
[MF{std::move(MF)}](std::pair<MT, bool> Arg) {
MF(Arg);
return NoMasterOutputType();
}),
std::function<std::tuple<Optional<T>, Optional<empty_deluxe_t<As>>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Result = F(Args...);
return std::tuple_cat(std::tuple(Result), NoMasterOutputType());
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename T, typename... Ts, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept {
if constexpr (TypeListSubsetOf<TypeList<T, Ts..., As...>,
BuiltinTypes>::Value) {
using MasterOutputType = std::tuple<Optional<DeluxeTuple<Ts>>...>;
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {
return MasterOutputType();
}),
std::function<
std::tuple<Optional<OutputType>, Optional<DeluxeTuple<Ts>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return wrapBuiltinInDeluxeTuple(Result,
seq_t<1 + sizeof...(Ts)>());
}));
} else if constexpr (TypeListAllDeluxeTuple<
TypeList<T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
using MasterOutputType = std::tuple<Optional<Ts>...>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {
return MasterOutputType();
}),
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Output = F(Args...);
return Output;
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename MT, typename T, typename... Ts, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept {
if constexpr (TypeListSubsetOf<TypeList<MT, T, Ts..., As...>,
BuiltinTypes>::Value) {
using MasterInputType = DeluxeTuple<MT>;
using MasterOutputType = std::tuple<Optional<DeluxeTuple<Ts>>...>;
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<MasterInputType, bool>)>(
[MF{std::move(MF)}](std::pair<MasterInputType, bool> Arg) {
const auto Result = MF({std::get<0>(Arg.first), Arg.second});
return wrapBuiltinInDeluxeTuple(Result, seq_t<sizeof...(Ts)>());
}),
std::function<
std::tuple<Optional<OutputType>, Optional<DeluxeTuple<Ts>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return wrapBuiltinInDeluxeTuple(Result,
seq_t<1 + sizeof...(Ts)>());
}));
} else if constexpr (TypeListAllDeluxeTuple<
TypeList<MT, T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
using MasterOutputType = std::tuple<Optional<Ts>...>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<MT, bool>)>(
[MF{std::move(MF)}](std::pair<MT, bool> Arg) {
const auto Output = MF(Arg);
return Output;
}),
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Output = F(Args...);
return Output;
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename Iterator, typename T, typename>
DeluxeContext::ErrorCode
DeluxeContext::registerSensorValues(AgentHandle Sensor, Iterator &&Start,
const Iterator &End, T Default) noexcept {
// Get the type of values provided by \p Iterator.
STATIC_ASSERT((std::is_same<T, typename Iterator::value_type>::value),
"type mismatch");
// Make sure preconditions are met.
if (!System->isDeluxeSensor(Sensor)) {
DCRETERROR(ErrorCode::NotSensor);
}
auto S = System->getDeluxeSensor(Sensor);
ASSERT(S); // Sanity check.
if (S->simulationDataSourceIsSet()) {
DCRETERROR(ErrorCode::AlreadyHasValueStream);
}
if constexpr (TypeListContains<BuiltinTypes, T>::Value) {
if (S->OutputType != TypeToken<T>::Value) {
DCRETERROR(ErrorCode::TypeMismatch);
}
// Register input stream.
// \note Need to capture parameters by value so having local copies.
S->registerSimulationDataSource(std::function<DeluxeTuple<T>(void)>([=
](void) mutable noexcept->DeluxeTuple<T> {
if (Start != End) {
LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
<< "': " << *Start << '\n';
return make_deluxe_tuple<T>(*Start++);
} else {
LOG_TRACE_STREAM << "Providing default value for sensor '"
<< S->FullName << "': " << Default << '\n';
return make_deluxe_tuple<T>(Default);
}
}));
} else if constexpr (IsTuple<T>::Value) {
using TT = matching_deluxe_tuple_t<T>;
if (std::is_same<T, EmptyDeluxeTuple>::value || S->OutputType != TT::TT) {
DCRETERROR(ErrorCode::TypeMismatch);
}
// Register input stream.
// \note Need to capture parameters by value so having local copies.
S->registerSimulationDataSource(
std::function<TT(void)>([=](void) mutable noexcept->TT {
if (Start != End) {
const TT DV(*Start++);
LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
<< "': " << DV << '\n';
return DV;
} else {
static const TT DD(Default);
LOG_TRACE_STREAM << "Providing default value for sensor '"
<< S->FullName << "': " << DD << '\n';
return DD;
}
}));
} else {
ASSERT(false && "Unexpected type argument");
}
return ErrorCode::NoError;
}
} // End namespace deluxe
} // End namespace rosa
// Undef local macro if not used in the corresponding implementation.
#ifndef ROSA_LIB_DELUXE_DELUXECONTEXT_CPP
#undef DCRETERROR
#endif
#endif // ROSA_DELUXE_DELUXECONTEXT_HPP

File Metadata

Mime Type
text/x-c++
Expires
Sun, Apr 12, 11:42 AM (1 d, 11 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
297003
Default Alt Text
DeluxeContext.hpp (38 KB)

Event Timeline