Page MenuHomePhorge

No OneTemporary

Size
57 KB
Referenced Files
None
Subscribers
None
diff --git a/include/rosa/deluxe/DeluxeAgent.hpp b/include/rosa/deluxe/DeluxeAgent.hpp
index aa3af06..48555ab 100755
--- a/include/rosa/deluxe/DeluxeAgent.hpp
+++ b/include/rosa/deluxe/DeluxeAgent.hpp
@@ -1,705 +1,705 @@
//===-- 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 "rosa/deluxe/DeluxeExecutionPolicy.h"
#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 There is a compatible *execution policy* set, 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;
/// The \c rosa::deluxe::DeluxeExecutionPolicy that controls the execution of
/// \c this object.
std::unique_ptr<DeluxeExecutionPolicy> ExecutionPolicy;
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;
/// Returns the current execution policy of \p this object.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The returned reference is valid only as long as \c
/// rosa::deluxe::DeluxeAgent::setExecutionPolicy() is not called and \p this
/// object is not destroyed.
///
/// \return \c rosa::deluxe::DeluxeAgent::ExecutionPolicy
const DeluxeExecutionPolicy &executionPolicy(void) const noexcept;
/// Sets the current execution policy of \p this object to \p EP.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note \p EP is set only if it can handle \p this object.
///
/// \param EP the new execution policy for \p this object
///
/// \return if \p EP was successfully set for \p this object.
bool setExecutionPolicy(std::unique_ptr<DeluxeExecutionPolicy> &&EP) 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 {
// Call the processing function only if \p ExecutionPolicy allows.
- if (ExecutionPolicy->doExecute(InputChanged)) {
+ if (ExecutionPolicy->shouldProcess(InputChanged)) {
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)),
ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)),
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));
}
ASSERT(inv());
}
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
diff --git a/include/rosa/deluxe/DeluxeExecutionPolicy.h b/include/rosa/deluxe/DeluxeExecutionPolicy.h
index 6daa713..caaad92 100644
--- a/include/rosa/deluxe/DeluxeExecutionPolicy.h
+++ b/include/rosa/deluxe/DeluxeExecutionPolicy.h
@@ -1,195 +1,195 @@
//===-- rosa/deluxe/DeluxeExecutionPolicy.h ---------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeExecutionPolicy.h
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Public interface of *execution policies* in the *deluxe interface*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXEEXECUTIONPOLICY_H
#define ROSA_DELUXE_DELUXEEXECUTIONPOLICY_H
#include "rosa/core/AgentHandle.hpp"
#include <memory>
#include <ostream>
#include <set>
#include <vector>
namespace rosa {
namespace deluxe {
// Forward declaration of DeluxeSystem. Do not include the corresponding header
// in this file because of cyclic dependency.
class DeluxeSystem;
/// *Execution policy* that controls how *agents* and *sensors* call their
/// processing functions.
///
/// An *execution policy* can be applied to a deluxe *unit* only if \c
/// deluxe::rosa::DeluxeExecutionPolicy::canHandle() allows it. Each deluxe
/// *unit* must have a compatible *execution policy* associated to it, and the
-/// *unit* queries \c rosa::deluxe::DeluxeExecutionPolicy::doExecute() on each
+/// *unit* queries \c rosa::deluxe::DeluxeExecutionPolicy::shouldProcess() on each
/// triggering and calls its processing funtion only if it is allowed by the
/// *execution policy*.
///
/// \see rosa::deluxe::DeluxeExecutionPolicy::decimation()
/// \see rosa::deluxe::DeluxeExecutionPolicy::awaitAll()
/// \see rosa::deluxe::DeluxeExecutionPolicy::awaitAny()
///
/// \todo Extend the interface with query functions about what kind of
/// execution policy is behind the interface. This can be done in relation
/// to the existing factory functions; for example, if the actual object is
/// decimation and with what rate.
class DeluxeExecutionPolicy {
protected:
/// Protected constructor, only implementations can instantiate the class.
DeluxeExecutionPolicy(void) noexcept = default;
private:
/// No instance can be copy-constructed, move-constructed, copied, and moved.
///
///@{
DeluxeExecutionPolicy(const DeluxeExecutionPolicy &) = delete;
DeluxeExecutionPolicy(DeluxeExecutionPolicy &&) = delete;
DeluxeExecutionPolicy &operator=(const DeluxeExecutionPolicy &) = delete;
DeluxeExecutionPolicy &operator=(DeluxeExecutionPolicy &&) = delete;
///@}
public:
/// Virtual destructor for subclasses.
virtual ~DeluxeExecutionPolicy(void) noexcept = default;
/// Creates an *execution policy* that allows execution with decimation of
/// triggering.
///
//// *Decimation* can handle both *agents* and *sensors*.
/// Processing functions are executed only on every \p D <sup>th</sup>
/// triggering. In the case of *sensors* in simulation, the simulation data
/// source is read on each triggering as it provides values with respect to
/// the highest execution frequency, but output is generated by the *sensor*
/// only on every \p D <sup>th</sup> triggering.
///
/// \note A rate of \c 0 is allowed as actual argument and is treated as rate
/// \c 1 (i.e., execute processing functions on each triggering).
///
/// \param D the rate of *decimation*
///
/// \return an *execution policy* implementing *decimation* with rate \p D
static std::unique_ptr<DeluxeExecutionPolicy> decimation(const size_t D);
/// Creates an *execution policy* that allows execution only if all defined
/// *slave* positions has new input.
///
/// *Await all* can handle only *agents* and only if the particular *agent*
/// has at least as many *slave* positions as the largest position defined in
/// \p S. Processing functions are executed only if new input has been
/// received for all defined *slave* positions.
///
/// \param S set of *slave* positions to await input from
///
/// \return an *execution policy* implementing *awaiting all* input from set
/// \p S
static std::unique_ptr<DeluxeExecutionPolicy>
awaitAll(const std::set<size_t> &S);
/// Creates an *execution policy* that allows execution if any of the defined
/// *slave* positions has new input.
///
/// *Await any* can handle only *agents* and only if the particular *agent*
/// has at least as many *slave* positions as the largest position defined in
/// \p S. Processing functions are executed if new input has been received for
/// any of the defined *slave* positions.
///
/// \param S set of *slave* positions to await input from
///
/// \return an *execution policy* implementing *awaiting any* input from set
/// \p S
static std::unique_ptr<DeluxeExecutionPolicy>
awaitAny(const std::set<size_t> &S);
/// Tells if \p this object can handle the deluxe *unit* referred by \p H.
///
/// The *execution policy* implemented by \p this object is applicable to the
/// given deluxe *unit* referred by \p H only if the function returns \c true.
///
/// \param H reference to the *unit* to check
/// \param S the system owning the *unit* referred by \p H
///
/// \return if \p this object can handle the *unit* referred by \p H
virtual bool canHandle(const AgentHandle H, const DeluxeSystem &S) const
noexcept = 0;
/// Tells if processing function should be executed on the current triggering.
///
/// The function is to be called on each triggering of the deluxe *unit*.
/// Decision about execution of processing function is done by \p this object
/// according to the implemented *execution policy*.
///
/// \param InputChanged flags indicating whether new input has been received
/// at *slave* positions
///
/// \return if to execute processing function
- virtual bool doExecute(const std::vector<bool> &InputChanged) noexcept = 0;
+ virtual bool shouldProcess(const std::vector<bool> &InputChanged) noexcept = 0;
/// Dumps \p this object into textual representation.
///
/// \return textual representation of \p this object
virtual std::string dump(void) const noexcept = 0;
protected:
/// Tells whether the *unit* referred by \p H is a \c
/// rosa::deluxe::DeluxeAgent.
///
/// \param H reference to the *unit* to check
/// \param S the system owning the *unit* referred by \p H
///
/// \return if the *unit* referred by \p H is a \c rosa::deluxe::DeluxeAgent
bool isDeluxeAgent(const AgentHandle H, const DeluxeSystem &S) const noexcept;
/// Tells the number of inputs handled by the *unit* referred by \p H.
///
/// If \p H refers to a \c rosa::deluxe::DeluxeAgent, the function returns the
/// number of inputs (i.e., *slave* positions) of the *agent*. Otherwise, the
/// function returns \c 0.
///
/// \param H reference to the *unit* to check
/// \param S the system owning the *unit* referred by \p H
///
/// \return the number of inputs handled by the *unit* referred by \p H
size_t numberOfDeluxeAgentInputs(const AgentHandle H,
const DeluxeSystem &S) const noexcept;
};
} // End namespace deluxe
} // End namespace rosa
namespace std {
/// Converts a \c rosa::deluxe::DeluxeExecutionPolicy into \c std::string.
///
/// \param EP \c rosa::deluxe::DeluxeExecutionPolicy to convert
///
/// \return \c std::string representing \p EP
string to_string(const rosa::deluxe::DeluxeExecutionPolicy &EP);
/// Dumps a \c rosa::deluxe::DeluxeExecutionPolicy to a given \c std::ostream.
///
/// \param [in,out] OS output stream to dump to
/// \param EP \c rosa::deluxe::DeluxeExecutionPolicy to dump
///
/// \return \p OS after dumping \p EP to it
ostream &operator<<(ostream &OS, const rosa::deluxe::DeluxeExecutionPolicy &EP);
} // End namespace std
#endif // ROSA_DELUXE_DELUXEEXECUTIONPOLICY_H
diff --git a/include/rosa/deluxe/DeluxeSensor.hpp b/include/rosa/deluxe/DeluxeSensor.hpp
index bdac895..55e766c 100755
--- a/include/rosa/deluxe/DeluxeSensor.hpp
+++ b/include/rosa/deluxe/DeluxeSensor.hpp
@@ -1,315 +1,315 @@
//===-- rosa/deluxe/DeluxeSensor.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeSensor.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Specialization of \c rosa::Agent for *sensor* role of the the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXESENSOR_HPP
#define ROSA_DELUXE_DELUXESENSOR_HPP
#include "rosa/core/Agent.hpp"
#include "rosa/deluxe/DeluxeAtoms.hpp"
#include "rosa/deluxe/DeluxeExecutionPolicy.h"
namespace rosa {
namespace deluxe {
/// Specialization of \c rosa::Agent for *sensor* role of the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
/// \invariant There is a compatible *execution policy* set
///
/// \see Definition of \c rosa::deluxe::DeluxeSensor::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 DeluxeSensor : public Agent {
/// Checks whether \p this object holds the class invariant.
///
/// \see Invariant of the class \c rosa::deluxe::DeluxeSensor
///
/// \return if \p this object holds the class invariant
bool inv(void) const noexcept;
/// The \c rosa::deluxe::DeluxeExecutionPolicy that controls the execution of
/// \c this object.
std::unique_ptr<DeluxeExecutionPolicy> ExecutionPolicy;
public:
/// Template alias for function objects used as data source for
/// \c rosa::deluxe::DeluxeSensor.
///
/// \note The function used for \c D is to be \c noexcept.
///
/// \tparam T type of data provided by the function
template <typename T> using D = std::function<T(void)>;
/// 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::DeluxeSensor::master
const TypeNumber OutputType;
private:
/// Alias for function objects used as trigger handler for
/// \c rosa::deluxe::DeluxeSensor.
///
/// \note The function used for \c H is to be \c noexcept.
///
/// \see \c DeluxeSensorTriggerHandlers
using H = std::function<void(void)>;
/// \defgroup DeluxeSensorTriggerHandlers Trigger handlers of rosa::deluxe::DeluxeSensor
///
/// \brief Trigger handler functions of \c rosa::deluxe::DeluxeSensor
///
/// The actual data source functions are captured in a lambda expression that
/// is in turn wrapped in a \c std::function object. The lambda expression
/// calls the data source function to obtain the next sensory value and sends
/// it to *master* by calling \c rosa::deluxe::DeluxeSensor::sendToMaster. The
/// function \c rosa::deluxe::DeluxeSensor::handleTrigger needs only to call
/// the proper function object.
/// Handles trigger during normal execution.
///
/// \ingroup DeluxeSensorTriggerHandlers
///
/// The function is used during normal execution. During simulation, the
/// simulation environment sets \c rosa::deluxe::DeluxeSensor::SFP, which is
/// used instead of \c rosa::deluxe::DeluxeSensor::FP.
const H FP;
/// Handles trigger during simulation.
///
/// \ingroup DeluxeSensorTriggerHandlers
///
/// The function is empty by default. The simulation environment sets it to be
/// used during simulation.
H SFP;
/// The *master* to send values to.
///
/// \note *Masters* are set dynamically, hence it is possible that a
/// \c rosa::deluxe::DeluxeSensor instance does not have any *master* at a
/// given moment.
Optional<AgentHandle> Master;
/// Wraps a data source function into a trigger handler.
///
/// \see \c DeluxeSensorTriggerHandlers
///
/// \tparam T type of data provided by \p F
///
/// \param F function to generate value with
/// \param inSimulation if F is a data source for Simulation
///
/// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template <typename T>
H triggerHandlerFromDataSource(D<T> &&F, bool inSimulation) 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 data to operate on
///
/// \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 generate the next value with during normal operation
///
/// \pre Statically, \p T is a built-in type:\code
/// TypeListContains<BuiltinTypes, T>::Value
/// \endcode
/// Dynamically, the instance is created as of kind
/// \c rosa::deluxe::atoms::SensorKind:
/// \code
/// Kind == rosa::deluxe::atoms::SensorKind
/// \endcode
template <typename T, typename = std::enable_if_t<
TypeListContains<BuiltinTypes, T>::Value>>
DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name,
MessagingSystem &S, D<T> &&F) noexcept;
/// Destroys \p this object.
~DeluxeSensor(void) noexcept;
/// Returns the current execution policy of \p this object.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note The returned reference is valid only as long as \c
/// rosa::deluxe::DeluxeSensor::setExecutionPolicy() is not called and \p this
/// object is not destroyed.
///
/// \return \c rosa::deluxe::DeluxeSensor::ExecutionPolicy
const DeluxeExecutionPolicy &executionPolicy(void) const noexcept;
/// Sets the current execution policy of \p this object to \p EP.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy
///
/// \note \p EP is set only if it can handle \p this object.
///
/// \param EP the new execution policy for \p this object
///
/// \return if \p EP was successfully set for \p this object.
bool setExecutionPolicy(std::unique_ptr<DeluxeExecutionPolicy> &&EP) noexcept;
/// The *master* of \p this object, if any.
///
/// \see \c rosa::deluxe::DeluxeSensor::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;
/// Clears the simulation trigger handler of \p this object.
///
/// The function assigns \c rosa::deluxe::DeluxeSensor::SFP with \c nullptr.
void clearSimulationDataSource(void) noexcept;
/// Tells whether a simulation trigger handler is set for \p this object.
///
/// The function returns whether \c rosa::deluxe::DeluxeSensor::SFP is not
/// \c nullptr.
///
/// \return if a simulation trigger handler is set for \p this object.
bool simulationDataSourceIsSet(void) const noexcept;
/// Registers a simulation data source for \p this object.
///
/// A new simulation trigger handler wrapping \p SF is stored in
/// \c rosa::deluxe::DeluxeSensor::SFP by overwriting any already registered
/// simulation data source.
///
/// \todo Enforce SF does not potentially throw exception.
///
/// \tparam T type of data provided by \p SF
///
/// \param SF function to generate value with
///
/// \pre \p T matches \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template <typename T> void registerSimulationDataSource(D<T> &&SF) noexcept;
private:
/// Sends a value to the *master* of \p this object.
///
/// \p Value is getting sent to \c rosa::deluxe::DeluxeSensor::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::DeluxeSensor::OutputType: \code
/// OutputType == TypeNumberOf<T>::Value
/// \endcode
template <typename T> void sendToMaster(const T &Value) noexcept;
/// Generates the next sensory value upon trigger from the system.
///
/// Executes \c rosa::deluxe::DeluxeSensor::FP or
/// \c rosa::deluxe::DeluxeSensor::SFP if set.
///
/// \note The only argument is a \c rosa::AtomConstant, hence its actual
/// value is ignored.
void handleTrigger(atoms::Trigger) noexcept;
};
template <typename T>
DeluxeSensor::H
DeluxeSensor::triggerHandlerFromDataSource(D<T> &&F,
bool inSimulation) noexcept {
ASSERT(OutputType == TypeNumberOf<T>::Value);
return [ this, F, inSimulation ](void) noexcept {
// Get value and send it to master only if \p ExecutionPolicy allows it.
- if (ExecutionPolicy->doExecute({})) {
+ if (ExecutionPolicy->shouldProcess({})) {
sendToMaster(F());
} else if (inSimulation) {
// But read input value in Simulation anyway as input values are provided
// for the highest execution frequency for simulation
F();
}
};
}
template <typename T, typename>
DeluxeSensor::DeluxeSensor(const AtomValue Kind, const id_t Id,
const std::string &Name, MessagingSystem &S,
D<T> &&F) noexcept
: Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger)),
ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)),
OutputType(TypeNumberOf<T>::Value),
FP(triggerHandlerFromDataSource(std::move(F), false)), SFP(nullptr) {
ASSERT(Kind == atoms::SensorKind);
LOG_TRACE("DeluxeSensor is created.");
ASSERT(inv());
}
template <typename T>
void DeluxeSensor::registerSimulationDataSource(D<T> &&SF) noexcept {
ASSERT(inv() && OutputType == TypeNumberOf<T>::Value);
SFP = triggerHandlerFromDataSource(std::move(SF), true);
ASSERT(inv());
}
template <typename T>
void DeluxeSensor::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));
}
ASSERT(inv());
}
} // End namespace deluxe
} // End namespace rosa
#endif // ROSA_DELUXE_DELUXESENSOR_HPP
diff --git a/lib/deluxe/executionpolicies/AwaitBase.cpp b/lib/deluxe/executionpolicies/AwaitBase.cpp
index 65a858e..d4ec684 100644
--- a/lib/deluxe/executionpolicies/AwaitBase.cpp
+++ b/lib/deluxe/executionpolicies/AwaitBase.cpp
@@ -1,60 +1,60 @@
//===-- deluxe/executionpolicies/AwaitBase.cpp ------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file deluxe/executionpolicies/AwaitBase.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Implementation for deluxe/executionpolicies/AwaitBase.h.
///
//===----------------------------------------------------------------------===//
#include "AwaitBase.h"
#include "rosa/support/debug.hpp"
#include <algorithm>
#include <sstream>
namespace rosa {
namespace deluxe {
AwaitBase::AwaitBase(const std::set<size_t> &S, CheckerType &&Checker)
: Set(S), Checker(Checker) {}
bool AwaitBase::canHandle(const AgentHandle H, const DeluxeSystem &S) const
noexcept {
return isDeluxeAgent(H, S) &&
canHandleNumberOfInputs(numberOfDeluxeAgentInputs(H, S));
}
-bool AwaitBase::doExecute(const std::vector<bool> &InputChanged) noexcept {
+bool AwaitBase::shouldProcess(const std::vector<bool> &InputChanged) noexcept {
// Sanity check of usage.
ASSERT(canHandleNumberOfInputs(InputChanged.size()));
return Checker(Set.begin(), Set.end(),
[&InputChanged](const size_t I) { return InputChanged[I]; });
}
bool AwaitBase::canHandleNumberOfInputs(const size_t NumberOfInputs) const
noexcept {
const auto MaxElemIt = std::max_element(Set.begin(), Set.end());
const size_t MaxElem = (MaxElemIt == Set.end()) ? 0 : *MaxElemIt;
return MaxElem <= NumberOfInputs;
}
std::string AwaitBase::dumpS(void) const noexcept {
std::stringstream SS;
SS << "[";
for (const auto &Value : Set) {
SS << " " << Value;
}
SS << " ]";
return SS.str();
}
} // End namespace deluxe
} // End namespace rosa
diff --git a/lib/deluxe/executionpolicies/AwaitBase.h b/lib/deluxe/executionpolicies/AwaitBase.h
index 9e5fdbb..e196701 100644
--- a/lib/deluxe/executionpolicies/AwaitBase.h
+++ b/lib/deluxe/executionpolicies/AwaitBase.h
@@ -1,105 +1,105 @@
//===-- deluxe/executionpolicies/AwaitBase.h --------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file deluxe/executionpolicies/AwaitBase.h
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Declaration of an *execution policy* that makes decisions depending
/// on input state of *slave* positions.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITBASE_H
#define ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITBASE_H
#include "rosa/deluxe/DeluxeExecutionPolicy.h"
#include <functional>
namespace rosa {
namespace deluxe {
/// Implementation of an *execution policy* that makes decisions depending on
/// whether new input has been received at some *slave* positions since the
/// laste triggering.
///
/// The class implements the \c rosa::deluxe::DeluxeExecutionPolicy interface
/// but delegates the defintion of the actual decision-making function to
/// subclasses.
///
/// \see rosa::deluxe::AwaitAll
/// \see rosa::deluxe::AwaitAny
class AwaitBase : public DeluxeExecutionPolicy {
protected:
/// Set of *slave* positions to check.
const std::set<size_t> Set;
/// Type of decision-making function used in \c
- /// rosa::deluxe::AwaitBase::doExecute().
+ /// rosa::deluxe::AwaitBase::shouldProcess().
using CheckerType = std::function<bool(std::set<size_t>::const_iterator,
std::set<size_t>::const_iterator,
std::function<bool(const size_t)>)>;
- // Decision-making function for \c rosa::deluxe::AwaitBase::doExecute().
+ // Decision-making function for \c rosa::deluxe::AwaitBase::shouldProcess().
const CheckerType Checker;
/// Protected constructor, only subclasses can instatiate the class.
///
/// \param S set of *slave* positions to await input from
/// \param Checker function that decides about execution
AwaitBase(const std::set<size_t> &S, CheckerType &&Checker);
public:
/// Tells if \p this object can handle the deluxe *unit* referred by \p H.
///
/// Any *execution policy* based on this class can handle *agents* with at
/// least as many *slave* positions as the largest one defined in \c
/// rosa::deluxe::AwaitBase::Set.
///
/// \param H reference to the *unit* to check
/// \param S the system owning the *unit* referred by \p H
///
/// \return if \p this object can handle the *unit* referred by \p H
bool canHandle(const AgentHandle H, const DeluxeSystem &S) const
noexcept override;
/// Tells if processing function should be executed on the current triggering.
///
/// Waiting for input allows execution when \c
/// rosa::deluxe::AwaitBase::Checker evaluates to \c true with respect to \c
/// rosa::deluxe::AwaitBase::Set and \p InputChanged.
///
/// \param InputChanged flags indicating whether new input has been received
/// at *slave* positions
///
/// \return if to execute processing function
- bool doExecute(const std::vector<bool> &InputChanged) noexcept override;
+ bool shouldProcess(const std::vector<bool> &InputChanged) noexcept override;
private:
/// Tells if \p this object can handle a *unit* with \p NumberOfInputs *slave*
/// positions.
///
/// \param NumberOfInputs the number of *slave* positions to consider
///
/// \return if \p this object can handle a *unit* with \p NumberOfInputs
/// *slave* positions
bool canHandleNumberOfInputs(const size_t NumberOfInputs) const noexcept;
protected:
/// Dumps the set of *slave* positions that \p this object checks.
///
/// \return textual representation of \c rosa::deluxe::AwaitBase::Set of \p
/// this object
std::string dumpS(void) const noexcept;
};
} // End namespace deluxe
} // End namespace rosa
#endif // ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITBASE_H
diff --git a/lib/deluxe/executionpolicies/Decimation.cpp b/lib/deluxe/executionpolicies/Decimation.cpp
index 676cd1e..2f324f9 100644
--- a/lib/deluxe/executionpolicies/Decimation.cpp
+++ b/lib/deluxe/executionpolicies/Decimation.cpp
@@ -1,41 +1,41 @@
//===-- deluxe/executionpolicies/Decimation.cpp -----------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file deluxe/executionpolicies/Decimation.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Implementation for deluxe/executionpolicies/Decimation.h.
///
//===----------------------------------------------------------------------===//
#include "Decimation.h"
#include <algorithm>
namespace rosa {
namespace deluxe {
Decimation::Decimation(const size_t D)
: Rate(std::max<size_t>(D, 1)), Cycle(0) {}
bool Decimation::canHandle(const AgentHandle, const DeluxeSystem &) const
noexcept {
return true;
}
-bool Decimation::doExecute(const std::vector<bool> &) noexcept {
+bool Decimation::shouldProcess(const std::vector<bool> &) noexcept {
return (Cycle++ % Rate) == 0;
}
std::string Decimation::dump(void) const noexcept {
return "Decimation with rate " + std::to_string(Rate);
}
} // End namespace deluxe
} // End namespace rosa
diff --git a/lib/deluxe/executionpolicies/Decimation.h b/lib/deluxe/executionpolicies/Decimation.h
index 8818524..b4d826c 100644
--- a/lib/deluxe/executionpolicies/Decimation.h
+++ b/lib/deluxe/executionpolicies/Decimation.h
@@ -1,73 +1,73 @@
//===-- deluxe/executionpolicies/Decimation.h -------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file deluxe/executionpolicies/Decimation.h
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2019
///
/// \brief Declaration of the *execution policy* *decimation*.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_LIB_DELUXE_EXECUTIONPOLICIES_DECIMATION_H
#define ROSA_LIB_DELUXE_EXECUTIONPOLICIES_DECIMATION_H
#include "rosa/deluxe/DeluxeExecutionPolicy.h"
namespace rosa {
namespace deluxe {
/// Implementation of the *execution policy* *decimation*.
///
/// \see \c rosa::deluxe::DeluxeExecutionPolicy::decimation()
class Decimation : public DeluxeExecutionPolicy {
/// The rate of *decimation*.
const size_t Rate;
/// Counter of triggerings.
size_t Cycle;
public:
/// Constructor.
///
/// \param D the rate of *decimation*
Decimation(const size_t D);
/// Tells if \p this object can handle the deluxe *unit* referred by \p H.
///
/// *Decimation* can handle any *units*.
///
/// \param H reference to the *unit* to check
/// \param S the system owning the *unit* referred by \p H
///
/// \return if \p this object can handle the *unit* referred by \p H
bool canHandle(const AgentHandle H, const DeluxeSystem &S) const
noexcept override;
/// Tells if processing function should be executed on the current triggering.
///
/// *Decimation* allows execution on each \c rosa::deluxe::Decimation::Rate
/// <sup>th</sup> triggering (i.e., calling of the function), which is counted
/// by \p this object in \c rosa::deluxe::Decimation::Cycle.
///
/// \param InputChanged *ignored*
///
/// \return if to execute processing function
- bool doExecute(const std::vector<bool> &InputChanged) noexcept override;
+ bool shouldProcess(const std::vector<bool> &InputChanged) noexcept override;
/// Dumps \p this object into textual representation.
///
/// \return textual representation of \p this object
std::string dump(void) const noexcept override;
};
} // End namespace deluxe
} // End namespace rosa
#endif // ROSA_LIB_DELUXE_EXECUTIONPOLICIES_DECIMATION_H

File Metadata

Mime Type
text/x-diff
Expires
Fri, Mar 14, 11:56 PM (13 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
129044
Default Alt Text
(57 KB)

Event Timeline