Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F1497447
DeluxeAgent.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
25 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 DAHANDLERNAME(N) handleSlave_##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 DAHANDLERDEFN(T, N) \
void DAHANDLERNAME(N)(atoms::Slave, id_t SlaveId, T Value) noexcept { \
saveInput(SlaveId, Value); \
}
/// Convenience macro for \c DAHANDLERDEFN with identical arguments.
///
/// \see \c DAHANDLERDEFN
///
/// This macro can be used instead of \c DAHANDLERDEFN 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 DAHANDLERDEF(T) DAHANDLERDEFN(T, T)
/// Results in a \c THISMEMBER reference to a member function defined by
/// \c DAHANDLERDEFN.
///
/// Used in the constructor of \c rosa::deluxe::DeluxeAgent to initialize super
/// class \c rosa::Agent with member function defined by \c DAHANDLERDEFN.
///
/// \see \c DAHANDLERDEFN, \c THISMEMBER
///
/// \param N name suffix for the function identifier
#define DAHANDLERREF(N) THISMEMBER(DAHANDLERNAME(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. Types of input values are consistent throughout all
/// the input-related containers. 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
:
/// Template alias for function objects used to process input and generate
/// output for \c rosa::deluxe::DeluxeAgent.
///
/// The output generated by the function is optional as an agent may decide
/// not to output anything at some situation.
///
/// \note The function used for \c D is to be \c noexcept.
///
/// \tparam T type of output
/// \tparam As types of input values
template
<
typename
T
,
typename
...
As
>
using
D
=
std
::
function
<
Optional
<
T
>
(
std
::
pair
<
As
,
bool
>
...)
>
;
/// 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
;
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::D.
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::D.
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::D.
const
std
::
unique_ptr
<
AbstractTokenizedStorage
>
InputValues
;
/// 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 function processing *slave* inputs and generating optional
/// output to *master* is captured in a lambda expression that is in turn
/// wrapped in a \c std::function object. The lambda expression calls the
/// processing function with the actual input data and sends its result -- if
/// any -- to *master* by calling \c rosa::deluxe::DeluxeAgent::sendToMaster.
/// Also, all the flags stored in \c rose::deluxe::DeluxeAgent::InputChanged
/// are reset when the current input values are processed. The function
/// \c rosa::deluxe::DeluxeAgent::handleTrigger needs only to call the
/// function object.
///
/// \see \c rosa::deluxe::DeluxeAgent::triggerHandlerFromProcessingFunction
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::D.
///
/// \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 whether types \p As... match the input types of \p this object.
///
/// \tparam As types to match against values in
/// \c rosa::deluxe::DeluxeAgent::InputTypes
///
/// \return if types \p As... match \c rosa::TypeNumber values stored in
/// \c rosa::deluxe::DeluxeAgent::InputTypes
template
<
typename
...
As
>
bool
inputTypesMatch
(
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<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 output and 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 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
...
As
,
size_t
...
S0
>
static
Optional
<
T
>
invokeWithTuple
(
D
<
T
,
As
...
>
F
,
std
::
tuple
<
std
::
pair
<
As
,
bool
>
...
>
Args
,
Seq
<
S0
...
>
)
noexcept
;
/// Wraps a processing function 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 T type of output
/// \tparam As types of input values
///
/// \param F function processing inputs and generating output
///
/// \pre Template arguments \p T and \p As... match the corresponding
/// types \p this object was created with: \code
/// OutputType == TypeNumberOf<T>::Value && inputTypesMatch<As...>()
/// \endcode
template
<
typename
T
,
typename
...
As
>
H
triggerHandlerFromProcessingFunction
(
D
<
T
,
As
...
>
&&
F
)
noexcept
;
public
:
/// Creates a new instance.
///
/// The constructor instantiates the base-class with functions to handle
/// messages as defined for the *deluxe interface*.
///
/// \todo Enforce F does not potentially throw exception.
///
/// \tparam T type of output of \p F
/// \tparam As types of input values of \p F
///
/// \note Instantiation fails if any of the type arguments \p T and \p As...
/// is not a built-in type.
///
/// \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 F function to process input values and generate output with
///
/// \pre Statically, all of the type arguments \p T and \p As... is a
/// built-in type: \code
/// TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value
/// \endcode Dynamically, the instance is created as of kind
/// \c rosa::deluxe::atoms::AgentKind: \code
/// Kind == rosa::deluxe::atoms::AgentKind
/// \endcode
template
<
typename
T
,
typename
...
As
,
typename
=
std
::
enable_if_t
<
TypeListSubsetOf
<
TypeList
<
T
,
As
...
>
,
BuiltinTypes
>::
Value
>>
DeluxeAgent
(
const
AtomValue
Kind
,
const
id_t
Id
,
const
std
::
string
&
Name
,
MessagingSystem
&
S
,
D
<
T
,
As
...
>
&&
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*.
///
/// \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
;
/// 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.
///
/// \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:
/// \code
/// Pos < NumberOfInputs &&
/// (!Slave ||
/// (unwrapAgent(*Slave.)Kind == rosa::deluxe::atoms::SensorKind &&
/// static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).OutputType ==
/// InputTypes[Pos]) ||
/// (unwrapAgent(*Slave).Kind == rosa::deluxe::atoms::AgentKind &&
/// static_cast<const DeluxeAgent &>(unwrapAgent(*Slave)).OutputType ==
/// InputTypes[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
;
/// 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
;
/// \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. 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 DAHANDLERDEF.
///
/// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
///
///@{
DAHANDLERDEF
(
AtomValue
)
DAHANDLERDEF
(
int16_t
)
DAHANDLERDEF
(
int32_t
)
DAHANDLERDEF
(
int64_t
)
DAHANDLERDEF
(
int8_t
)
DAHANDLERDEFN
(
long
double
,
long_double
)
DAHANDLERDEFN
(
std
::
string
,
std__string
)
DAHANDLERDEF
(
uint16_t
)
DAHANDLERDEF
(
uint32_t
)
DAHANDLERDEF
(
uint64_t
)
DAHANDLERDEF
(
uint8_t
)
DAHANDLERDEF
(
unit_t
)
DAHANDLERDEF
(
bool
)
DAHANDLERDEF
(
double
)
DAHANDLERDEF
(
float
)
/// @}
};
/// Anonymous namespace with implementation for
/// \c rosa::deluxe::DeluxeAgent::inputTypesMatch, consider it private.
namespace
{
/// Template \c struct whose specializations provide a recursive implementation
/// for \c rosa::deluxe::DeluxeAgent::inputTypesMatch.
///
/// \note Matching a list of types \p As... against a \c std::vector of
/// \c rosa::TypeNumber values, \c InputTypes, like \code
/// bool match = InputTypesMatchImpl<As...>::f(InputTypes, 0);
/// \endcode
///
/// \tparam As types to match
template
<
typename
...
As
>
struct
InputTypesMatchImpl
;
/// 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
InputTypesMatchImpl
<
A
,
As
...
>
{
/// Tells whether types \p A, \p As... match \c rosa::TypeNumber values
/// stored in \p InputTypes 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
/// InputTypes, then further types \p As.. are matched recursively starting
/// at position \c (Pos + 1).
///
/// \param InputTypes container of \c rosa::TypeNumber values to match
/// types against
/// \param Pos position in \p InputTypes to start matching at
///
/// \return if types \p A, \p As... match \c rosa::TypeNumber values stored
/// in \p InputTypes starting at position \p Pos
static
bool
f
(
const
std
::
vector
<
TypeNumber
>
&
InputTypes
,
size_t
Pos
)
noexcept
{
return
Pos
<
InputTypes
.
size
()
&&
TypeNumberOf
<
A
>::
Value
==
InputTypes
[
Pos
]
&&
InputTypesMatchImpl
<
As
...
>::
f
(
InputTypes
,
Pos
+
1
);
}
};
/// Template specialization for the terminal case, when no type remains to
/// check.
template
<>
struct
InputTypesMatchImpl
<>
{
/// Tells whether \p Pos is the number of values stored in \p InputTypes.
///
/// In this terminal case, there is no more types to matchi 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 InputTypes. That is true if \p Pos points exactly to the end of
/// \p InputTypes.
///
/// \param InputTypes container of \c rosa::TypeNumber values to match
/// types against
/// \param Pos position in \p InputTypes to start matching at
///
/// \return if \p Pos is the number of values stored in \p InputTypes
static
bool
f
(
const
std
::
vector
<
TypeNumber
>
&
InputTypes
,
size_t
Pos
)
noexcept
{
return
Pos
==
InputTypes
.
size
();
}
};
}
// End namespace
template
<
typename
...
As
>
bool
DeluxeAgent
::
inputTypesMatch
(
void
)
const
noexcept
{
return
InputTypesMatchImpl
<
As
...
>::
f
(
InputTypes
,
0
);
}
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
<
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
...
As
,
size_t
...
S0
>
Optional
<
T
>
DeluxeAgent
::
invokeWithTuple
(
D
<
T
,
As
...
>
F
,
std
::
tuple
<
std
::
pair
<
As
,
bool
>
...
>
Args
,
Seq
<
S0
...
>
)
noexcept
{
ASSERT
(
sizeof
...(
As
)
==
sizeof
...(
S0
));
return
F
(
std
::
get
<
S0
>
(
Args
)...);
}
template
<
typename
T
,
typename
...
As
>
DeluxeAgent
::
H
DeluxeAgent
::
triggerHandlerFromProcessingFunction
(
D
<
T
,
As
...
>
&&
F
)
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
<
As
...
>
;
ASSERT
(
OutputType
==
TypeNumberOf
<
T
>::
Value
&&
(
this
->*
MFP
)());
return
[
this
,
F
]()
noexcept
{
using
Indices
=
typename
GenSeq
<
sizeof
...(
As
)
>::
Type
;
auto
Args
=
prepareCurrentInputs
<
As
...
>
(
Indices
());
std
::
fill
(
InputChanged
.
begin
(),
InputChanged
.
end
(),
false
);
Optional
<
T
>
R
=
invokeWithTuple
(
F
,
Args
,
Indices
());
if
(
R
)
{
sendToMaster
(
*
R
);
}
};
}
template
<
typename
T
,
typename
...
As
,
typename
>
DeluxeAgent
::
DeluxeAgent
(
const
AtomValue
Kind
,
const
id_t
Id
,
const
std
::
string
&
Name
,
MessagingSystem
&
S
,
D
<
T
,
As
...
>
&&
F
)
noexcept
:
Agent
(
Kind
,
Id
,
Name
,
S
,
THISMEMBER
(
handleTrigger
),
DAHANDLERREF
(
AtomValue
),
DAHANDLERREF
(
int16_t
),
DAHANDLERREF
(
int32_t
),
DAHANDLERREF
(
int64_t
),
DAHANDLERREF
(
int8_t
),
DAHANDLERREF
(
long_double
),
DAHANDLERREF
(
std__string
),
DAHANDLERREF
(
uint16_t
),
DAHANDLERREF
(
uint32_t
),
DAHANDLERREF
(
uint64_t
),
DAHANDLERREF
(
uint8_t
),
DAHANDLERREF
(
unit_t
),
DAHANDLERREF
(
bool
),
DAHANDLERREF
(
double
),
DAHANDLERREF
(
float
)),
OutputType
(
TypeNumberOf
<
T
>::
Value
),
NumberOfInputs
(
sizeof
...(
As
)),
InputTypes
({
TypeNumberOf
<
As
>::
Value
...}),
InputChanged
(
NumberOfInputs
,
false
),
InputValues
(
new
TokenizedStorage
<
As
...
>
()),
FP
(
triggerHandlerFromProcessingFunction
(
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
::
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
());
}
}
// End namespace deluxe
}
// End namespace rosa
#undef DAHANDLEREF
#undef DAHANDLEDEF
#undef DAHANDLEDEFN
#undef DAHANDLENAME
#endif
// ROSA_DELUXE_DELUXEAGENT_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Mar 1, 9:34 PM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
286477
Default Alt Text
DeluxeAgent.hpp (25 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment