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 /// 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 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 using D = std::function(std::pair...)>; /// 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 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 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 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; /// 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 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> Slaves; /// Associates \c rosa::id_t values to corresponding indices of registered /// *slaves*. /// /// \see \c rosa::deluxe::DeluxeAgent::Slaves std::map 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 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() && sizeof...(As) == sizeof...(S0) /// \endcode template std::tuple...> prepareCurrentInputs(Seq) 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 static Optional invokeWithTuple(D F, std::tuple...> Args, Seq) 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::Value && inputTypesMatch() /// \endcode template H triggerHandlerFromProcessingFunction(D &&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, BuiltinTypes>::Value /// \endcode Dynamically, the instance is created as of kind /// \c rosa::deluxe::atoms::AgentKind: \code /// Kind == rosa::deluxe::atoms::AgentKind /// \endcode template , BuiltinTypes>::Value>> DeluxeAgent(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, D &&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 &&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 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 _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 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(unwrapAgent(*Slave)).OutputType == /// InputTypes[Pos]) || /// (unwrapAgent(*Slave).Kind == rosa::deluxe::atoms::AgentKind && /// static_cast(unwrapAgent(*Slave)).OutputType == /// InputTypes[Pos])) /// \endcode void registerSlave(const size_t Pos, const Optional 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::Value /// \endcode template 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::Value /// \endcode template 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::f(InputTypes, 0); /// \endcode /// /// \tparam As types to match template 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 struct InputTypesMatchImpl { /// 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 &InputTypes, size_t Pos) noexcept { return Pos < InputTypes.size() && TypeNumberOf::Value == InputTypes[Pos] && InputTypesMatchImpl::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 &InputTypes, size_t Pos) noexcept { return Pos == InputTypes.size(); } }; } // End namespace template bool DeluxeAgent::inputTypesMatch(void) const noexcept { return InputTypesMatchImpl::f(InputTypes, 0); } template std::tuple...> DeluxeAgent::prepareCurrentInputs(Seq) 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; ASSERT(inv() && (this->*MFP)() && sizeof...(As) == sizeof...(S0)); return std::make_tuple( std::make_pair(*static_cast(InputValues->pointerTo(S0)), InputChanged[S0])...); } template Optional DeluxeAgent::invokeWithTuple( D F, std::tuple...> Args, Seq) noexcept { ASSERT(sizeof...(As) == sizeof...(S0)); return F(std::get(Args)...); } template DeluxeAgent::H DeluxeAgent::triggerHandlerFromProcessingFunction(D &&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; ASSERT(OutputType == TypeNumberOf::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::Type; auto Args = prepareCurrentInputs(Indices()); std::fill(InputChanged.begin(), InputChanged.end(), false); Optional R = invokeWithTuple(F, Args, Indices()); if (R) { sendToMaster(*R); } } }; } template DeluxeAgent::DeluxeAgent(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, D &&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::Value), NumberOfInputs(sizeof...(As)), InputTypes({TypeNumberOf::Value...}), InputChanged(NumberOfInputs, false), InputValues(new TokenizedStorage()), FP(triggerHandlerFromProcessingFunction(std::move(F))), Slaves(NumberOfInputs) { ASSERT(Kind == atoms::AgentKind); LOG_TRACE("DeluxeAgent is created."); ASSERT(inv()); } template void DeluxeAgent::sendToMaster(const T &Value) noexcept { ASSERT(inv() && OutputType == TypeNumberOf::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 void DeluxeAgent::saveInput(id_t Id, T Value) noexcept { ASSERT(inv() && SlaveIds.find(Id) != SlaveIds.end() && InputTypes[SlaveIds.find(Id)->second] == TypeNumberOf::Value); size_t Pos = SlaveIds.at(Id); *static_cast(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 #include #include #include 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 th /// 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 th 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 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 awaitAll(const std::set &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 awaitAny(const std::set &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 &InputChanged) noexcept = 0; + virtual bool shouldProcess(const std::vector &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 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 using D = std::function; /// 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; /// \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 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::Value /// \endcode template H triggerHandlerFromDataSource(D &&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::Value /// \endcode /// Dynamically, the instance is created as of kind /// \c rosa::deluxe::atoms::SensorKind: /// \code /// Kind == rosa::deluxe::atoms::SensorKind /// \endcode template ::Value>> DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, D &&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 &&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 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 _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::Value /// \endcode template void registerSimulationDataSource(D &&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::Value /// \endcode template 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 DeluxeSensor::H DeluxeSensor::triggerHandlerFromDataSource(D &&F, bool inSimulation) noexcept { ASSERT(OutputType == TypeNumberOf::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 DeluxeSensor::DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name, MessagingSystem &S, D &&F) noexcept : Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger)), ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)), OutputType(TypeNumberOf::Value), FP(triggerHandlerFromDataSource(std::move(F), false)), SFP(nullptr) { ASSERT(Kind == atoms::SensorKind); LOG_TRACE("DeluxeSensor is created."); ASSERT(inv()); } template void DeluxeSensor::registerSimulationDataSource(D &&SF) noexcept { ASSERT(inv() && OutputType == TypeNumberOf::Value); SFP = triggerHandlerFromDataSource(std::move(SF), true); ASSERT(inv()); } template void DeluxeSensor::sendToMaster(const T &Value) noexcept { ASSERT(inv() && OutputType == TypeNumberOf::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 #include namespace rosa { namespace deluxe { AwaitBase::AwaitBase(const std::set &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 &InputChanged) noexcept { +bool AwaitBase::shouldProcess(const std::vector &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 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 Set; /// Type of decision-making function used in \c - /// rosa::deluxe::AwaitBase::doExecute(). + /// rosa::deluxe::AwaitBase::shouldProcess(). using CheckerType = std::function::const_iterator, std::set::const_iterator, std::function)>; - // 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 &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 &InputChanged) noexcept override; + bool shouldProcess(const std::vector &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 namespace rosa { namespace deluxe { Decimation::Decimation(const size_t D) : Rate(std::max(D, 1)), Cycle(0) {} bool Decimation::canHandle(const AgentHandle, const DeluxeSystem &) const noexcept { return true; } -bool Decimation::doExecute(const std::vector &) noexcept { +bool Decimation::shouldProcess(const std::vector &) 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 /// th 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 &InputChanged) noexcept override; + bool shouldProcess(const std::vector &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