Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F5298803
Application.hpp
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Size
37 KB
Referenced Files
None
Subscribers
None
Application.hpp
View Options
//===-- rosa/app/Application.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/app/Application.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2020
///
/// \brief Public interface for the *application interface* for working with
/// agent
/// systems.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_APP_APPLICATION_HPP
#define ROSA_APP_APPLICATION_HPP
#include
"rosa/app/AppSystem.hpp"
#include
"rosa/support/types.hpp"
#include
<iterator>
#include
<memory>
#include
<set>
/// Local helper macro to log and return a
/// \c rosa::app::Application::ErrorCode value.
///
/// Creates a debug message with the stringified value and returns the value.
///
/// \param Err \c rosa::app::Application::ErrorCode value to log and
/// return
#define APPRETERROR(Err) \
{ \
LOG_DEBUG(#Err); \
return Err; \
}
namespace
rosa
{
namespace
app
{
/// Defines the *application interface*.
///
/// \todo The classes \c rosa::app::AppSensor and \c
/// rosa::app::AppAgent share some common features in relation to their
/// *slave* role in the *application interface*. But their definitions are
/// completely independent. It could be investigated how to lift their common
/// parts into a new *application slave* class, which would serve as base for
/// both, to avoid code duplication.
class
Application
{
/// 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::app::Application::getSystem.
std
::
shared_ptr
<
AppSystem
>
System
;
/// References to all *sensors* and *agents* created by \p this object.
std
::
set
<
AgentHandle
>
AppUnits
;
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::app::Application.
///
/// \param Name name of the underlying \c rosa::AppSystem
///
/// \return \c std::unique_ptr for the new instance of
/// \c rosa::app::Application with a new, empty \c rosa::AppSystem
static
std
::
unique_ptr
<
Application
>
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
Application
(
const
std
::
string
&
Name
)
noexcept
;
public
:
/// Destroys \p this object.
~
Application
(
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::app::AppTuple or \p T is \c
/// rosa::app::EmptyAppTuple.
///
/// \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::app::Application::registerSensorValues is used to
/// register an alternative simulation data source with \c
/// rosa::app::AppSensor::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::app::AppSensor::AppSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template
<
typename
MT
,
typename
T
,
typename
=
std
::
enable_if
<
TypeListAllAppTuple
<
TypeList
<
MT
,
T
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
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::app::AppTuple 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::app::Application::registerSensorValues is used to register
/// an alternative simulation data source with
/// \c rosa::app::AppSensor::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::app::AppSensor::AppSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template
<
typename
T
,
typename
=
std
::
enable_if_t
<
TypeListContains
<
BuiltinTypes
,
T
>::
Value
||
(
IsAppTuple
<
T
>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
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::app::AppTuple. Moreover, \p T cannot be
/// \c rosa::app::EmptyAppTuple. 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::app::Application::registerSensorValues is used to
/// register an alternative simulation data source with \c
/// rosa::app::AppSensor::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::app::AppSensor::AppSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template
<
typename
MT
,
typename
T
,
typename
=
std
::
enable_if
<
TypeListSubsetOf
<
TypeList
<
MT
,
T
>
,
BuiltinTypes
>::
Value
||
(
TypeListAllAppTuple
<
TypeList
<
MT
,
T
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
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::app::AppTuple or
/// any of \p T and \p As... is \c rosa::app::EmptyAppTuple.
///
/// \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::app::AppAgent::AppAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template
<
typename
MT
,
typename
T
,
typename
...
Ts
,
typename
...
As
,
typename
=
std
::
enable_if_t
<
TypeListAllAppTuple
<
TypeList
<
MT
,
T
,
Ts
...,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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::app::AppTuple. Moreover, none of
/// them can be \c rosa::app::EmptyAppTuple. 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::app::AppAgent::AppAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template
<
typename
T
,
typename
...
As
,
typename
=
std
::
enable_if_t
<
TypeListSubsetOf
<
TypeList
<
T
,
As
...
>
,
BuiltinTypes
>::
Value
||
(
TypeListAllAppTuple
<
TypeList
<
T
,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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::app::AppTuple. Moreover,
/// none of \p T and \p As... can be \c rosa::app::EmptyAppTuple.
/// 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::app::AppAgent::AppAgent.
///
/// \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
||
(
TypeListAllAppTuple
<
TypeList
<
MT
,
T
,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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::app::AppTuple. Moreover,
/// none of \p T and \p As... can be \c rosa::app::EmptyAppTuple.
/// 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::app::EmptyAppTuple. It is not
/// possible to disable master-output at any position by using built-in types.
///
/// \see \c rosa::app::AppAgent::AppAgent.
///
/// \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
||
(
TypeListAllAppTuple
<
TypeList
<
T
,
Ts
...,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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::app::AppTuple.
/// Moreover, none of \p T and \p As... can be \c
/// rosa::app::EmptyAppTuple. 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::app::EmptyAppTuple. It is not
/// possible to disable master-output at any position by using built-in types.
///
/// \see \c rosa::app::AppAgent::AppAgent.
///
/// \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
||
(
TypeListAllAppTuple
<
TypeList
<
MT
,
T
,
Ts
...,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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::app::AppExecutionPolicy
///
/// \note The referred \p Unit is either *sensor* or *agent*.
///
/// \note The returned reference is valid only as long as \c
/// rosa::app::Application::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::app::AppExecutionPolicy from \p Unit if \p Unit
/// is valid
Optional
<
const
AppExecutionPolicy
&>
getExecutionPolicy
(
AgentHandle
Unit
)
const
noexcept
;
/// Sets the current execution policy of the referred \p Unit to \p
/// ExecutionPolicy.
///
/// \see \c rosa::app::AppExecutionPolicy
///
/// \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::app::Application::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
<
AppExecutionPolicy
>
&&
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::app::Application::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Agent is not \c rosa::app::AppAgent
/// `NotSensor` | Referred \p Sensor is not \c rosa::app::AppSensor
/// `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::app::Application::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Master or \p Slave is not \c
/// rosa::app::AppAgent `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::app::Application::registerSensorValues,
/// \c rosa::app::Application::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::app::AppTuple).
///
/// \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::app::Application::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::app::AppSensor
/// `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::app::Application::AppUnits 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::app::Application, consider it private.
namespace
{
/// Maps any type \p T to \c rosa::app::EmptyAppTuple.
template
<
typename
T
>
struct
MapToEmptyAppTuple
{
using
Type
=
EmptyAppTuple
;
};
/// Convenience template alias for \c MapToEmptyAppTuple.
template
<
typename
T
>
using
empty_app_t
=
typename
MapToEmptyAppTuple
<
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::app::AppTuple.
///
/// \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::app::AppTuple
///
/// \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
<
AppTuple
<
Ts
>>
...
>
wrapBuiltinInAppTuple
(
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
<
AppTuple
<
Ts
>>
(
make_app_tuple
<
Ts
>
(
*
std
::
get
<
S0
>
(
Values
)))
:
Optional
<
AppTuple
<
Ts
>>
()...);
}
}
// End namespace
template
<
typename
MT
,
typename
T
,
typename
>
AgentHandle
Application
::
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
));
AppUnits
.
emplace
(
H
);
return
H
;
}
template
<
typename
T
,
typename
>
AgentHandle
Application
::
createSensor
(
const
std
::
string
&
Name
,
std
::
function
<
T
(
void
)
>
&&
F
)
noexcept
{
auto
EmptyMF
=
std
::
function
<
void
(
std
::
pair
<
EmptyAppTuple
,
bool
>
)
>
(
[](
std
::
pair
<
EmptyAppTuple
,
bool
>
)
{});
if
constexpr
(
TypeListContains
<
BuiltinTypes
,
T
>::
Value
)
{
using
OutputType
=
AppTuple
<
T
>
;
return
createSensorImpl
(
Name
,
std
::
move
(
EmptyMF
),
std
::
function
<
OutputType
(
void
)
>
(
[
F
{
std
::
move
(
F
)}](
void
)
{
return
OutputType
(
F
());
}));
}
else
if
constexpr
(
IsAppTuple
<
T
>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
)
{
return
createSensorImpl
(
Name
,
std
::
move
(
EmptyMF
),
std
::
move
(
F
));
}
else
{
ASSERT
(
false
&&
"Unexpected type argument"
);
}
}
template
<
typename
MT
,
typename
T
,
typename
>
AgentHandle
Application
::
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
=
AppTuple
<
MT
>
;
using
OutputType
=
AppTuple
<
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
(
TypeListAllAppTuple
<
TypeList
<
MT
,
T
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
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
Application
::
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
));
AppUnits
.
emplace
(
H
);
return
H
;
}
template
<
typename
T
,
typename
...
As
,
typename
>
AgentHandle
Application
::
createAgent
(
const
std
::
string
&
Name
,
std
::
function
<
Optional
<
T
>
(
std
::
pair
<
As
,
bool
>
...)
>
&&
F
)
noexcept
{
using
NoMasterOutputType
=
std
::
tuple
<
Optional
<
empty_app_t
<
As
>>
...
>
;
auto
EmptyMF
=
std
::
function
<
NoMasterOutputType
(
std
::
pair
<
EmptyAppTuple
,
bool
>
)
>
(
[](
std
::
pair
<
EmptyAppTuple
,
bool
>
)
{
return
NoMasterOutputType
();
});
if
constexpr
(
TypeListSubsetOf
<
TypeList
<
T
,
As
...
>
,
BuiltinTypes
>::
Value
)
{
using
OutputType
=
AppTuple
<
T
>
;
return
createAgentImpl
(
Name
,
std
::
move
(
EmptyMF
),
std
::
function
<
std
::
tuple
<
Optional
<
OutputType
>
,
Optional
<
empty_app_t
<
As
>>
...
>
(
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...)
>
(
[
F
{
std
::
move
(
F
)}](
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...
Args
)
{
const
auto
Result
=
F
({
std
::
get
<
0
>
(
Args
.
first
),
Args
.
second
}...);
return
std
::
tuple_cat
(
wrapBuiltinInAppTuple
(
std
::
tuple
(
Result
),
seq_t
<
1
>
()),
NoMasterOutputType
());
}));
}
else
if
constexpr
(
TypeListAllAppTuple
<
TypeList
<
T
,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
value
)))
{
return
createAgentImpl
(
Name
,
std
::
move
(
EmptyMF
),
std
::
function
<
std
::
tuple
<
Optional
<
T
>
,
Optional
<
empty_app_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
Application
::
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_app_t
<
As
>>
...
>
;
if
constexpr
(
TypeListSubsetOf
<
TypeList
<
MT
,
T
,
As
...
>
,
BuiltinTypes
>::
Value
)
{
using
MasterInputType
=
AppTuple
<
MT
>
;
using
OutputType
=
AppTuple
<
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_app_t
<
As
>>
...
>
(
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...)
>
(
[
F
{
std
::
move
(
F
)}](
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...
Args
)
{
const
auto
Result
=
F
({
std
::
get
<
0
>
(
Args
.
first
),
Args
.
second
}...);
return
std
::
tuple_cat
(
wrapBuiltinInAppTuple
(
std
::
tuple
(
Result
),
seq_t
<
1
>
()),
NoMasterOutputType
());
}));
}
else
if
constexpr
(
TypeListAllAppTuple
<
TypeList
<
MT
,
T
,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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_app_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
Application
::
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
<
AppTuple
<
Ts
>>
...
>
;
using
OutputType
=
AppTuple
<
T
>
;
return
createAgentImpl
(
Name
,
std
::
function
<
MasterOutputType
(
std
::
pair
<
EmptyAppTuple
,
bool
>
)
>
(
[](
std
::
pair
<
EmptyAppTuple
,
bool
>
)
{
return
MasterOutputType
();
}),
std
::
function
<
std
::
tuple
<
Optional
<
OutputType
>
,
Optional
<
AppTuple
<
Ts
>>
...
>
(
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...)
>
(
[
F
{
std
::
move
(
F
)}](
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...
Args
)
{
const
auto
Result
=
F
({
std
::
get
<
0
>
(
Args
.
first
),
Args
.
second
}...);
return
wrapBuiltinInAppTuple
(
Result
,
seq_t
<
1
+
sizeof
...(
Ts
)
>
());
}));
}
else
if
constexpr
(
TypeListAllAppTuple
<
TypeList
<
T
,
Ts
...,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
value
)))
{
using
MasterOutputType
=
std
::
tuple
<
Optional
<
Ts
>
...
>
;
return
createAgentImpl
(
Name
,
std
::
function
<
MasterOutputType
(
std
::
pair
<
EmptyAppTuple
,
bool
>
)
>
(
[](
std
::
pair
<
EmptyAppTuple
,
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
Application
::
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
=
AppTuple
<
MT
>
;
using
MasterOutputType
=
std
::
tuple
<
Optional
<
AppTuple
<
Ts
>>
...
>
;
using
OutputType
=
AppTuple
<
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
wrapBuiltinInAppTuple
(
Result
,
seq_t
<
sizeof
...(
Ts
)
>
());
}),
std
::
function
<
std
::
tuple
<
Optional
<
OutputType
>
,
Optional
<
AppTuple
<
Ts
>>
...
>
(
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...)
>
(
[
F
{
std
::
move
(
F
)}](
std
::
pair
<
AppTuple
<
As
>
,
bool
>
...
Args
)
{
const
auto
Result
=
F
({
std
::
get
<
0
>
(
Args
.
first
),
Args
.
second
}...);
return
wrapBuiltinInAppTuple
(
Result
,
seq_t
<
1
+
sizeof
...(
Ts
)
>
());
}));
}
else
if
constexpr
(
TypeListAllAppTuple
<
TypeList
<
MT
,
T
,
Ts
...,
As
...
>>::
Value
&&
!
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
&&
(
true
&&
...
&&
(
!
std
::
is_same
<
As
,
EmptyAppTuple
>::
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
>
Application
::
ErrorCode
Application
::
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
->
isAppSensor
(
Sensor
))
{
APPRETERROR
(
ErrorCode
::
NotSensor
);
}
auto
S
=
System
->
getAppSensor
(
Sensor
);
ASSERT
(
S
);
// Sanity check.
if
(
S
->
simulationDataSourceIsSet
())
{
APPRETERROR
(
ErrorCode
::
AlreadyHasValueStream
);
}
if
constexpr
(
TypeListContains
<
BuiltinTypes
,
T
>::
Value
)
{
if
(
S
->
OutputType
!=
TypeToken
<
T
>::
Value
)
{
APPRETERROR
(
ErrorCode
::
TypeMismatch
);
}
// Register input stream.
// \note Need to capture parameters by value so having local copies.
S
->
registerSimulationDataSource
(
std
::
function
<
AppTuple
<
T
>
(
void
)
>
([
=
](
void
)
mutable
noexcept
->
AppTuple
<
T
>
{
if
(
Start
!=
End
)
{
LOG_TRACE_STREAM
<<
"Reading next value for sensor '"
<<
S
->
FullName
<<
"': "
<<
PRINTABLE
(
*
Start
)
<<
'\n'
;
return
make_app_tuple
<
T
>
(
*
Start
++
);
}
else
{
LOG_TRACE_STREAM
<<
"Providing default value for sensor '"
<<
S
->
FullName
<<
"': "
<<
PRINTABLE
(
Default
)
<<
'\n'
;
return
make_app_tuple
<
T
>
(
Default
);
}
}));
}
else
if
constexpr
(
IsTuple
<
T
>::
Value
)
{
using
TT
=
matching_app_tuple_t
<
T
>
;
if
(
std
::
is_same
<
T
,
EmptyAppTuple
>::
value
||
S
->
OutputType
!=
TT
::
TT
)
{
APPRETERROR
(
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
AV
(
*
Start
++
);
LOG_TRACE_STREAM
<<
"Reading next value for sensor '"
<<
S
->
FullName
<<
"': "
<<
PRINTABLE
(
AV
)
<<
'\n'
;
return
AV
;
}
else
{
static
const
TT
AD
(
Default
);
LOG_TRACE_STREAM
<<
"Providing default value for sensor '"
<<
S
->
FullName
<<
"': "
<<
PRINTABLE
(
AD
)
<<
'\n'
;
return
AD
;
}
}));
}
else
{
ASSERT
(
false
&&
"Unexpected type argument"
);
}
return
ErrorCode
::
NoError
;
}
}
// End namespace app
}
// End namespace rosa
// Undef local macro if not used in the corresponding implementation.
#ifndef ROSA_LIB_APP_APPLICATION_CPP
#undef APPRETERROR
#endif
#endif
// ROSA_APP_APPLICATION_HPP
File Metadata
Details
Attached
Mime Type
text/x-c++
Expires
Sun, Apr 12, 11:42 AM (1 d, 20 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
287505
Default Alt Text
Application.hpp (37 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment