Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F27037015
DeluxeAgent.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Authored By
Unknown
Size
44 KB
Referenced Files
None
Subscribers
None
DeluxeAgent.hpp
View Options
//===-- rosa/deluxe/DeluxeAgent.hpp -----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeAgent.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Specialization of \c rosa::Agent for *agent* role of the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXEAGENT_HPP
#define ROSA_DELUXE_DELUXEAGENT_HPP
#include
"rosa/core/Agent.hpp"
#include
"rosa/deluxe/DeluxeAtoms.hpp"
#include
<map>
/// Local helper macros to deal with built-in types.
///
///@{
/// Creates function name for member functions in \c rosa::deluxe::DeluxeAgent.
///
/// \param N name suffix to use
#define DASLAVEHANDLERNAME(N) handleSlave_##N
/// Creates function name for member functions in \c rosa::deluxe::DeluxeAgent.
///
/// \param N name suffix to use
#define DAMASTERHANDLERNAME(N) handleMaster_##N
/// Defines member functions for handling messages from *slaves* in
/// \c rosa::deluxe::DeluxeAgent.
///
/// \see \c DeluxeAgentInputHandlers
///
/// \note No pre- and post-conditions are validated directly by these functions,
/// they rather rely on \c rosa::deluxe::DeluxeAgent::saveInput to do that.
///
/// \param T the type of input to handle
/// \param N name suffix for the function identifier
#define DASLAVEHANDLERDEFN(T, N) \
void DASLAVEHANDLERNAME(N)(atoms::Slave, id_t SlaveId, T Value) noexcept { \
saveInput(SlaveId, Value); \
}
/// Defines member functions for handling messages from *master* in
/// \c rosa::deluxe::DeluxeAgent.
///
/// \see \c DeluxeAgentMasterInputHandlers
///
/// \note No pre- and post-conditions are validated directly by these functions,
/// they rather rely on \c rosa::deluxe::DeluxeAgent::saveMasterInput to do
/// that.
///
/// \param T the type of input to handle
/// \param N name suffix for the function identifier
#define DAMASTERHANDLERDEFN(T, N) \
void DAMASTERHANDLERNAME(N)(atoms::Master, id_t MasterId, \
T Value) noexcept { \
saveMasterInput(MasterId, Value); \
}
/// Convenience macro for \c DASLAVEHANDLERDEFN with identical arguments.
///
/// \see \c DASLAVEHANDLERDEFN
///
/// This macro can be used instead of \c DASLAVEHANDLERDEFN if the actual value
/// of \p T can be used as a part of a valid identifier.
///
/// \param T the type of input to handle
#define DASLAVEHANDLERDEF(T) DASLAVEHANDLERDEFN(T, T)
/// Convenience macro for \c DAMASTERHANDLERDEFN with identical arguments.
///
/// \see \c DAMASTERHANDLERDEFN
///
/// This macro can be used instead of \c DAMASTERHANDLERDEFN if the actual value
/// of \p T can be used as a part of a valid identifier.
///
/// \param T the type of input to handle
#define DAMASTERHANDLERDEF(T) DAMASTERHANDLERDEFN(T, T)
/// Results in a \c THISMEMBER reference to a member function defined by
/// \c DASLAVEHANDLERDEFN.
///
/// Used in the constructor of \c rosa::deluxe::DeluxeAgent to initialize super
/// class \c rosa::Agent with member function defined by \c DASLAVEHANDLERDEFN.
///
/// \see \c DASLAVEHANDLERDEFN, \c THISMEMBER
///
/// \param N name suffix for the function identifier
#define DASLAVEHANDLERREF(N) THISMEMBER(DASLAVEHANDLERNAME(N))
/// Results in a \c THISMEMBER reference to a member function defined by
/// \c DAMASTERHANDLERDEFN.
///
/// Used in the constructor of \c rosa::deluxe::DeluxeAgent to initialize super
/// class \c rosa::Agent with member function defined by \c DAMASTERHANDLERDEFN.
///
/// \see \c DAMASTERHANDLERDEFN, \c THISMEMBER
///
/// \param N name suffix for the function identifier
#define DAMASTERHANDLERREF(N) THISMEMBER(DAMASTERHANDLERNAME(N))
///@}
namespace
rosa
{
namespace
deluxe
{
/// Specialization of \c rosa::Agent for *agent* role of the *deluxe interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
/// \invariant All input-related container objects have a size matching
/// \c rosa::deluxe::DeluxeAgent::NumberOfInputs, thus having a corresponding
/// entry for each input. \c rosa::deluxe::DeluxeAgent::NumberOfMasterOutputs
/// matches \c rosa::deluxe::DeluxeAgent::NumberOfInputs. All
/// master-output-related container objects have a size matching \c
/// rosa::deluxe::DeluxeAgent::NumberOfMasterOutputs. Types of input and
/// master-output values are consistent throughout all the input-related and
/// master-output-related containers, respectively. No *slave* is registered at
/// more than one input position. *Slave* registrations and corresponding
/// reverse lookup information are consistent.
///
/// \see Definition of \c rosa::deluxe::DeluxeAgent::inv on the class invariant
///
/// \note All member functions validate the class invariant as part of their
/// precondition. Moreover, non-const functions validate the invariant before
/// return as their postcondition.
class
DeluxeAgent
:
public
Agent
{
/// Checks whether \p this object holds the class invariant.
///
/// \see Invariant of the class \c rosa::deluxe::DeluxeAgent
///
/// \return if \p this object holds the class invariant
bool
inv
(
void
)
const
noexcept
;
public
:
/// The type of values produced by \p this object.
///
/// That is the type of values \p this object sends to its *master*.
///
/// \see \c rosa::deluxe::DeluxeAgent::master
const
TypeNumber
OutputType
;
/// Number of inputs processed by \p this object.
const
size_t
NumberOfInputs
;
/// The type of values \p this object processes from its *master*.
///
/// \see \c rosa::deluxe::DeluxeAgent::master
const
TypeNumber
MasterInputType
;
/// Number of outputs produces by \p this object for its *slaves*.
///
/// \note This values is equal to \c
/// rosa::deluxe::DeluxeAgent::NumberOfInputs.
///
/// \see \c rosa::deluxe::DeluxeAgent::slave.
const
size_t
NumberOfMasterOutputs
;
private
:
/// Types of input values produced by *slaves* of \p this object.
///
/// \note The \c rosa::TypeNumber values stored here match the corresponding
/// values in \c rosa::deluxe::DeluxeAgent::InputValues.
///
/// \note The position of a type in the \c std::vector indicates which
/// argument of \p this object's processing function it belongs to. See also
/// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
const
std
::
vector
<
TypeNumber
>
InputTypes
;
/// Indicates whether any particular input value has been changed since the
/// last trigger received from the system.
///
/// All the flags are reset to \c false upon handling a trigger and then set
/// to \c true by \c rosa::deluxe::DeluxeAgent::saveInput when storing a new
/// input value in \c rosa::deluxe::DeluxeAgent::InputValues.
///
/// \note The position of a flag in the \c std::vector indicates which
/// argument of \p this object's processing function it belongs to. See also
/// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
std
::
vector
<
bool
>
InputChanged
;
/// Stores the actual input values.
///
/// \note The types of stored values match the corresponding
/// \c rosa::TypeNumber values in \c rosa::deluxe::DeluxeAgent::InputTypes.
///
/// \note The position of a value in the \c rosa::AbstractTokenizedStorage
/// indicates which argument of \p this object's processing function it is.
/// See also \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
const
std
::
unique_ptr
<
AbstractTokenizedStorage
>
InputValues
;
/// Indicates whether the input value from the *master* has been changed since
/// the last trigger received from the system.
///
/// The flag is reset to \c false upon handling a trigger and then set to \c
/// true by \c rosa::deluxe::DeluxeAgent::saveMasterInput when storig a new
/// input value in \c rosa::deluxe::DeluxeAgent::MasterInputValue.
bool
MasterInputChanged
;
/// Stores the actual input value from *master*.
///
/// \note The type of the stored value matches the type indicated by \c
/// rosa::deluxe::DeluxeAgent::MasterInputType.
const
std
::
unique_ptr
<
AbstractTokenizedStorage
>
MasterInputValue
;
/// Types of output values produced by \p this object for its *slaves*.
///
/// That is the type of values \p this object sends to its *slaves*.
///
/// \note The position of a type in the \c std::vector indicates which
/// *slave* of \p this object the type belongs to. See also
/// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
const
std
::
vector
<
TypeNumber
>
MasterOutputTypes
;
/// Alias for function objects used as trigger handler for
/// \c rosa::deluxe::DeluxeAgent.
///
/// \note The function used for \c H is to be \c noexcept.
///
/// \see \c rosa::deluxe::DeluxeAgent::FP
using
H
=
std
::
function
<
void
(
void
)
>
;
/// Handles trigger from the system.
///
/// The actual functions processing *slave* and *master* inputs and generating
/// optional output to *master* and *slaves* are captured in a lambda
/// expression that is in turn wrapped in a \c std::function object. The
/// lambda expression calls the master-input processing function with the
/// actual master-input data and sends its result -- if any -- to *slaves* by
/// calling \c rosa::deluxe::DeluxeAgent::handleMasterOutputs; then calls the
/// input processing function with the actual input data and sends its result
/// -- if any -- to *master* by calling \c
/// rosa::deluxe::DeluxeAgent::sendToMaster and *slaves* by calling \c
/// rosa::deluxe::DeluxeAgent::handleMasterOutputs. Also, all the flags stored
/// in \c rosa::deluxe::DeluxeAgent::InputChanged and \c
/// rosa::deluxe::DeluxeAgent::MasterInputChanged are reset when the current
/// values are processed. The function \c
/// rosa::deluxe::DeluxeAgent::handleTrigger needs only to call the
/// function object.
///
/// \see \c
/// rosa::deluxe::DeluxeAgent::triggerHandlerFromProcessingFunctions
const
H
FP
;
/// The *master* to send values to.
///
/// \note *Masters* are set dynamically, hence it is possible that a
/// \c rosa::deluxe::DeluxeAgent instance does not have any *master* at a
/// given moment.
Optional
<
AgentHandle
>
Master
;
/// The *slaves* sending input to \p this object.
///
/// \note The position of a *slave* in the \c std::vector indicates which
/// argument of \p this object's processing function it belongs to. See also
/// \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \note *Slaves* are set dynamically, hence it is possible that a
/// \c rosa::deluxe::DeluxeAgent instance does have input positions without
/// any *slave* associated to them.
///
/// \note Reverse lookup information is maintained in
/// \c rosa::deluxe::DeluxeAgent::SlaveIds, which is to be kept in sync with
/// the *slaves* stored here.
std
::
vector
<
Optional
<
AgentHandle
>>
Slaves
;
/// Associates \c rosa::id_t values to corresponding indices of registered
/// *slaves*.
///
/// \see \c rosa::deluxe::DeluxeAgent::Slaves
std
::
map
<
id_t
,
size_t
>
SlaveIds
;
/// Tells the unique identifier of the *master* of \p this object, if any
/// registered.
///
/// \return the unique identifier of the *master*
///
/// \pre A *master* is registered for \p this object: \code
/// Master
/// \endcode
id_t
masterId
(
void
)
const
noexcept
;
/// Tells whether types stored in \c rosa::TypeList \p As match the input
/// types of \p this object.
///
/// \tparam As \c rosa::TypeList containing types to match against values in
/// \c rosa::deluxe::DeluxeAgent::InputTypes
///
/// \note Instatiation of the template fails if \p As is not \c
/// rosa::TypeList.
///
/// \return if types in \p As match \c rosa::TypeNumber values stored in
/// \c rosa::deluxe::DeluxeAgent::InputTypes
template
<
typename
As
>
bool
inputTypesMatch
(
void
)
const
noexcept
;
/// Tells whether types stored in \c rosa::TypeList \p Ts match the
/// master-output types of \p this object.
///
/// \tparam Ts \c rosa::TypeList containing types to match against values in
/// \c rosa::deluxe::DeluxeAgent::MasterOutputTypes
///
/// \note Instatiation of the template fails if \p As is not \c
/// rosa::TypeList.
///
/// \return if types in \p Ts match \c rosa::TypeNumber values stored in
/// \c rosa::deluxe::DeluxeAgent::MasterOutputTypes
template
<
typename
Ts
>
bool
masterOutputTypesMatch
(
void
)
const
noexcept
;
/// Gives an \c std::tuple containing the current input values and their
/// change flags so that they can be used for the processing function.
///
/// \tparam As types of the input values
/// \tparam S0 indices for accessing input values and their change flags
///
/// \note The only argument provides indices statically as template arguments
/// \p S0..., so its actual value is ignored.
///
/// \return current input values and their change flags prepared for invoking
/// the processing function with them
///
/// \pre The type arguments \p As... match the input types of \p this object
/// and the provided indices \p S0... constitute a proper sequence for
/// accessing input values and their change flags: \code
/// inputTypesMatch<TypeList<As...>>() && sizeof...(As) == sizeof...(S0)
/// \endcode
template
<
typename
...
As
,
size_t
...
S0
>
std
::
tuple
<
std
::
pair
<
As
,
bool
>
...
>
prepareCurrentInputs
(
Seq
<
S0
...
>
)
const
noexcept
;
/// Invokes a processing function matching the input, output, and
/// master-output input types of \p this object with actual arguments provided
/// in a \c std::tuple.
///
/// \note \p Args providing the actual arguments for \p F is to be created by
/// \c rosa::deluxe::DeluxeAgent::prepareCurrentInputs.
///
/// \tparam T output type of the processing function
/// \tparam Ts types of master-output values of the processing function
/// \tparam As types of inputs for the processing function
/// \tparam S0 indices starting with `0` for extracting actual arguments from
/// \p Args
///
/// \param F the processing function to invoke
/// \param Args the actual arguments to invoke \p F with
///
/// \note The last argument provides indices statically as template arguments
/// \p S0..., so its actual value is ignored.
///
/// \return the result of \p F for actual arguments \p Args
///
/// \pre The provided sequence of indices \p S0... constitutes a proper
/// sequence for extracting all actual arguments for
/// \p F from \p Args: \code
/// sizeof...(As) == sizeof...(S0)
/// \endcode
template
<
typename
T
,
typename
...
Ts
,
typename
...
As
,
size_t
...
S0
>
static
std
::
tuple
<
Optional
<
T
>
,
Optional
<
Ts
>
...
>
invokeWithTuple
(
std
::
function
<
std
::
tuple
<
Optional
<
T
>
,
Optional
<
Ts
>
...
>
(
std
::
pair
<
As
,
bool
>
...)
>
F
,
const
std
::
tuple
<
std
::
pair
<
As
,
bool
>
...
>
Args
,
Seq
<
S0
...
>
)
noexcept
;
/// Handles the master-output value at position \p Pos of \p Output.
///
/// \p Output is a \c std::tuple resulted by a processing function and
/// contains master-output values starting at position \p Offset. The
/// function takes the master-output value for *slave* position \p Pos and
/// sends its actual value, if any, to the corresponding *slave*.
///
/// \note A master-output of type \c rosa::unit_t indicates no actual output
/// and hence no message is generated for a position whose corresponding
/// master-output type is \c rosa::unit_t.
///
/// \note The function provides position-based implementation for \c
/// rosa::deluxe::DeluxeAgent::handleMasterOutputs.
///
/// \tparam Offset index of the first master-output value in \p Output
/// \tparam Pos the position of the master-output to handle
/// \tparam Ts output types stored in \p Output
///
/// \param Output \c std::tuple resulted by the processing function
///
/// \pre \p Output matches the master-output types \p this object was created
/// with and \p Pos is a valid master-output index: \code
/// masterOutputTypesMatch<typename TypeListDrop<Offset,
/// TypeList<Ts...>>::Type>() &&
/// Pos < NumberOfMasterOutputs
/// \endcode
template
<
size_t
Offset
,
size_t
Pos
,
typename
...
Ts
>
void
handleMasterOutputAtPos
(
const
std
::
tuple
<
Optional
<
Ts
>
...
>
&
Output
)
noexcept
;
/// Handles master-output values from \p Output.
///
/// \p Output is a \c std::tuple resulted by a processing function and
/// contains master-output values starting at position \p Offset. The function
/// takes master-output values and sends each actual value to the
/// corresponding *slave*.
///
/// \tparam Offset index of the first master-output value in \p Output
/// \tparam Ts output types stored in \p Output
/// \tparam S0 indices starting with `0` for extracting master-output values
/// from \p Output
///
/// \param Output \c std::tuple resulted by a processing function
///
/// \pre \p Output matches the master-output types \p this object was created
/// with and the provided sequence of indices \p S0... constitues a proper
/// sequence for extraing all master-output values from \p Output: \code
/// masterOutputTypesMatch<typename TypeListDrop<Offset,
/// TypeList<Ts...>>::Type>() &&
/// sizeof...(S0) == NumberOfMasterOutputs
/// \endcode
template
<
size_t
Offset
,
typename
...
Ts
,
size_t
...
S0
>
void
handleMasterOutputs
(
const
std
::
tuple
<
Optional
<
Ts
>
...
>
&
Output
,
Seq
<
S0
...
>
)
noexcept
;
/// Wraps processing functions into a trigger handler.
///
/// \see \c rosa::deluxe::DeluxeAgent::FP
///
/// \note The function cannot be const qualified because the lambda
/// expression defined in it needs to capture \p this object by a non-const
/// reference
///
/// \tparam MT type of master-input
/// \tparam T type of output
/// \tparam Ts types of master-output values
/// \tparam As types of input values
///
/// \param MF function processing master-input and generating output
/// \param F function processing inputs and generating output
///
/// \note A master-input type of \c rosa::unit_t indicates that \p this object
/// does not receive master-input, \p MF is never called if \p MT is \c
/// rosa::unit_t.
///
/// \return trigger handler function based on \p F and \p MF
///
/// \pre Template arguments \p MT, \p T, \p Ts..., and \p As... match the
/// corresponding types \p this object was created with: \code
/// MasterInputType == TypeNumberOf<MT>::Value &&
/// OutputType == TypeNumberOf<T>::Value &&
/// inputTypesMatch<TypeList<As...>>() &&
/// masterOutputTypesMatch<TypeList<Ts...>>()
/// \endcode
template
<
typename
MT
,
typename
T
,
typename
...
Ts
,
typename
...
As
>
H
triggerHandlerFromProcessingFunctions
(
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 instance.
///
/// The constructor instantiates the base-class with functions to handle
/// messages as defined for the *deluxe interface*.
///
/// The function \p F generates a \c std::tuple of values: the first value is
/// the output for the *master* and the rest is for the *slaves*. All output
/// generated by the function is optional as an agent may decide not to output
/// anything at some situation.
///
/// \todo Enforce \p F and \p MF do not potentially throw exception.
///
/// \tparam MT type of master-input handled by \p MF
/// \tparam T type of output of \p F
/// \tparam Ts type of master-output values of \p F and \p MF
/// \tparam As types of input values of \p F
///
/// \note Instantiation fails if any of the type arguments \p MT, \p T, \p
/// Ts..., and \p As... is not a built-in type.
///
/// \note If \p MT is \c rosa::unit_t, the constructed object does not receive
/// master-input. Similarly, if any of \p Ts... is \c rosa::unit_t, the
/// constructed object does not generated master-output for the corresponding
/// *slave* position.
///
/// \param Kind kind of the new \c rosa::Unit instance
/// \param Id unique identifier of the new \c rosa::Unit instance
/// \param Name name of the new \c rosa::Unit instance
/// \param S \c rosa::MessagingSystem owning the new instance
/// \param MF function to process master-input values and generate
/// master-output with
/// \param F function to process input values and generate output and
/// master-output with
///
/// \pre Statically, all of the type arguments \p MT, \p T, \p Ts..., and \p
/// As... is a built-in type and the number of input and master-output types
/// are equal: \code
/// TypeListSubsetOf<TypeList<MT, T, Ts..., As...>,
/// BuiltinTypes>::Value && sizeof...(Ts) == sizeof...(As)
///\endcode
/// Dynamically, the instance is created as of kind \c
/// rosa::deluxe::atoms::AgentKind: \code
/// Kind == rosa::deluxe::atoms::AgentKind
/// \endcode
template
<
typename
MT
,
typename
T
,
typename
...
Ts
,
typename
...
As
,
typename
=
std
::
enable_if_t
<
TypeListSubsetOf
<
TypeList
<
MT
,
T
,
Ts
...,
As
...
>
,
BuiltinTypes
>::
Value
&&
sizeof
...(
Ts
)
==
sizeof
...(
As
)
>>
DeluxeAgent
(
const
AtomValue
Kind
,
const
id_t
Id
,
const
std
::
string
&
Name
,
MessagingSystem
&
S
,
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
;
/// Destroys \p this object.
~
DeluxeAgent
(
void
)
noexcept
;
/// The *master* of \p this object, if any is registered.
///
/// \see \c rosa::deluxe::DeluxeAgent::registerMaster
///
/// \return the *master* registered for \p this object
Optional
<
AgentHandle
>
master
(
void
)
const
noexcept
;
/// Registers a *master* for \p this object.
///
/// The new *master* is registered by overwriting the reference to any
/// already registered *master*. One can clear the registered reference by
/// passing an *empty* \c rosa::Optional object as actual argument.
///
/// \note The role of the referred *master* is validated by checking its
/// *kind*.
///
/// \note Any call to \c rosa::deluxe::DeluxeAgent::registerMaster should be
/// paired with a corresponding call of \c
/// rosa::deluxe::DeluxeAgent::registerSlave, which validates that
/// input/output types of master and slave matches.
///
/// \param _Master the *master* to register
///
/// \pre \p _Master is empty or of kind \c rosa::deluxe::atoms::AgentKind:
/// \code
/// !_Master || unwrapAgent(*_Master).Kind == rosa::deluxe::atoms::AgentKind
/// \endcode
void
registerMaster
(
const
Optional
<
AgentHandle
>
_Master
)
noexcept
;
/// Tells the type of values consumed from the *slave* at a position.
///
/// That is the type of values \p this object expect to be sent to it by its
/// *slave* registered at position \p Pos.
///
/// \see \c rosa::deluxe::DeluxeAgent::slave
///
/// \param Pos position of *slave*
///
/// \return \c rosa::TypeNumber representing the type of values consumed from
/// the *slave* at position \p Pos
///
/// \pre \p Pos is a valid index of input: \code
/// Pos < NumberOfInputs
/// \endcode
TypeNumber
inputType
(
const
size_t
Pos
)
const
noexcept
;
/// Tells the type of values produced for the *slave* at a position.
///
/// That is the type of values \p this object potentially sends to its
/// *slave* registered at position \p Pos.
///
/// \see \c rosa::deluxe::DeluxeAgent::slave
///
/// \param Pos position of *slave*
///
/// \return \c rosa::TypeNumber representing the type of values produced for
/// the *slave* at position \p Pos
///
/// \pre \p Pos is a valid index of input: \code
/// Pos < NumberOfMasterOutputs
/// \endcode
TypeNumber
masterOutputType
(
const
size_t
Pos
)
const
noexcept
;
/// The *slave* of \p this object registered at a position, if any.
///
/// \see \c rosa::deluxe::DeluxeAgent::registerSlave
///
/// \param Pos position of *slave*
///
/// \return the *slave* registered for \p this object at position \p Pos
///
/// \pre \p Pos is a valid index of input: \code
/// Pos < NumberOfInputs
/// \endcode
Optional
<
AgentHandle
>
slave
(
const
size_t
Pos
)
const
noexcept
;
/// Registers a *slave* for \p this object at a position.
///
/// The new *slave* is registered by overwriting the reference to any already
/// registered *slave* at position \p Pos. One can clear the registered
/// reference by passing an *empty* \c rosa::Optional object as actual
/// argument. If \p Slave is already registered for another position, the
/// other position gets cleared.
///
/// \note The role of the referred *slave* is validated by checking its
/// *kind*.
///
/// \note The type of values produced by the referred *slave* is validated by
/// matching its `OutputType` against the corresponding value in
/// \c rosa::deluxe::DeluxeAgent::InputTypes.
///
/// \note The type of master-input values processed by the referred *slave* is
/// validated by matching its `MasterInputType` against the corresponding
/// value in \c rosa::deluxe::DeluxeAgent::MasterOutputTypes.
///
/// \param Pos position to register \p Slave at
/// \param Slave the *slave* to register
///
/// \pre \p Pos is a valid index of input, \p Slave is empty or of kind
/// \c rosa::deluxe::atoms::AgentKind or \c rosa::deluxe::atoms::SensorKind,
/// and \p Slave -- if not empty -- produces values of types matching the
/// expected input type at position \p Pos and processes values of types
/// matching the produced master-output type at position \p Pos:
/// \code
/// Pos < NumberOfInputs &&
/// (!Slave ||
/// (unwrapAgent(*Slave.)Kind == rosa::deluxe::atoms::SensorKind &&
/// static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).OutputType ==
/// InputTypes[Pos] &&
/// (MasterOutputTypes[Pos] == TypeNumberOf<unit_t>::Value ||
/// static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).MasterInputType
/// == MasterOutputTypes[Pos])) ||
/// (unwrapAgent(*Slave).Kind == rosa::deluxe::atoms::AgentKind &&
/// static_cast<const DeluxeAgent &>(unwrapAgent(*Slave)).OutputType ==
/// InputTypes[Pos] &&
/// (MasterOutputTypes[Pos] == TypeNumberOf<unit_t>::Value ||
/// static_cast<const DeluxeAgent &>(unwrapAgent(*Slave)).MasterInputType ==
/// MasterOutputTypes[Pos])))
/// \endcode
void
registerSlave
(
const
size_t
Pos
,
const
Optional
<
AgentHandle
>
Slave
)
noexcept
;
/// Tells the position of a registered *slave*.
///
/// \param Slave \c rosa::AgentHandle for the *slave* to check
///
/// \return position of \p Slave if it is registered and found,
/// \c rosa::deluxe::DeluxeAgent::NumberOfInputs otherwise.
size_t
positionOfSlave
(
AgentHandle
Slave
)
const
noexcept
;
private
:
/// Sends a value to the *master* of \p this object.
///
/// \p Value is getting sent to \c rosa::deluxe::DeluxeAgent::Master if it
/// contains a valid handle for a \c rosa::deluxe::DeluxeAgent. The function
/// does nothing otherwise.
///
/// \tparam T type of the value to send
///
/// \param Value value to send
///
/// \pre \p T matches \c rosa::deluxe::DeluxeiAgent::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
sendToMaster
(
const
T
&
Value
)
noexcept
;
/// Sends a value to a *slave* of \p this object at position \p Pos.
///
/// \p Value is getting sent to \c rosa::deluxe::DeluxeAgent::Slaves[Pos] if
/// it contains a valid handle. The function does nothing otherwise.
///
/// \tparam T type of the value to send
///
/// \param Pos the position of the *slave* to send \p Value to
/// \param Value value to send
///
/// \pre \p Pos is a valid *slave* position and \p T matches \c
/// rosa::deluxe::DeluxeiAgent::MasterOutputTypes[Pos]: \code
/// Pos < NumberOfMasterOutputs &&
/// MasterOutputTypes[Pos] == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
sendToSlave
(
const
size_t
Pos
,
const
T
&
Value
)
noexcept
;
/// Generates the next output by processing current input values upon trigger
/// from the system.
///
/// Executes \c rosa::deluxe::DeluxeAgent::FP.
///
/// \note The only argument is a \c rosa::AtomConstant, hence its actual
/// value is ignored.
void
handleTrigger
(
atoms
::
Trigger
)
noexcept
;
/// Stores a new input value from a *slave*.
///
/// The function stores \p Value in \c rosa::deluxe::DeluxeAgent::InputValues
/// at the position associated to \p Id in
/// \c rosa::deluxe::DeluxeAgent::SlaveIds and also sets the corresponding
/// flag in \c rosa::deluxe::DeluxeAgent::InputChanged.
///
/// \note Utilized by member functions of group \c DeluxeAgentInputHandlers.
///
/// \tparam T type of input to store
///
/// \param Id unique identifier of *slave*
/// \param Value the input value to store
///
/// \pre The *slave* with \p Id is registered and the input from it is
/// expected to be of type \p T: \code
/// SlaveIds.find(Id) != SlaveIds.end() &&
/// InputTypes[SlaveIds.find(Id)->second] == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
saveInput
(
id_t
Id
,
T
Value
)
noexcept
;
/// Stores a new input value from the *master*.
///
/// The function stores \p Value in \c
/// rosa::deluxe::DeluxeAgent::MasterInputValue and also sets the
/// corresponding flag \c rosa::deluxe::DeluxeAgent::MasterInputChanged.
///
/// \note Utilized by member functions of group \c
/// DeluxeAgentMasterInputHandlers.
///
/// \tparam T type of input to store
///
/// \param Id unique identifier of the *master*
/// \param Value the input value to store
///
/// \pre The *master* with \p Id is registered and the input from the *master*
/// is expected to be of type \p T: \code
/// Master && masterId() == Id && MasterInputType == TypeNumberOf<T>::Value
/// \endcode
template
<
typename
T
>
void
saveMasterInput
(
id_t
Id
,
T
Value
)
noexcept
;
/// \defgroup DeluxeAgentInputHandlers Input handlers of
/// rosa::deluxe::DeluxeAgent
///
/// Definition of member functions handling messages from *slaves* with
/// different types of input
///
/// A *master* generally needs to be prepared to deal with values of any
/// built-in type to handle messages from its *slaves*. Each type requires a
/// separate message handler, which are implemented by these functions. The
/// functions instantiate \c rosa::deluxe::DeluxeAgent::saveInput with the
/// proper template argument and pass the content of the message on for
/// processing.
///
/// \note The member functions in this group are defined by \c
/// DASLAVEHANDLERDEF.
///
/// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
///
///@{
DASLAVEHANDLERDEF
(
AtomValue
)
DASLAVEHANDLERDEF
(
int16_t
)
DASLAVEHANDLERDEF
(
int32_t
)
DASLAVEHANDLERDEF
(
int64_t
)
DASLAVEHANDLERDEF
(
int8_t
)
DASLAVEHANDLERDEFN
(
long
double
,
long_double
)
DASLAVEHANDLERDEFN
(
std
::
string
,
std__string
)
DASLAVEHANDLERDEF
(
uint16_t
)
DASLAVEHANDLERDEF
(
uint32_t
)
DASLAVEHANDLERDEF
(
uint64_t
)
DASLAVEHANDLERDEF
(
uint8_t
)
DASLAVEHANDLERDEF
(
unit_t
)
DASLAVEHANDLERDEF
(
bool
)
DASLAVEHANDLERDEF
(
double
)
DASLAVEHANDLERDEF
(
float
)
/// @}
/// \defgroup DeluxeAgentMasterInputHandlers Master-input handlers of
/// rosa::deluxe::DeluxeAgent
///
/// Definition of member functions handling messages from the *master* with
/// different types of input
///
/// A *slave* generally needs to be prepared to deal with values of any
/// built-in type, except for \c rosa::unit_t, to handle messages from its
/// *master*. Each type requires a separate message handler, which are
/// implemented by these functions. The functions instantiate
/// \c rosa::deluxe::DeluxeAgent::saveMasterInput with the proper template
/// argument and pass the content of the message on for processing.
///
/// \note The member functions in this group are defined by \c
/// DAMASTERHANDLERDEF.
///
/// \note Keep these definitions in sync with \c rosa::BuiltinTypes; but do no
/// include \c rosa::unit_t.
///
///@{
DAMASTERHANDLERDEF
(
AtomValue
)
DAMASTERHANDLERDEF
(
int16_t
)
DAMASTERHANDLERDEF
(
int32_t
)
DAMASTERHANDLERDEF
(
int64_t
)
DAMASTERHANDLERDEF
(
int8_t
)
DAMASTERHANDLERDEFN
(
long
double
,
long_double
)
DAMASTERHANDLERDEFN
(
std
::
string
,
std__string
)
DAMASTERHANDLERDEF
(
uint16_t
)
DAMASTERHANDLERDEF
(
uint32_t
)
DAMASTERHANDLERDEF
(
uint64_t
)
DAMASTERHANDLERDEF
(
uint8_t
)
DAMASTERHANDLERDEF
(
bool
)
DAMASTERHANDLERDEF
(
double
)
DAMASTERHANDLERDEF
(
float
)
/// @}
};
/// Anonymous namespace with implementation for
/// \c rosa::deluxe::DeluxeAgent::inputTypesMatch and \c
/// rosa::deluxe::DeluxeAgent::masterOutputTypesMatch, consider it private.
namespace
{
/// Template \c struct whose specializations provide a recursive implementation
/// for \c TypesMatchList.
///
/// \tparam As types to match
template
<
typename
...
As
>
struct
TypesMatchImpl
;
/// Template specialization for the general case, when at least one type is to
/// be matched.
///
/// \tparam A first type to match
/// \tparam As further types to match
template
<
typename
A
,
typename
...
As
>
struct
TypesMatchImpl
<
A
,
As
...
>
{
/// Tells whether types \p A, \p As... match \c rosa::TypeNumber values
/// stored in \p Types starting at position \p Pos.
///
/// The function has got a recursive implementation: it matches the first
/// type \p A against \c rosa::TypeNumber at position \p Pos of \p Types, then
/// further types \p As.. are matched recursively starting at position
/// \c (Pos + 1).
///
/// \param Types container of \c rosa::TypeNumber values to match types
/// against
/// \param Pos position in \p Types to start matching at
///
/// \return if types \p A, \p As... match \c rosa::TypeNumber values stored
/// in \p Types starting at position \p Pos
static
bool
f
(
const
std
::
vector
<
TypeNumber
>
&
Types
,
size_t
Pos
)
noexcept
{
return
Pos
<
Types
.
size
()
&&
TypeNumberOf
<
A
>::
Value
==
Types
[
Pos
]
&&
TypesMatchImpl
<
As
...
>::
f
(
Types
,
Pos
+
1
);
}
};
/// Template specialization for the terminal case, when no type remains to
/// check.
template
<>
struct
TypesMatchImpl
<>
{
/// Tells whether \p Pos is the number of values stored in \p Types.
///
/// In this terminal case, there is no more types to match because all the
/// types are supposed to be already matched successfully. The whole list of
/// types already matched is a complete match if it covers all values in
/// \p Types. That is true if \p Pos points exactly to the end of \p Types.
///
/// \param Types container of \c rosa::TypeNumber values to match types
/// against
/// \param Pos position in \p Types to start matching at
///
/// \return if \p Pos is the number of values stored in \p Types
static
bool
f
(
const
std
::
vector
<
TypeNumber
>
&
Types
,
size_t
Pos
)
noexcept
{
return
Pos
==
Types
.
size
();
}
};
/// Template \c struct that provides an implementation for \c
/// rosa::deluxe::DeluxeAgent::inputTypesMatch and \c
/// rosa::deluxe::DeluxeAgent::masterOutputTypesMatch.
///
/// \note Match a list of types \p As... against a \c std::vector of
/// \c rosa::TypeNumber values, \c Types, like \code
/// bool match = TypesMatchList<TypeList<As...>>::f(Types);
/// \endcode
///
/// \tparam As \c rosa::TypeList that contains types to match
template
<
typename
As
>
struct
TypesMatchList
;
/// Template specialization implementing the feature.
///
/// \tparam As \c rosa::TypeList that contains types to match
template
<
typename
...
As
>
struct
TypesMatchList
<
TypeList
<
As
...
>>
{
/// Tells whether types \p As... match \c rosa::TypeNumber values
/// stored in \p Types.
///
/// The function unwraps the types from \c rosa::TypeList and utilizes \c
/// TypesMatchImpl to do the check.
///
/// \param Types container of \c rosa::TypeNumber values to match types
/// against
///
/// \return if types \p As... match \c rosa::TypeNumber values stored
/// in \p Types
static
bool
f
(
const
std
::
vector
<
TypeNumber
>
&
Types
)
noexcept
{
return
TypesMatchImpl
<
As
...
>::
f
(
Types
,
0
);
}
};
}
// End namespace
template
<
typename
As
>
bool
DeluxeAgent
::
inputTypesMatch
(
void
)
const
noexcept
{
return
TypesMatchList
<
As
>::
f
(
InputTypes
);
}
template
<
typename
Ts
>
bool
DeluxeAgent
::
masterOutputTypesMatch
(
void
)
const
noexcept
{
return
TypesMatchList
<
Ts
>::
f
(
MasterOutputTypes
);
}
template
<
typename
...
As
,
size_t
...
S0
>
std
::
tuple
<
std
::
pair
<
As
,
bool
>
...
>
DeluxeAgent
::
prepareCurrentInputs
(
Seq
<
S0
...
>
)
const
noexcept
{
// Need to indirectly reference \c rosa::deluxe::DeluxeAgent::inputTypesMatch
// inside \c ASSERT because of the comma in its template argument list.
auto
MFP
=
&
DeluxeAgent
::
inputTypesMatch
<
TypeList
<
As
...
>>
;
ASSERT
(
inv
()
&&
(
this
->*
MFP
)()
&&
sizeof
...(
As
)
==
sizeof
...(
S0
));
return
std
::
make_tuple
(
std
::
make_pair
(
*
static_cast
<
const
As
*>
(
InputValues
->
pointerTo
(
S0
)),
InputChanged
[
S0
])...);
}
template
<
typename
T
,
typename
...
Ts
,
typename
...
As
,
size_t
...
S0
>
std
::
tuple
<
Optional
<
T
>
,
Optional
<
Ts
>
...
>
DeluxeAgent
::
invokeWithTuple
(
std
::
function
<
std
::
tuple
<
Optional
<
T
>
,
Optional
<
Ts
>
...
>
(
std
::
pair
<
As
,
bool
>
...)
>
F
,
const
std
::
tuple
<
std
::
pair
<
As
,
bool
>
...
>
Args
,
Seq
<
S0
...
>
)
noexcept
{
ASSERT
(
sizeof
...(
As
)
==
sizeof
...(
S0
));
return
F
(
std
::
get
<
S0
>
(
Args
)...);
}
template
<
size_t
Offset
,
size_t
Pos
,
typename
...
Ts
>
void
DeluxeAgent
::
handleMasterOutputAtPos
(
const
std
::
tuple
<
Optional
<
Ts
>
...
>
&
Output
)
noexcept
{
// Need to indirectly reference \c
// rosa::deluxe::DeluxeAgent::masterOutputTypesMatch inside \c ASSERT because
// of the comma in its template argument list.
auto
MOTMFP
=
&
DeluxeAgent
::
masterOutputTypesMatch
<
typename
TypeListDrop
<
Offset
,
TypeList
<
Ts
...
>>::
Type
>
;
ASSERT
(
inv
()
&&
(
this
->*
MOTMFP
)()
&&
Pos
<
NumberOfMasterOutputs
);
// Do not do anything for master-output type \c rosa::unit_t.
if
(
!
std
::
is_same
<
typename
TypeListAt
<
TypeList
<
Ts
...
>
,
Offset
+
Pos
>::
Type
,
unit_t
>::
value
)
{
const
auto
MasterOutput
=
std
::
get
<
Offset
+
Pos
>
(
Output
);
if
(
MasterOutput
)
{
sendToSlave
(
Pos
,
*
MasterOutput
);
}
}
}
template
<
size_t
Offset
,
typename
...
Ts
,
size_t
...
S0
>
void
DeluxeAgent
::
handleMasterOutputs
(
const
std
::
tuple
<
Optional
<
Ts
>
...
>
&
Output
,
Seq
<
S0
...
>
)
noexcept
{
// Need to indirectly reference \c
// rosa::deluxe::DeluxeAgent::masterOutputTypesMatch inside \c ASSERT because
// of the comma in its template argument list.
auto
MOTMFP
=
&
DeluxeAgent
::
masterOutputTypesMatch
<
typename
TypeListDrop
<
Offset
,
TypeList
<
Ts
...
>>::
Type
>
;
ASSERT
(
inv
()
&&
(
this
->*
MOTMFP
)()
&&
sizeof
...(
S0
)
==
NumberOfMasterOutputs
);
// Handle each master-output position in a fold expression.
(
handleMasterOutputAtPos
<
Offset
,
S0
>
(
Output
),
...);
}
template
<
typename
MT
,
typename
T
,
typename
...
Ts
,
typename
...
As
>
DeluxeAgent
::
H
DeluxeAgent
::
triggerHandlerFromProcessingFunctions
(
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
{
// Need to indirectly reference \c rosa::deluxe::DeluxeAgent::inputTypesMatch
// and \c rosa::deluxe::DeluxeAgent::masterOutputTypesMatch inside \c ASSERT
// because of the comma in their respective template argument lists.
auto
ITMFP
=
&
DeluxeAgent
::
inputTypesMatch
<
TypeList
<
As
...
>>
;
auto
MOTMFP
=
&
DeluxeAgent
::
masterOutputTypesMatch
<
TypeList
<
Ts
...
>>
;
ASSERT
(
MasterInputType
==
TypeNumberOf
<
MT
>::
Value
&&
OutputType
==
TypeNumberOf
<
T
>::
Value
&&
(
this
->*
ITMFP
)()
&&
(
this
->*
MOTMFP
)());
return
[
this
,
MF
,
F
]()
noexcept
{
// \note These indices work for both inputs and master-outputs.
using
Indices
=
typename
GenSeq
<
sizeof
...(
As
)
>::
Type
;
// Handle master-input.
// Do not do anything for master-input type \c rosa::unit_t.
if
(
MasterInputType
!=
TypeNumberOf
<
unit_t
>::
Value
)
{
LOG_TRACE_STREAM
<<
"DeluxeAgent "
<<
Name
<<
" handles master-input."
<<
std
::
endl
;
const
auto
MasterInputArg
=
std
::
make_pair
(
*
static_cast
<
const
MT
*>
(
MasterInputValue
->
pointerTo
(
0
)),
MasterInputChanged
);
MasterInputChanged
=
false
;
const
std
::
tuple
<
Optional
<
Ts
>
...
>
MasterOutput
=
MF
(
MasterInputArg
);
handleMasterOutputs
<
0
>
(
MasterOutput
,
Indices
());
}
// Handle inputs.
LOG_TRACE_STREAM
<<
"DeluxeAgent "
<<
Name
<<
" handles input."
<<
std
::
endl
;
const
auto
InputArgs
=
prepareCurrentInputs
<
As
...
>
(
Indices
());
std
::
fill
(
InputChanged
.
begin
(),
InputChanged
.
end
(),
false
);
const
std
::
tuple
<
Optional
<
T
>
,
Optional
<
Ts
>
...
>
Output
=
invokeWithTuple
(
F
,
InputArgs
,
Indices
());
const
auto
OutputToMaster
=
std
::
get
<
0
>
(
Output
);
if
(
OutputToMaster
)
{
sendToMaster
(
*
OutputToMaster
);
}
handleMasterOutputs
<
1
>
(
Output
,
Indices
());
};
}
template
<
typename
MT
,
typename
T
,
typename
...
Ts
,
typename
...
As
,
typename
>
DeluxeAgent
::
DeluxeAgent
(
const
AtomValue
Kind
,
const
id_t
Id
,
const
std
::
string
&
Name
,
MessagingSystem
&
S
,
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
:
Agent
(
Kind
,
Id
,
Name
,
S
,
THISMEMBER
(
handleTrigger
),
DASLAVEHANDLERREF
(
AtomValue
),
DASLAVEHANDLERREF
(
int16_t
),
DASLAVEHANDLERREF
(
int32_t
),
DASLAVEHANDLERREF
(
int64_t
),
DASLAVEHANDLERREF
(
int8_t
),
DASLAVEHANDLERREF
(
long_double
),
DASLAVEHANDLERREF
(
std__string
),
DASLAVEHANDLERREF
(
uint16_t
),
DASLAVEHANDLERREF
(
uint32_t
),
DASLAVEHANDLERREF
(
uint64_t
),
DASLAVEHANDLERREF
(
uint8_t
),
DASLAVEHANDLERREF
(
unit_t
),
DASLAVEHANDLERREF
(
bool
),
DASLAVEHANDLERREF
(
double
),
DASLAVEHANDLERREF
(
float
),
DAMASTERHANDLERREF
(
AtomValue
),
DAMASTERHANDLERREF
(
int16_t
),
DAMASTERHANDLERREF
(
int32_t
),
DAMASTERHANDLERREF
(
int64_t
),
DAMASTERHANDLERREF
(
int8_t
),
DAMASTERHANDLERREF
(
long_double
),
DAMASTERHANDLERREF
(
std__string
),
DAMASTERHANDLERREF
(
uint16_t
),
DAMASTERHANDLERREF
(
uint32_t
),
DAMASTERHANDLERREF
(
uint64_t
),
DAMASTERHANDLERREF
(
uint8_t
),
DAMASTERHANDLERREF
(
bool
),
DAMASTERHANDLERREF
(
double
),
DAMASTERHANDLERREF
(
float
)),
OutputType
(
TypeNumberOf
<
T
>::
Value
),
NumberOfInputs
(
sizeof
...(
As
)),
MasterInputType
(
TypeNumberOf
<
MT
>::
Value
),
NumberOfMasterOutputs
(
NumberOfInputs
),
InputTypes
({
TypeNumberOf
<
As
>::
Value
...}),
InputChanged
(
NumberOfInputs
,
false
),
InputValues
(
new
TokenizedStorage
<
As
...
>
()),
MasterInputChanged
(
false
),
MasterInputValue
(
new
TokenizedStorage
<
MT
>
()),
MasterOutputTypes
({
TypeNumberOf
<
Ts
>::
Value
...}),
FP
(
triggerHandlerFromProcessingFunctions
(
std
::
move
(
MF
),
std
::
move
(
F
))),
Slaves
(
NumberOfInputs
)
{
ASSERT
(
Kind
==
atoms
::
AgentKind
);
LOG_TRACE
(
"DeluxeAgent is created."
);
ASSERT
(
inv
());
}
template
<
typename
T
>
void
DeluxeAgent
::
sendToMaster
(
const
T
&
Value
)
noexcept
{
ASSERT
(
inv
()
&&
OutputType
==
TypeNumberOf
<
T
>::
Value
);
// There is a handle and the referred *master* is in a valid state.
if
(
Master
&&
*
Master
)
{
Master
->
sendMessage
(
Message
::
create
(
atoms
::
Slave
::
Value
,
Id
,
Value
));
}
}
template
<
typename
T
>
void
DeluxeAgent
::
sendToSlave
(
const
size_t
Pos
,
const
T
&
Value
)
noexcept
{
ASSERT
(
inv
()
&&
Pos
<
NumberOfMasterOutputs
&&
MasterOutputTypes
[
Pos
]
==
TypeNumberOf
<
T
>::
Value
);
// There is a handle and the referred *slave* is in a valid state.
auto
Slave
=
Slaves
[
Pos
];
if
(
Slave
&&
*
Slave
)
{
Slave
->
sendMessage
(
Message
::
create
(
atoms
::
Master
::
Value
,
Id
,
Value
));
}
}
template
<
typename
T
>
void
DeluxeAgent
::
saveInput
(
id_t
Id
,
T
Value
)
noexcept
{
ASSERT
(
inv
()
&&
SlaveIds
.
find
(
Id
)
!=
SlaveIds
.
end
()
&&
InputTypes
[
SlaveIds
.
find
(
Id
)
->
second
]
==
TypeNumberOf
<
T
>::
Value
);
size_t
Pos
=
SlaveIds
.
at
(
Id
);
*
static_cast
<
T
*>
(
InputValues
->
pointerTo
(
Pos
))
=
Value
;
InputChanged
[
Pos
]
=
true
;
ASSERT
(
inv
());
}
template
<
typename
T
>
void
DeluxeAgent
::
saveMasterInput
(
id_t
Id
,
T
Value
)
noexcept
{
ASSERT
(
inv
()
&&
Master
&&
masterId
()
==
Id
&&
MasterInputType
==
TypeNumberOf
<
T
>::
Value
);
*
static_cast
<
T
*>
(
MasterInputValue
->
pointerTo
(
0
))
=
Value
;
MasterInputChanged
=
true
;
ASSERT
(
inv
());
}
}
// End namespace deluxe
}
// End namespace rosa
#undef DASLAVEHANDLEREF
#undef DAMASTERHANDLEREF
#undef DASLAVEHANDLEDEF
#undef DAMASTERHANDLEDEF
#undef DASLAVEHANDLEDEFN
#undef DAMASTERHANDLEDEFN
#undef DASLAVEHANDLENAME
#undef DAMASTERHANDLENAME
#endif
// ROSA_DELUXE_DELUXEAGENT_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Tue, Oct 27, 8:23 PM (1 d, 17 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
410406
Default Alt Text
DeluxeAgent.hpp (44 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline