Page MenuHomePhorge

No OneTemporary

Size
57 KB
Referenced Files
None
Subscribers
None
diff --git a/include/rosa/deluxe/DeluxeContext.hpp b/include/rosa/deluxe/DeluxeContext.hpp
index bb91eeb..9363c41 100644
--- a/include/rosa/deluxe/DeluxeContext.hpp
+++ b/include/rosa/deluxe/DeluxeContext.hpp
@@ -1,985 +1,935 @@
//===-- rosa/deluxe/DeluxeContext.hpp ---------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeContext.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Public interface for the *deluxe interface* for working with agent
/// systems.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXECONTEXT_HPP
#define ROSA_DELUXE_DELUXECONTEXT_HPP
#include "rosa/deluxe/DeluxeSystem.hpp"
#include "rosa/support/types.hpp"
#include <iterator>
#include <memory>
#include <set>
/// Local helper macro to log and return a
/// \c rosa::deluxe::DeluxeContext::ErrorCode value.
///
/// Creates a debug message with the stringified value and returns the value.
///
/// \param Err \c rosa::deluxe::DeluxeContext::ErrorCode value to log and
/// return
#define DCRETERROR(Err) \
{ \
LOG_DEBUG(#Err); \
return Err; \
}
namespace rosa {
namespace deluxe {
/// Defines the *deluxe interface*.
///
/// \todo The classes \c rosa::deluxe::DeluxeSensor and \c
/// rosa::deluxe::DeluxeAgent share some common features in relation to their
/// *slave* role in the *deluxe interface*. But their definitions are completely
/// independent. It could be investigated how to lift their common parts into a
/// new *deluxe slave* class, which would serve as base for both, to avoid code
/// duplication.
class DeluxeContext {
/// A system owned by \p this object.
///
/// \note The reference is kept in a \c std::shared_ptr because of the member
/// function \c rosa::deluxe::DeluxeContext::getSystem.
std::shared_ptr<DeluxeSystem> System;
/// References to all *sensors* and *agents* created by \p this object.
std::set<AgentHandle> DeluxeUnits;
public:
/// Errors that may be resulted by some of the member functions of the class.
enum struct ErrorCode {
NoError,
TypeMismatch,
NotSensor,
NotAgent,
NotUnit,
WrongPosition,
AlreadyHasSlave,
AlreadyHasMaster,
AlreadyHasValueStream,
UnsuitableExecutionPolicy
};
/// Returns a new instance of \c rosa::deluxe::DeluxeContext.
///
/// \param Name name of the underlying \c rosa::DeluxeSystem
///
/// \return \c std::unique_ptr for the new instance of
/// \c rosa::deluxe::DeluxeContext with a new, empty \c rosa::DeluxeSystem
static std::unique_ptr<DeluxeContext>
create(const std::string &Name) noexcept;
private:
/// Creates a new instance.
///
/// \note Private constructor restricts instantiation to member functions of
/// the class.
///
/// \param Name name of the underlying \c rosa::MessagingSystem
DeluxeContext(const std::string &Name) noexcept;
public:
/// Destroys \p this object.
~DeluxeContext(void) noexcept;
/// Returns a reference for the underlying \c rosa::MessagingSystem.
///
/// \note One cannot do much with a \c rosa::MessagingSystem currently, this
/// is for future use.
///
/// \return reference for the underlying \c rosa::MessagingSystem.
std::weak_ptr<MessagingSystem> getSystem(void) const noexcept;
private:
/// Creates a new *sensor* in the context of \p this object.
///
/// The new *sensor* handles master-input by \p MF.
///
/// \tparam MT type of master-input the new *sensor* handles
/// \tparam T type of data the new *sensor* operates on
///
/// \note Instantiation fails if any of the type arguments \p MT and \p T
/// is not an instance of \c rosa::deluxe::DeluxeTuple or \p T is \c
/// rosa::deluxe::EmptyDeluxeTuple.
///
/// \param Name name of the new *sensor*
/// \param MF function for the new *sensors* to process master-input
/// values with
/// \param F function for the new *sensor* to generate the next value with
/// during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to
/// register an alternative simulation data source with \c
/// rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \see \c rosa::deluxe::DeluxeSensor::DeluxeSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename MT, typename T,
typename =
std::enable_if<TypeListAllDeluxeTuple<TypeList<MT, T>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value>>
AgentHandle createSensorImpl(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept;
public:
/// Creates a new *sensor* in the context of \p this object.
///
/// The new *sensor* does not receive master-input.
///
/// \tparam T type of data the new *sensor* operates on
///
/// \note Instantiation fails if type argument \p T is neither a built-in type
/// nor an instance of \c rosa::deluxe::DeluxeTuple with at least one element.
///
/// \param Name name of the new *sensor*
/// \param F function for the new *sensor* to generate the next value with
/// during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to register
/// an alternative simulation data source with
/// \c rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \see \c rosa::deluxe::DeluxeSensor::DeluxeSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename T, typename = std::enable_if_t<
TypeListContains<BuiltinTypes, T>::Value ||
(IsDeluxeTuple<T>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value)>>
AgentHandle createSensor(
const std::string &Name,
std::function<T(void)> &&F = [](void) { return T(); }) noexcept;
/// Creates a new *sensor* in the context of \p this object.
///
/// The new *sensor* handles master-input by \p MF.
///
/// \tparam MT type of master-input the new *sensor* handles
/// \tparam T type of data the new *sensor* operates on
///
/// \note The type arguments \p MT and \p T must be either all built-in types
/// or all instances of \c rosa::deluxe::DeluxeTuple. Moreover, \p T cannot be
/// \c rosa::deluxe::EmptyDeluxeTuple. Instantiation fails if these conditions
/// do not hold.
///
/// \param Name name of the new *sensor*
/// \param MF function for the new *sensors* to process master-input
/// values with \param F function for the new *sensor* to generate
/// the next value with during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to
/// register an alternative simulation data source with \c
/// rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \see \c rosa::deluxe::DeluxeSensor::DeluxeSensor.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename MT, typename T,
typename = std::enable_if<
TypeListSubsetOf<TypeList<MT, T>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<MT, T>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value)>>
AgentHandle createSensor(
const std::string &Name, std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F = [](void) { return T(); }) noexcept;
private:
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* receives master-input by \p MF and produces
/// master-output.
///
/// \tparam MT type of master-input the new *agent* handles
/// \tparam T type of data the new *agent* outputs
/// \tparam Ts types of master-output the new *agent* produces
/// \tparam As types of inputs the new *agent* takes
///
/// \note Instantiation fails if any of the type arguments \p MT, \p T, \p
/// Ts..., and \p As... is not an instance of \c rosa::deluxe::DeluxeTuple or
/// any of \p T and \p As... is \c rosa::deluxe::EmptyDeluxeTuple.
///
/// \param Name name of the new *agent*
/// \param MF function for the new *agent* to process master-input
/// values with \param F function for the new *agent* to process
/// input values and generate output with
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <typename MT, typename T, typename... Ts, typename... As,
typename = std::enable_if_t<
TypeListAllDeluxeTuple<TypeList<MT, T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value))>>
AgentHandle createAgentImpl(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept;
public:
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* neither receives master-input nor produces
/// master-output.
///
/// \tparam T type of data the new *agent* outputs
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p T and \p As... must be either all built-in
/// types or all instances of \c rosa::deluxe::DeluxeTuple. Moreover, none of
/// them can be \c rosa::deluxe::EmptyDeluxeTuple. Instantiation fails if
/// these conditions do not hold.
///
/// \param Name name of the new *agent*
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename T, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle
createAgent(const std::string &Name,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* receives master-input by \p MF but does not
/// produce master-output.
///
/// \tparam MT type of master-input the new *agent* handles
/// \tparam T type of data the new *agent* outputs
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p MT, \p T, and \p As... must be either all
/// built-in types or all instances of \c rosa::deluxe::DeluxeTuple. Moreover,
/// none of \p T and \p As... can be \c rosa::deluxe::EmptyDeluxeTuple.
/// Instantiation fails if these conditions do not hold.
///
/// \param Name name of the new *agent*
/// \param MF function for the new *agent* to process master-input
/// values with
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename MT, typename T, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<MT, T, As...>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<MT, T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle
createAgent(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* does not receive master-input but produces
/// master-output.
///
/// \tparam T type of data the new *agent* outputs
/// \tparam Ts types of master-output the new *agent* produces
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p T, \p Ts, and \p As... must be either all
/// built-in types or all instances of \c rosa::deluxe::DeluxeTuple. Moreover,
/// none of \p T and \p As... can be \c rosa::deluxe::EmptyDeluxeTuple.
/// Instantiation fails if these conditions do not hold.
///
/// \param Name name of the new *agent*
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \note \p F does not produce master-output for a given position if the
/// corresponding type is \c rosa::deluxe::EmptyDeluxeTuple. It is not
/// possible to disable master-output at any position by using built-in types.
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename T, typename... Ts, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<T, Ts..., As...>, BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle
createAgent(const std::string &Name,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// The new *agent* receives master-input by \p MF and produces
/// master-output.
///
/// \tparam MT type of master-input the new *agent* handles
/// \tparam T type of data the new *agent* outputs
/// \tparam Ts types of master-output the new *agent* produces
/// \tparam As types of inputs the new *agent* takes
///
/// \note The type arguments \p MT, \p T, \p Ts, and \p As... must be either
/// all built-in types or all instances of \c rosa::deluxe::DeluxeTuple.
/// Moreover, none of \p T and \p As... can be \c
/// rosa::deluxe::EmptyDeluxeTuple. Instantiation fails if these conditions
/// do not hold.
///
/// \param Name name of the new *agent*
/// \param MF function for the new *agent* to process master-input
/// values with
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \note \p F does not produce master-output for a given position if the
/// corresponding type is \c rosa::deluxe::EmptyDeluxeTuple. It is not
/// possible to disable master-output at any position by using built-in types.
///
/// \see \c rosa::deluxe::DeluxeAgent::DeluxeAgent.
///
/// \return \c rosa::AgentHandle for the new *agent*
template <
typename MT, typename T, typename... Ts, typename... As,
typename = std::enable_if_t<
TypeListSubsetOf<TypeList<MT, T, Ts..., As...>,
BuiltinTypes>::Value ||
(TypeListAllDeluxeTuple<TypeList<MT, T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... && (!std::is_same<As, EmptyDeluxeTuple>::value)))>>
AgentHandle createAgent(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept;
/// Returns the current execution policy of the referred \p Unit
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The referred \p Unit is either *sensor* or *agent*.
///
/// \note The returned reference is valid only as long as \c
/// rosa::deluxe::DeluxeContext::setExecutionPolicy() is not called with the
/// *unit* referred by \p Unit and the *unit* is not destroyed.
///
/// \param Unit the *unit* whose execution policy is to be obtained
///
/// \return the \c rosa::deluxe::DeluxeExecutionPolicy from \p Unit if \p Unit
/// is valid
Optional<const DeluxeExecutionPolicy &>
getExecutionPolicy(AgentHandle Unit) const noexcept;
/// Sets the current execution policy of the referred \p Unit to \p
/// ExecutionPolicy.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The referred \p Unit is either *sensor* or *agent*.
///
/// \param Unit the *unit* whose execution policy is to be set
/// \param ExecutionPolicy the new execution policy for \p Unit
///
/// \return how successful setting \p ExecutionPolicy for \p Unit was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotUnit` | Referred \p Unit is not valid
/// `UnsuitableExecutionPolicy` | \p ExecutionPolicy cannot handle \p Unit
ErrorCode setExecutionPolicy(
AgentHandle Unit,
std::unique_ptr<DeluxeExecutionPolicy> &&ExecutionPolicy) noexcept;
/// Connects a *sensor* to an *agent* in the context of \p this object.
///
/// \param Agent the *agent* to connect to
/// \param Pos the index of slot of \p Agent to connect \p Sensor to
/// \param Sensor the *sensor* to connect
/// \param Description optional textual description of the connection
///
/// \return how successfull connecting \p Sensor to \p Agent at slot
/// index \p Pos was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Agent is not \c rosa::deluxe::DeluxeAgent
/// `NotSensor` | Referred \p Sensor is not \c rosa::deluxe::DeluxeSensor
/// `WrongPosition` | \p Pos is not a valid input position of \p Agent
/// `TypeMismatch` | Expected input type at position \p Pos of \p Agent is other thanthe output type of \p Sensor or expected master-input of \p Sensor is other than master-output at position \p Pos of \p Agent if any
/// `AlreadyHasSlave` | \p Agent at position \p Pos already has a *slave* registered
/// `AlreadyHasMaster` | \p Sensor already has a *master* registered
ErrorCode connectSensor(AgentHandle Agent, const size_t Pos,
AgentHandle Sensor,
const std::string &Description = "") noexcept;
/// Connectes two *agents* in the context of \p this object.
///
/// \param Master the *agent* to connect to
/// \param Pos the index of slot of \p Master to connect \p Slave to
/// \param Slave the *agent* to connect
/// \param Description optional textual description of the connection
///
/// \return how succesfull connecting \p Slave to \p Master at slot
/// index \p Pos was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Master or \p Slave is not \c rosa::deluxe::DeluxeAgent
/// `WrongPosition` | \p Pos is not a valid input position of \p Master
/// `TypeMismatch` | Expected input type at position \p Pos of \p Master is other than the output type of \p Slave or expected master-input of \p Slave is other than master-output at position \p Pos of \p Master if any
/// `AlreadyHasSlave` | \p Master at position \p Pos already has a *slave* registered
/// `AlreadyHasMaster` | \p Slave already has a *master* registered
ErrorCode connectAgents(AgentHandle Master, const size_t Pos,
AgentHandle Slave,
const std::string &Description = "") noexcept;
/// Initializes \c this object and others managed by \p this object
/// for setting up and performing simulation.
///
/// \see \c rosa::deluxe::DeluxeContext::registerSensorValues,
/// \c rosa::deluxe::DeluxeContext::simulate
///
/// Need to clear simulation data sources from all the *sensors*.
void initializeSimulation(void) noexcept;
public:
/// Registers a stream providing values for a *sensor* during
/// simulation.
///
/// \tparam Iterator type of iterator providing values for \p Sensor
- /// \tparam T type of values \p Sensor is operating on, always use
- /// default!
+ /// \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 an instance of \c rosa::deluxe::DeluxeTuple with at least one element.
+ /// nor a tuple (i.e., can be converted to \c rosa::deluxe::DeluxeTuple).
///
/// \param Sensor the *sensor* to register values for
/// \param Start provides values for \p Sensor
/// \param End denotes the end of stream of values
/// \param Default value to be used when input stream is depleted
/// during simulation
///
/// \return how successful registering \p Source for \p Sensor
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
- /// `TypeMismatch` | \p Sensor generates values of a type other than
- /// \p T `NotSensor` | Referred \p Sensor is not \c
- /// rosa::deluxe::DeluxeSensor `AlreadyHasValueStream` | \p Sensor already has
- /// simulation data source set
- template <
- typename Iterator, typename T = typename Iterator::value_type,
- typename = std::enable_if_t<TypeListContains<BuiltinTypes, T>::Value ||
- (IsDeluxeTuple<T>::Value &&
- !std::is_same<T, EmptyDeluxeTuple>::value)>>
+ /// `TypeMismatch` | \p T does not match the type of values
+ /// generated by \p Sensor
+ /// `NotSensor` | Referred \p Sensor is not \c
+ /// rosa::deluxe::DeluxeSensor
+ /// `AlreadyHasValueStream` | \p Sensor already has simulation data source set
+ template <typename Iterator, typename T = typename Iterator::value_type,
+ typename = std::enable_if_t<
+ TypeListContains<BuiltinTypes, T>::Value || IsTuple<T>::Value>>
ErrorCode registerSensorValues(AgentHandle Sensor, Iterator &&Start,
const Iterator &End, T Default = {}) noexcept;
/// Performs the system contained by \p this object.
///
/// The function performs \p NumCycles cycle of simulation. In each
/// cycle, all the *agents* and *sensors* registered in \c
/// rosa::deluxe::DeluxeContext::DeluxeUnits are trigged for
/// execution.
///
/// \param NumCycles number of cycles to perform
///
/// \pre All the *sensors* in the system contained by \p this object
/// generate their output from simulation data sources.
void simulate(const size_t NumCycles) const noexcept;
};
/// Anonymous namespace with helper features for implementing
/// \c rosa::deluxe::DeluxeContext, consider it private.
namespace {
/// Maps any type \p T to \c rosa::deluxe::EmptyDeluxeTuple.
template <typename T> struct MapToEmptyDeluxeTuple {
using Type = EmptyDeluxeTuple;
};
/// Convenience template alias for \c MapToEmptyDeluxeTuple.
template <typename T>
using empty_deluxe_t = typename MapToEmptyDeluxeTuple<T>::Type;
/// Converts a \c std::tuple of \c rosa::Optional built-in types into a
/// corresponding \c std::tuple of \c rosa::Optional with each actual value
/// wrapped in \c rosa::deluxe::DeluxeTuple.
///
/// \tparam Ts types of the values
/// \tparam S0 indices for accessing values in \p Values
///
/// \param Values the \c std::tuple of \c rosa::Optional with built-in values
///
/// \note The second argument provides indices statically as template arguments
/// \p S0..., so its actual value is ignored.
///
/// \return a \c std::tuple of \c rosa::Optional corresponding to \p Values
/// with each actual value wrapped in \c rosa::deluxe::DeluxeTuple
///
/// \pre Statically, all type arguments \p Ts... are built-in types and the
/// provided indices \p S0... match the length of \p Ts...: \code
/// TypeListSubsetOf<TypeList<Ts...>, BuiltinTypes>::Value &&
/// sizeof...(Ts) == sizeof...(S0)
/// \endcode
template <typename... Ts, size_t... S0>
std::tuple<Optional<DeluxeTuple<Ts>>...>
wrapBuiltinInDeluxeTuple(const std::tuple<Optional<Ts>...> &Values,
Seq<S0...>) noexcept {
STATIC_ASSERT((TypeListSubsetOf<TypeList<Ts...>, BuiltinTypes>::Value),
"not built-in types");
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent type arguments");
return std::make_tuple(std::get<S0>(Values)
? Optional<DeluxeTuple<Ts>>(
make_deluxe_tuple<Ts>(*std::get<S0>(Values)))
: Optional<DeluxeTuple<Ts>>()...);
}
} // End namespace
template <typename MT, typename T, typename>
AgentHandle
DeluxeContext::createSensorImpl(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept {
AgentHandle H = System->createSensor(Name, std::move(MF), std::move(F));
DeluxeUnits.emplace(H);
return H;
}
template <typename T, typename>
AgentHandle DeluxeContext::createSensor(const std::string &Name,
std::function<T(void)> &&F) noexcept {
auto EmptyMF = std::function<void(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {});
if constexpr (TypeListContains<BuiltinTypes, T>::Value) {
using OutputType = DeluxeTuple<T>;
return createSensorImpl(
Name, std::move(EmptyMF),
std::function<OutputType(void)>(
[F{std::move(F)}](void) { return OutputType(F()); }));
} else if constexpr (IsDeluxeTuple<T>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value) {
return createSensorImpl(Name, std::move(EmptyMF), std::move(F));
} else {
ASSERT(false && "Unexpected type argument");
}
}
template <typename MT, typename T, typename>
AgentHandle
DeluxeContext::createSensor(const std::string &Name,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept {
if constexpr (TypeListSubsetOf<TypeList<MT, T>, BuiltinTypes>::Value) {
using MasterInputType = DeluxeTuple<MT>;
using OutputType = DeluxeTuple<T>;
return createSensorImpl(
Name,
std::function<void(std::pair<MasterInputType, bool>)>(
[MF{std::move(MF)}](std::pair<MasterInputType, bool> Arg) {
MF({std::get<0>(Arg.first), Arg.second});
}),
std::function<OutputType(void)>(
[F{std::move(F)}](void) { return OutputType(F()); }));
} else if constexpr (TypeListAllDeluxeTuple<TypeList<MT, T>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value) {
return createSensorImpl(Name, std::move(MF), std::move(F));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename MT, typename T, typename... Ts, typename... As, typename>
AgentHandle DeluxeContext::createAgentImpl(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept {
AgentHandle H = System->createAgent(Name, std::move(MF), std::move(F));
DeluxeUnits.emplace(H);
return H;
}
template <typename T, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept {
using NoMasterOutputType = std::tuple<Optional<empty_deluxe_t<As>>...>;
auto EmptyMF =
std::function<NoMasterOutputType(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {
return NoMasterOutputType();
});
if constexpr (TypeListSubsetOf<TypeList<T, As...>, BuiltinTypes>::Value) {
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name, std::move(EmptyMF),
std::function<
std::tuple<Optional<OutputType>, Optional<empty_deluxe_t<As>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return std::tuple_cat(
wrapBuiltinInDeluxeTuple(std::tuple(Result), seq_t<1>()),
NoMasterOutputType());
}));
} else if constexpr (TypeListAllDeluxeTuple<TypeList<T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
return createAgentImpl(
Name, std::move(EmptyMF),
std::function<std::tuple<Optional<T>, Optional<empty_deluxe_t<As>>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Result = F(Args...);
return std::tuple_cat(std::tuple(Result), NoMasterOutputType());
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename MT, typename T, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name, std::function<void(std::pair<MT, bool>)> &&MF,
std::function<Optional<T>(std::pair<As, bool>...)> &&F) noexcept {
using NoMasterOutputType = std::tuple<Optional<empty_deluxe_t<As>>...>;
if constexpr (TypeListSubsetOf<TypeList<MT, T, As...>, BuiltinTypes>::Value) {
using MasterInputType = DeluxeTuple<MT>;
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name,
std::function<NoMasterOutputType(std::pair<MasterInputType, bool>)>(
[MF{std::move(MF)}](std::pair<MasterInputType, bool> Arg) {
MF({std::get<0>(Arg.first), Arg.second});
return NoMasterOutputType();
}),
std::function<
std::tuple<Optional<OutputType>, Optional<empty_deluxe_t<As>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return std::tuple_cat(
wrapBuiltinInDeluxeTuple(std::tuple(Result), seq_t<1>()),
NoMasterOutputType());
}));
} else if constexpr (TypeListAllDeluxeTuple<TypeList<MT, T, As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
return createAgentImpl(
Name,
std::function<NoMasterOutputType(std::pair<MT, bool>)>(
[MF{std::move(MF)}](std::pair<MT, bool> Arg) {
MF(Arg);
return NoMasterOutputType();
}),
std::function<std::tuple<Optional<T>, Optional<empty_deluxe_t<As>>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Result = F(Args...);
return std::tuple_cat(std::tuple(Result), NoMasterOutputType());
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename T, typename... Ts, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept {
if constexpr (TypeListSubsetOf<TypeList<T, Ts..., As...>,
BuiltinTypes>::Value) {
using MasterOutputType = std::tuple<Optional<DeluxeTuple<Ts>>...>;
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {
return MasterOutputType();
}),
std::function<
std::tuple<Optional<OutputType>, Optional<DeluxeTuple<Ts>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return wrapBuiltinInDeluxeTuple(Result,
seq_t<1 + sizeof...(Ts)>());
}));
} else if constexpr (TypeListAllDeluxeTuple<
TypeList<T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
using MasterOutputType = std::tuple<Optional<Ts>...>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<EmptyDeluxeTuple, bool>)>(
[](std::pair<EmptyDeluxeTuple, bool>) {
return MasterOutputType();
}),
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Output = F(Args...);
return Output;
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename MT, typename T, typename... Ts, typename... As, typename>
AgentHandle DeluxeContext::createAgent(
const std::string &Name,
std::function<std::tuple<Optional<Ts>...>(std::pair<MT, bool>)> &&MF,
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)> &&F) noexcept {
if constexpr (TypeListSubsetOf<TypeList<MT, T, Ts..., As...>,
BuiltinTypes>::Value) {
using MasterInputType = DeluxeTuple<MT>;
using MasterOutputType = std::tuple<Optional<DeluxeTuple<Ts>>...>;
using OutputType = DeluxeTuple<T>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<MasterInputType, bool>)>(
[MF{std::move(MF)}](std::pair<MasterInputType, bool> Arg) {
const auto Result = MF({std::get<0>(Arg.first), Arg.second});
return wrapBuiltinInDeluxeTuple(Result, seq_t<sizeof...(Ts)>());
}),
std::function<
std::tuple<Optional<OutputType>, Optional<DeluxeTuple<Ts>>...>(
std::pair<DeluxeTuple<As>, bool>...)>(
[F{std::move(F)}](std::pair<DeluxeTuple<As>, bool>... Args) {
const auto Result = F({std::get<0>(Args.first), Args.second}...);
return wrapBuiltinInDeluxeTuple(Result,
seq_t<1 + sizeof...(Ts)>());
}));
} else if constexpr (TypeListAllDeluxeTuple<
TypeList<MT, T, Ts..., As...>>::Value &&
!std::is_same<T, EmptyDeluxeTuple>::value &&
(true && ... &&
(!std::is_same<As, EmptyDeluxeTuple>::value))) {
using MasterOutputType = std::tuple<Optional<Ts>...>;
return createAgentImpl(
Name,
std::function<MasterOutputType(std::pair<MT, bool>)>(
[MF{std::move(MF)}](std::pair<MT, bool> Arg) {
const auto Output = MF(Arg);
return Output;
}),
std::function<std::tuple<Optional<T>, Optional<Ts>...>(
std::pair<As, bool>...)>(
[F{std::move(F)}](std::pair<As, bool>... Args) {
const auto Output = F(Args...);
return Output;
}));
} else {
ASSERT(false && "Unexpected type arguments");
}
}
template <typename Iterator, typename T, typename>
DeluxeContext::ErrorCode
DeluxeContext::registerSensorValues(AgentHandle Sensor, Iterator &&Start,
const Iterator &End, T Default) noexcept {
// Get the type of values provided by \p Iterator.
STATIC_ASSERT((std::is_same<T, typename Iterator::value_type>::value),
"type mismatch");
- // \note This constexpr variable is defined in the lambda below for MSVC.
- // Keep that definition in sync with this one.
- constexpr bool isBuiltin = TypeListContains<BuiltinTypes, T>::Value;
- if constexpr (!isBuiltin) {
- // T must be a std::tuple.
- STATIC_ASSERT(std::tuple_size<T>::value == 1, "Wrong tuple type");
- STATIC_ASSERT(
- (TypeListContains<BuiltinTypes,
- typename std::tuple_element<0, T>::type>::Value),
- "Wrong element type in tuple");
- }
- using TT = sensor_t<T>;
// Make sure preconditions are met.
if (!System->isDeluxeSensor(Sensor)) {
DCRETERROR(ErrorCode::NotSensor);
}
auto S = System->getDeluxeSensor(Sensor);
ASSERT(S); // Sanity check.
-<<<<<<< HEAD
- if (S->OutputType != TypeNumberOf<TT>::Value) {
- DCRETERROR(ErrorCode::TypeMismatch);
- } else if (S->simulationDataSourceIsSet()) {
- DCRETERROR(ErrorCode::AlreadyHasValueStream);
- }
- // Register input stream.
- // \note Need to capture parameters by value so having local copies.
- S->registerSimulationDataSource(
- DeluxeSensor::D<TT>([=](void) mutable noexcept {
-#ifdef ROSA_WINDOWS
- // MSVC has problem propagating constexpr into the lambda; repeat it.
- // Keep this definition in sync with the original above.
- constexpr bool isBuiltin = TypeListContains<BuiltinTypes, T>::Value;
-#endif // defined ROSA_WINDOWS
- if (Start != End) {
- TT Value;
- if constexpr (isBuiltin) {
- Value = *Start;
- } else {
- Value = std::get<0>(*Start);
- }
- ++Start;
- LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
- << "': " << Value << '\n';
- return Value;
- } else {
- TT Value;
- if constexpr (isBuiltin) {
- Value = Default;
- } else {
- Value = std::get<0>(Default);
- }
- LOG_TRACE_STREAM << "Providing default value for sensor '"
- << S->FullName << "': " << Value << '\n';
- return Value;
- }
- }));
-=======
if (S->simulationDataSourceIsSet()) {
DCRETERROR(ErrorCode::AlreadyHasValueStream);
}
if constexpr (TypeListContains<BuiltinTypes, T>::Value) {
if (S->OutputType != TypeToken<T>::Value) {
DCRETERROR(ErrorCode::TypeMismatch);
}
// Register input stream.
// \note Need to capture parameters by value so having local copies.
S->registerSimulationDataSource(std::function<DeluxeTuple<T>(void)>([=
](void) mutable noexcept->DeluxeTuple<T> {
if (Start != End) {
LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
<< "': " << *Start << '\n';
return make_deluxe_tuple<T>(*Start++);
} else {
LOG_TRACE_STREAM << "Providing default value for sensor '"
<< S->FullName << "': " << Default << '\n';
return make_deluxe_tuple<T>(Default);
}
}));
- } else if constexpr (IsDeluxeTuple<T>::Value &&
- !std::is_same<T, EmptyDeluxeTuple>::value) {
- if (S->OutputType != T::TT) {
+ } else if constexpr (IsTuple<T>::Value) {
+
+ using TT = matching_deluxe_tuple_t<T>;
+ if (std::is_same<T, EmptyDeluxeTuple>::value || S->OutputType != TT::TT) {
DCRETERROR(ErrorCode::TypeMismatch);
}
// Register input stream.
// \note Need to capture parameters by value so having local copies.
S->registerSimulationDataSource(
- std::function<T(void)>([=](void) mutable noexcept->T {
+ std::function<TT(void)>([=](void) mutable noexcept->TT {
if (Start != End) {
+ const TT DV(*Start++);
LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
- << "': " << *Start << '\n';
- return *Start++;
+ << "': " << DV << '\n';
+ return DV;
} else {
+ static const TT DD(Default);
LOG_TRACE_STREAM << "Providing default value for sensor '"
- << S->FullName << "': " << Default << '\n';
- return Default;
+ << S->FullName << "': " << DD << '\n';
+ return DD;
}
}));
} else {
ASSERT(false && "Unexpected type argument");
}
->>>>>>> master
return ErrorCode::NoError;
}
} // End namespace deluxe
} // End namespace rosa
// Undef local macro if not used in the corresponding implementation.
#ifndef ROSA_LIB_DELUXE_DELUXECONTEXT_CPP
#undef DCRETERROR
#endif
#endif // ROSA_DELUXE_DELUXECONTEXT_HPP
diff --git a/include/rosa/deluxe/DeluxeTuple.hpp b/include/rosa/deluxe/DeluxeTuple.hpp
index e57d29b..9e26950 100644
--- a/include/rosa/deluxe/DeluxeTuple.hpp
+++ b/include/rosa/deluxe/DeluxeTuple.hpp
@@ -1,359 +1,465 @@
//===-- rosa/deluxe/DeluxeTuple.hpp -----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeTuple.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Facilities for handling multiple input/output values for connections
/// in the *deluxe interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXETUPLE_HPP
#define ROSA_DELUXE_DELUXETUPLE_HPP
#include "rosa/support/sequence.hpp"
#include "rosa/support/type_token.hpp"
#include <ostream>
#include <tuple>
namespace rosa {
namespace deluxe {
/// A tuple to manage multiple input/output values in the *deluxe interface*.
///
/// \tparam Ts types of elements of the tuple
///
/// \note The template may be instantiated only with built-in types and the
/// number of those type may not exceed the capacity of a \c rosa::Token.
template <typename... Ts>
struct DeluxeTuple : public std::tuple<Ts...> {
// Statically enforce that the class template is instantiated only with
// built-in types.
STATIC_ASSERT((TypeListSubsetOf<TypeList<Ts...>, BuiltinTypes>::Value),
"not built-in types");
// Statically enforce that the class template is instantiated with not too
// many types.
// \note Instantiation would fail on \c rosa::deluxe::DeluxeTuple::TT if there
// are too any types; this assertion is for more readable error reporting.
STATIC_ASSERT(sizeof...(Ts) <= token::MaxTokenizableListSize,
"Too many types");
/// How many elements the instance has.
static constexpr token_size_t Length = sizeof...(Ts);
/// What types the class contains.
///
/// Type information encoded as \c rosa::Token.
static constexpr Token TT = TypeToken<Ts...>::Value;
/// Default constructor, zero-initializes elements.
DeluxeTuple(void) = default;
/// Constructor, initializes the underlying \c std::tuple with lvalue
/// references.
///
/// \param Args value references to the values to store
DeluxeTuple(const std::decay_t<Ts> &... Args) : std::tuple<Ts...>(Args...) {}
/// Constructor, initializes the underlying \c std::tuple with rvalue
/// references.
///
/// \param Args rvalue references to the values to store
DeluxeTuple(std::decay_t<Ts> &&... Args)
: std::tuple<Ts...>(std::move(Args)...) {}
+ /// Contructor, initializes the underlying \c std::tuple from another matching
+ /// \c std::tuple.
+ DeluxeTuple(const std::tuple<Ts...> &Args) : std::tuple<Ts...>(Args) {}
+
/// Default copy-constructor.
DeluxeTuple(const DeluxeTuple &) = default;
/// Default move-constructor.
DeluxeTuple(DeluxeTuple &&) = default;
/// Default copy-assignment.
DeluxeTuple &operator=(const DeluxeTuple &) = default;
/// Default move-assignment.
DeluxeTuple &operator=(DeluxeTuple &&) = default;
private:
/// Dumps \p this object to a given \c std::ostream.
///
/// \note Provides implementation for \c rosa::deluxe::DeluxeTuple::dump.
///
/// \tparam S0 Indices for accessing elements.
///
/// \param [in,out] OS output stream to dump to
///
/// \note The second argument provides indices statically as template
/// arguments \p S0..., so its actual value is ignored.
///
/// \pre Statically, \p S0... matches number of types \p this object was
/// created: \code
/// sizeof...(S0) == sizeof...(Ts)
/// \endcode
template <size_t... S0>
void dump(std::ostream &OS, Seq<S0...>) const noexcept;
public:
/// Dumps \p this object to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
void dump(std::ostream &OS) const noexcept;
};
template <typename... Ts>
template <size_t... S0>
void DeluxeTuple<Ts...>::dump(std::ostream &OS, Seq<S0...>) const noexcept {
STATIC_ASSERT(sizeof...(S0) == sizeof...(Ts), "inconsistent type arguments");
// Convert value to std::string with std::to_string except for a value of
// std::string that does not need conversion.
auto dump_to_string = [](const auto &V) {
if constexpr (std::is_same<std::decay_t<decltype(V)>, std::string>::value) {
return V;
} else {
return std::to_string(V);
}
};
OS << "{";
(OS << ... << (" " + dump_to_string(std::get<S0>(*this))));
OS << " }";
}
template <typename... Ts>
void DeluxeTuple<Ts...>::dump(std::ostream &OS) const noexcept {
dump(OS, seq_t<sizeof...(Ts)>());
}
/// Type alias for a \c rosa::deluxe::DeluxeTuple that contains no elements.
using EmptyDeluxeTuple = DeluxeTuple<>;
/// Template specialization for \c rosa::deluxe::EmptyDeluxeTuple.
template <> struct DeluxeTuple<> : public std::tuple<> {
/// How many elements the instance has.
static constexpr token_size_t Length = 0;
/// What types the class contains.
///
/// Type information encoded as \c rosa::Token.
static constexpr Token TT = TypeToken<>::Value;
/// Constructor, initializes the underlying \c std::tuple.
DeluxeTuple(void) : std::tuple<>() {}
/// Default copy-constructor.
DeluxeTuple(const DeluxeTuple &) = default;
// Default move-constructor.
DeluxeTuple(DeluxeTuple &&) = default;
/// Default copy-assignment.
DeluxeTuple &operator=(const DeluxeTuple &) = default;
// Default move-assignment,
DeluxeTuple &operator=(DeluxeTuple &&) = default;
/// Dumps \p this object to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
static void dump(std::ostream &OS) noexcept;
};
/// Creates a \c rosa::deluxe::DeluxeTuple instance from the given lvalues
/// references.
///
/// \tparam Ts types of elements of the tuple
///
/// \see \c rosa::deluxe::DeluxeTuple
///
/// \param Args values to store in the tuple
///
/// \return an instance of \c rosa::deluxe::DeluxeTuple<Ts...> with \p Args as
/// elements
template <typename... Ts>
inline DeluxeTuple<Ts...> make_deluxe_tuple(const Ts &... Args) noexcept {
return DeluxeTuple<Ts...>(Args...);
}
/// Creates a \c rosa::deluxe::DeluxeTuple instance from the given rvalue
/// references.
///
/// \tparam Ts types of elements of the tuple
///
/// \see \c rosa::deluxe::DeluxeTuple
///
/// \param Args values to store in the tuple
///
/// \return an instance of \c rosa::deluxe::DeluxeTuple<Ts...> with \p Args as
/// elements
template <typename... Ts>
inline DeluxeTuple<Ts...> make_deluxe_tuple(Ts&&... Args) noexcept {
return DeluxeTuple<Ts...>(std::move(Args)...);
}
+/// Creates a \c rosa::deluxe::DeluxeTuple instance from the given \c std::tuple
+/// reference.
+///
+/// \tparam Ts types of elements of the tuple
+///
+/// \see \c rosa::deluxe::DeluxeTuple
+///
+/// \param Args values to store in the tuple
+///
+/// \return an instance of \c rosa::deluxe::DeluxeTuple<Ts...> with \p Args as
+/// elements
+template <typename... Ts>
+inline DeluxeTuple<Ts...>
+make_deluxe_tuple(const std::tuple<Ts...> &Args) noexcept {
+ return DeluxeTuple<Ts...>(Args);
+}
+
/// \defgroup UnwrapDeluxeTuple Implementation of
/// rosa::deluxe::UnwrapDeluxeTuple
///
/// \brief Unwraps element types from an instance of \c
/// rosa::deluxe::DeluxeTuple into a \c rosa::TypeList
///
/// Types can be unwrapped from a \c rosa::deluxe::DeluxeTuple instance as \code
/// typename UnwrapDeluxeTuple<List>::Type
/// \endcode
///
/// For example, the following expression evaluates to `true`: \code
/// std::is_same<typename UnwrapDeluxeTuple<DeluxeTuple<T1, T2>>::Type,
/// TypeList<T1, T2>>::value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam Tuple \c rosa::deluxe::DeluxeTuple to unwrap
template <typename Tuple> struct UnwrapDeluxeTuple;
/// Implementation of the template for \c rosa::deluxe::DeluxeTuple instances.
template <typename... Ts> struct UnwrapDeluxeTuple<DeluxeTuple<Ts...>> {
using Type = TypeList<Ts...>;
};
///@}
/// \defgroup TypeListUnwrapDeluxeTuple Implementation of
/// \c rosa::deluxe::TypeListUnwrapDeluxeTuple
///
/// \brief Unwraps element types from instances of \c
/// rosa::deluxe::DeluxeTuple in a \c rosa::TypeList.
///
/// Types can be unwrapped from \c rosa::deluxe::DeluxeTuple instances as \code
/// typename TypeListUnwrapDeluxeTuple<List>::Type
/// \endcode
///
/// For example, the following expression evaluates to `true`: \code
/// std::is_same<
/// typename TypeListUnwrapDeluxeTuple<TypeList<T0,
/// DeluxeTuple<T1, T2>,
/// T3>>::Type,
/// TypeList<T0, T1, T2, T3>
/// >::value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to check
template <typename List> struct TypeListUnwrapDeluxeTuple;
/// Specialization for \c rosa::EmptyTypeList.
template <> struct TypeListUnwrapDeluxeTuple<EmptyTypeList> {
using Type = EmptyTypeList;
};
/// Specialization for the case when the first type in \p List is an instance of
/// \c rosa::deluxe::DeluxeTuple.
template <typename... As, typename... Ts>
struct TypeListUnwrapDeluxeTuple<TypeList<DeluxeTuple<As...>, Ts...>> {
using Type = typename TypeListConcat<
typename UnwrapDeluxeTuple<DeluxeTuple<As...>>::Type,
typename TypeListUnwrapDeluxeTuple<TypeList<Ts...>>::Type>::Type;
};
/// Implementation for a general first type in \p List.
template <typename T, typename... Ts>
struct TypeListUnwrapDeluxeTuple<TypeList<T, Ts...>> {
using Type = typename TypeListPush<
T, typename TypeListUnwrapDeluxeTuple<TypeList<Ts...>>::Type>::Type;
};
///@}
+/// \defgroup IsTuple Implementation of \c rosa::deluxe::IsTuple
+///
+/// \brief Tells if a type is a tuple as in it can be converted to \c
+/// rosa::deluxe::DeluxeTuple.
+///
+/// \see \c rosa::deluxe::MatchingDeluxeTuple
+///
+/// Whether a type \c T is a tuple can be checked as \code
+/// IsTuple<T>::Value
+/// \endcode
+///@{
+
+/// Declaration of the template.
+///
+/// \tparam T type to check
+template <typename T> struct IsTuple;
+
+/// Specialization for the case when the type is an instance of \c std::tuple.
+template <typename... Ts> struct IsTuple<std::tuple<Ts...>> {
+ static constexpr bool Value = true;
+};
+
+/// Specialization for the case when the type is an instance of \c std::tuple.
+template <typename... Ts> struct IsTuple<DeluxeTuple<Ts...>> {
+ static constexpr bool Value = true;
+};
+
+/// Implementation for a general case of type \p T.
+template <typename T> struct IsTuple { static constexpr bool Value = false; };
+
+///@}
+
/// \defgroup IsDeluxeTuple Implementation of \c rosa::deluxe::IsDeluxeTuple
///
/// \brief Tells if a type is an instance of \c rosa::deluxe::DeluxeTuple.
///
/// Whether a type \c T is an instance of \c rosa::deluxe::DeluxeTuple can be
/// checked as \code
/// IsDeluxeTuple<T>::Value
/// \endcode
+///
+/// \note `!IsDeluxeTuple<T>::Value || IsTuple<T>::Value`
///@{
/// Declaration of the template.
///
/// \tparam T type to check
template <typename T> struct IsDeluxeTuple;
/// Specialization for the case when the type is an instance of \c
/// rosa::deluxe::DeluxeTuple.
template <typename... Ts>
struct IsDeluxeTuple<DeluxeTuple<Ts...>> {
static constexpr bool Value = true;
};
/// Implementation for a general case of type \p T.
template <typename T>
struct IsDeluxeTuple {
static constexpr bool Value = false;
};
///@}
+/// \defgroup MatchingDeluxeTuple Implementation of \c
+/// rosa::deluxe::MatchingDeluxeTuple
+///
+/// \brief Gives the \c rosa::deluxe::DeluxeTuple type that matches a given
+/// tuple type.
+///
+/// The matching \c rosa::deluxe::DeluxeTuple type for a tuple type \p T can be
+/// obtained as \code
+/// typename MatchingDeluxeTuple<T>::Type
+/// \endcode
+/// If \p T is \c rosa::deluxe::DeluxeTuple, the matching type is \p T itself.
+/// If \p T is \c std::tuple, the matching type if \c rosa::deluxe::DeluxeTuple
+/// with the same type parameters as \p T.
+/// \c rosa::deluxe::MatchingDeluxeTuple is not defined for other type
+/// parameters.
+///
+/// \note The template is defined for type \p T only if
+/// `rosa::deluxe::IsTuple<T>::Value`. Values of such types can be used to
+/// construct a new instance of the class \c rosa::deluxe::DeluxeTuple.
+///
+///\see \c rosa::deluxe::IsTuple
+///@{
+
+/// Declaration of the template.
+///
+/// \tparam T type to check
+template <typename T> struct MatchingDeluxeTuple;
+
+/// Specialization for the case when the type is an instance of \c
+/// rosa::deluxe::DeluxeTuple.
+template <typename... Ts> struct MatchingDeluxeTuple<DeluxeTuple<Ts...>> {
+ using Type = DeluxeTuple<Ts...>;
+};
+
+/// Specialization for the case when the type is an instance of \c
+/// std::tuple.
+template <typename... Ts> struct MatchingDeluxeTuple<std::tuple<Ts...>> {
+ using Type = DeluxeTuple<Ts...>;
+};
+
+///@}
+
+/// Convenience template type alias for easy use of \c
+/// rosa::deluxe::MatchingDeluxeTuple.
+///
+/// Converts a tuple type to the matching \c rosa::deluxe::DeluxeTuple type.
+///
+/// \tparam Tuple type to convert
+template <typename Tuple>
+using matching_deluxe_tuple_t = typename MatchingDeluxeTuple<Tuple>::Type;
+
/// \defgroup TypeListAllDeluxeTuple Implementation of
/// \c rosa::deluxe::TypeListAllDeluxeTuple
///
/// \brief Tells if all types in a \c rosa::TypeList is an instance of \c
/// rosa::deluxe::DeluxeTuple.
///
/// Whether a \c rosa::TypeList \c List contains instances of \c
/// rosa::deluxe::DeluxeTuple only can be checked as \code
/// TypeListAllDeluxeTuple<List>::Value
/// \endcode
///@{
/// Declaration of the template.
///
/// \tparam List \c rosa::TypeList to check
template <typename List> struct TypeListAllDeluxeTuple;
/// Specialization for \c rosa::EmptyTypeList.
template <> struct TypeListAllDeluxeTuple<EmptyTypeList> {
static constexpr bool Value = true;
};
/// Implementation for the general case when there is at leasst one element in
/// the list.
template <typename T, typename... Ts>
struct TypeListAllDeluxeTuple<TypeList<T, Ts...>> {
static constexpr bool Value =
IsDeluxeTuple<T>::Value && TypeListAllDeluxeTuple<TypeList<Ts...>>::Value;
};
///@}
} // End namespace deluxe
} // End namespace rosa
namespace std {
/// Dumps a \c rosa::deluxe::Deluxe instance to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param Tuple \c rosa::deluxe::Deluxe to dump
///
/// \return \p OS after dumping \p Tuple to it
template <typename... Ts>
ostream &operator<<(ostream &OS,
const rosa::deluxe::DeluxeTuple<Ts...> &Tuple) {
Tuple.dump(OS);
return OS;
}
} // End namespace std
#endif // ROSA_DELUXE_DELUXETUPLE_HPP

File Metadata

Mime Type
text/x-diff
Expires
Fri, Jul 4, 2:25 AM (2 h, 23 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157429
Default Alt Text
(57 KB)

Event Timeline