diff --git a/examples/deluxe-interface/deluxe-interface.cpp b/examples/deluxe-interface/deluxe-interface.cpp index 896f555..43222e4 100755 --- a/examples/deluxe-interface/deluxe-interface.cpp +++ b/examples/deluxe-interface/deluxe-interface.cpp @@ -1,191 +1,191 @@ //===-- examples/deluxe-interface/deluxe-interface.cpp ----------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file examples/deluxe-interface/deluxe-interface.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017 /// /// \brief A simple example on the \c rosa::deluxe::DeluxeContext and related /// classes. //===----------------------------------------------------------------------===// #include "rosa/config/version.h" #include "rosa/deluxe/DeluxeContext.hpp" #include #include #include using namespace rosa; using namespace rosa::deluxe; using namespace rosa::terminal; /// How many cycles of simulation to perform. const size_t NumberOfSimulationCycles = 16; /// Helper function creating a deluxe agent for logging and forwarding values. /// /// Received values are dumped to \c LOG_INFO_STREAM and then returned as /// result. /// /// \tparam T type of values to handle /// /// \param C the deluxe context to create the agent in /// \param Name name of the new agent /// /// \return handle for the new agent template AgentHandle createLowLevelAgent(std::unique_ptr &C, const std::string &Name) { using handler = DeluxeAgent::D; using result = Optional; return C->createAgent( Name, handler([&, Name](std::pair I) -> result { LOG_INFO_STREAM << "\n******\n" << Name << " " << (I.second ? "" : "") << " value: " << I.first << "\n******\n"; return {I.first}; })); } int main(void) { LOG_INFO_STREAM << '\n' << library_string() << " -- " << Color::Red << "deluxe-interface example" << Color::Default << '\n'; std::unique_ptr C = DeluxeContext::create("Deluxe"); // // Create deluxe sensors. // LOG_INFO("Creating sensors."); // All sensors are created without defining a normal generator function, but // with the default value of the second argument. That, however, requires the // data type to be explicitly defined. This is good for simulation only. AgentHandle IntSensor = C->createSensor("IntSensor"); AgentHandle FloatSensor = C->createSensor("FloatSensor"); // Check and set execution policy for sensors. LOG_INFO("Execution policies for sensors."); - LOG_INFO(C->getExecutionPolicy(IntSensor)->dump()); + LOG_INFO(std::to_string(*C->getExecutionPolicy(IntSensor))); C->setExecutionPolicy(IntSensor, DeluxeExecutionPolicy::decimation(2)); C->setExecutionPolicy(FloatSensor, DeluxeExecutionPolicy::decimation(2)); - LOG_INFO(C->getExecutionPolicy(IntSensor)->dump()); + LOG_INFO(std::to_string(*C->getExecutionPolicy(IntSensor))); // // Create low-level deluxe agents with \c createLowLevelAgent. // LOG_INFO("Creating low-level agents."); AgentHandle IntAgent = createLowLevelAgent(C, "IntAgent"); AgentHandle FloatAgent = createLowLevelAgent(C, "FloatAgent"); // Set execution policies for low-level agents. LOG_INFO("Setting Execution policies for low-level agents."); C->setExecutionPolicy(IntAgent, DeluxeExecutionPolicy::awaitAll({0})); C->setExecutionPolicy(FloatAgent, DeluxeExecutionPolicy::awaitAll({0})); // // Connect sensors to low-level agents. // LOG_INFO("Connect sensors to their corresponding low-level agents."); C->connectSensor(IntAgent, 0, IntSensor, "Int Sensor Channel"); C->connectSensor(FloatAgent, 0, FloatSensor, "Float Sensor Channel"); // // Create a high-level deluxe agent. // LOG_INFO("Create high-level agent."); // The new agent logs its input values and results in the the sum of them. AgentHandle SumAgent = C->createAgent( "Sum Agent", DeluxeAgent::D( [](std::pair I1, std::pair I2) -> Optional { LOG_INFO_STREAM << "\n*******\nSum Agent triggered with values:\n" << (I1.second ? "" : "") << " int value: " << I1.first << "\n" << (I2.second ? "" : "") << " float value: " << I2.first << "\n******\n"; return {I1.first + I2.first}; })); // // Connect low-level agents to the high-level agent. // LOG_INFO("Connect low-level agents to the high-level agent."); C->connectAgents(SumAgent, 0, IntAgent, "Int Agent Channel"); C->connectAgents(SumAgent, 1, FloatAgent, "Float Agent Channel"); // // For simulation output, create a logger agent writing the output of the // high-level agent into a log stream. // LOG_INFO("Create a logger agent."); // The agent logs each new input value and produces nothing. AgentHandle LoggerAgent = C->createAgent("Logger Agent", DeluxeAgent::D( [](std::pair Sum) -> Optional { if (Sum.second) { LOG_INFO_STREAM << "Result: " << Sum.first << "\n"; } return {}; })); // // Connect the high-level agent to the logger agent. // LOG_INFO("Connect the high-level agent to the logger agent."); C->connectAgents(LoggerAgent, 0, SumAgent, "Sum Agent Channel"); // // Do simulation. // LOG_INFO("Setting up and performing simulation."); // // Initialize deluxe context for simulation. // C->initializeSimulation(); // // Create some vectors and register them for their corresponding sensors. // std::vector IntValues(NumberOfSimulationCycles); std::generate(IntValues.begin(), IntValues.end(), [i = 0](void) mutable { return ++i; }); C->registerSensorValues(IntSensor, IntValues.begin(), IntValues.end()); std::vector FloatValues(NumberOfSimulationCycles); std::generate(FloatValues.begin(), FloatValues.end(), [f = 0.5f](void) mutable { f += 0.3f; return std::floor(f) + 0.5f; }); C->registerSensorValues(FloatSensor, FloatValues.begin(), FloatValues.end()); // // Simulate. // C->simulate(NumberOfSimulationCycles); return 0; } diff --git a/include/rosa/deluxe/DeluxeExecutionPolicy.h b/include/rosa/deluxe/DeluxeExecutionPolicy.h index ffbe353..6daa713 100644 --- a/include/rosa/deluxe/DeluxeExecutionPolicy.h +++ b/include/rosa/deluxe/DeluxeExecutionPolicy.h @@ -1,175 +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 /// 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; /// 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/lib/deluxe/DeluxeAgent.cpp b/lib/deluxe/DeluxeAgent.cpp index 3728913..0096b02 100755 --- a/lib/deluxe/DeluxeAgent.cpp +++ b/lib/deluxe/DeluxeAgent.cpp @@ -1,233 +1,238 @@ //===-- deluxe/DeluxeAgent.cpp ----------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file deluxe/DeluxeAgent.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017-2019 /// /// \brief Implementation of rosa/deluxe/DeluxeAgent.hpp. /// //===----------------------------------------------------------------------===// #include "rosa/deluxe/DeluxeAgent.hpp" #include "rosa/deluxe/DeluxeSystem.hpp" #include namespace rosa { namespace deluxe { bool DeluxeAgent::inv(void) const noexcept { // Check execution policy. // \note The \c rosa::System the \c rosa::Unit is created with is a // \c rosa::DeluxeSystem. const DeluxeSystem &DS = static_cast(Unit::system()); if (!ExecutionPolicy || !ExecutionPolicy->canHandle(Self, DS)) { return false; } // Check container sizes. if (!(InputTypes.size() == NumberOfInputs && InputChanged.size() == NumberOfInputs && InputValues->size() == NumberOfInputs && Slaves.size() == NumberOfInputs)) { return false; } // Check *slave* types and validate *slave* registrations and reverse lookup // information. std::map RefIds; // Build up a reference of SlaveIds in this. for (size_t I = 0; I < NumberOfInputs; ++I) { // First, validate input types at position \c I. const TypeNumber T = InputTypes[I]; if (InputValues->typeAt(I) != T) { return false; } // Check the registered *slave* at position \c I. const auto &Slave = Slaves[I]; // If \c Slave is empty, nothing to check. if (!Slave) continue; // \c Slave is not empty here. // Check the `OutputType` of the registered *slave*. const auto &A = unwrapAgent(*Slave); if (!((A.Kind == atoms::SensorKind && static_cast(A).OutputType == T) || (A.Kind == atoms::AgentKind && static_cast(A).OutputType == T))) { return false; } // Validate that the *slave* is not registered more than once. if (std::any_of( Slaves.begin() + I + 1, Slaves.end(), [&Slave](const Optional &O) { return O && *Slave == *O; })) { return false; } // Build the content of \c RefIds. RefIds.emplace(A.Id, I); } // Validate *slave* reverse lookup information against our reference. if (RefIds != SlaveIds) { return false; } // All checks were successful, the invariant is held. return true; } DeluxeAgent::~DeluxeAgent(void) noexcept { ASSERT(inv()); LOG_TRACE("Destroying DeluxeAgent..."); // Make sure \p this object is not a registered *slave*. if (Master) { ASSERT(unwrapAgent(*Master).Kind == atoms::AgentKind); // Sanity check. DeluxeAgent &M = static_cast(unwrapAgent(*Master)); ASSERT(M.positionOfSlave(self()) != M.NumberOfInputs); // Sanity check. M.registerSlave(M.positionOfSlave(self()), {}); Master = {}; } // Also, make sure \p this object is no acting *master*. for (size_t Pos = 0; Pos < NumberOfInputs; ++Pos) { registerSlave(Pos, {}); } // Now there is no connection with other entities, safe to destroy. } const DeluxeExecutionPolicy &DeluxeAgent::executionPolicy(void) const noexcept { ASSERT(inv()); return *ExecutionPolicy; } bool DeluxeAgent::setExecutionPolicy( std::unique_ptr &&EP) noexcept { ASSERT(inv()); + LOG_TRACE_STREAM << "DeluxeAgent " << FullName << " setting execution policy " + << *EP << std::endl; bool Success = false; // \note The \c rosa::System the \c rosa::Unit is created with is a // \c rosa::DeluxeSystem. const DeluxeSystem &DS = static_cast(Unit::system()); if (EP && EP->canHandle(self(), DS)) { ExecutionPolicy.swap(EP); Success = true; + } else { + LOG_TRACE_STREAM << "Execution policy " << *EP + << " cannot handle DeluxeAgent " << FullName << std::endl; } ASSERT(inv()); return Success; } Optional DeluxeAgent::master(void) const noexcept { ASSERT(inv()); return Master; } void DeluxeAgent::registerMaster(const Optional _Master) noexcept { ASSERT(inv() && (!_Master || unwrapAgent(*_Master).Kind == atoms::AgentKind)); Master = _Master; ASSERT(inv()); } TypeNumber DeluxeAgent::inputType(const size_t Pos) const noexcept { ASSERT(inv() && Pos < NumberOfInputs); return InputTypes[Pos]; } Optional DeluxeAgent::slave(const size_t Pos) const noexcept { ASSERT(inv() && Pos < NumberOfInputs); return Slaves[Pos]; } void DeluxeAgent::registerSlave(const size_t Pos, const Optional Slave) noexcept { ASSERT(inv() && Pos < NumberOfInputs && (!Slave || (unwrapAgent(*Slave).Kind == atoms::SensorKind && static_cast(unwrapAgent(*Slave)).OutputType == InputTypes[Pos]) || (unwrapAgent(*Slave).Kind == atoms::AgentKind && static_cast(unwrapAgent(*Slave)).OutputType == InputTypes[Pos]))); // If registering an actual *slave*, not just clearing the slot, make sure // the same *slave* is not registered to another slot. if (Slave) { auto It = SlaveIds.find(unwrapAgent(*Slave).Id); if (It != SlaveIds.end()) { Slaves[It->second] = {};//Optional(); SlaveIds.erase(It); } } // Obtain the place whose content is to be replaced with \p Slave auto &OldSlave = Slaves[Pos]; // If there is already a *slave* registered at \p Pos, clear reverse lookup // information for it, and make sure it no longer has \p this object as // *master*. if (OldSlave) { auto &A = unwrapAgent(*OldSlave); ASSERT(SlaveIds.find(A.Id) != SlaveIds.end()); // Sanity check. SlaveIds.erase(A.Id); if (A.Kind == atoms::AgentKind) { static_cast(A).registerMaster({}); } else { ASSERT(A.Kind == atoms::SensorKind); // Sanity check. static_cast(A).registerMaster({}); } } // Register \p Slave at \p Pos. OldSlave = Slave; // If registering an actual *slave*, not just clearing the slot, register // reverse lookup information for the new *slave*. if (Slave) { SlaveIds.emplace(unwrapAgent(*Slave).Id, Pos); } ASSERT(inv()); } size_t DeluxeAgent::positionOfSlave(const AgentHandle Slave) const noexcept { ASSERT(inv()); bool Found = false; size_t Pos = 0; while (!Found && Pos < NumberOfInputs) { auto &ExistingSlave = Slaves[Pos]; if (ExistingSlave && *ExistingSlave == Slave) { Found = true; } else { ++Pos; } } ASSERT(Found || Pos == NumberOfInputs); // Sanity check. return Pos; } void DeluxeAgent::handleTrigger(atoms::Trigger) noexcept { ASSERT(inv()); FP(); ASSERT(inv()); } } // End namespace deluxe } // End namespace rosa diff --git a/lib/deluxe/DeluxeExecutionPolicy.cpp b/lib/deluxe/DeluxeExecutionPolicy.cpp index ee59bcd..bbea1ea 100644 --- a/lib/deluxe/DeluxeExecutionPolicy.cpp +++ b/lib/deluxe/DeluxeExecutionPolicy.cpp @@ -1,53 +1,67 @@ //===-- deluxe/DeluxeExecutionPolicy.cpp ------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file deluxe/DeluxeExecutionPolicy.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2019 /// /// \brief Implementation for rosa/deluxe/DeluxeExecutionPolicy.h. /// //===----------------------------------------------------------------------===// #include "rosa/deluxe/DeluxeExecutionPolicy.h" #include "rosa/deluxe/DeluxeSystem.hpp" #include "executionpolicies/Decimation.h" #include "executionpolicies/AwaitAll.h" #include "executionpolicies/AwaitAny.h" namespace rosa { namespace deluxe { std::unique_ptr DeluxeExecutionPolicy::decimation(const size_t D) { return std::unique_ptr(new Decimation(D)); } std::unique_ptr DeluxeExecutionPolicy::awaitAll(const std::set &S) { return std::unique_ptr(new AwaitAll(S)); } std::unique_ptr DeluxeExecutionPolicy::awaitAny(const std::set &S) { return std::unique_ptr(new AwaitAny(S)); } bool DeluxeExecutionPolicy::isDeluxeAgent(const AgentHandle H, const DeluxeSystem &S) const noexcept { return S.isDeluxeAgent(H); } size_t DeluxeExecutionPolicy::numberOfDeluxeAgentInputs( const AgentHandle H, const DeluxeSystem &S) const noexcept { auto A = S.getDeluxeAgent(H); return A ? A->NumberOfInputs : 0; } } // End namespace deluxe } // End namespace rosa + +namespace std { + +string to_string(const rosa::deluxe::DeluxeExecutionPolicy &EP) { + return EP.dump(); +} + +ostream &operator<<(ostream &OS, + const rosa::deluxe::DeluxeExecutionPolicy &EP) { + OS << to_string(EP); + return OS; +} + +} // End namespace std diff --git a/lib/deluxe/DeluxeSensor.cpp b/lib/deluxe/DeluxeSensor.cpp index 0175cd5..c5269f7 100755 --- a/lib/deluxe/DeluxeSensor.cpp +++ b/lib/deluxe/DeluxeSensor.cpp @@ -1,108 +1,113 @@ //===-- deluxe/DeluxeSensor.cpp ---------------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file deluxe/DeluxeSensor.cpp /// /// \author David Juhasz (david.juhasz@tuwien.ac.at) /// /// \date 2017-2019 /// /// \brief Implementation of rosa/deluxe/DeluxeSensor.hpp. /// //===----------------------------------------------------------------------===// #include "rosa/deluxe/DeluxeSensor.hpp" #include "rosa/deluxe/DeluxeSystem.hpp" namespace rosa { namespace deluxe { bool DeluxeSensor::inv(void) const noexcept { // Check execution policy. // \note The \c rosa::System the \c rosa::Unit is created with is a // \c rosa::DeluxeSystem. const DeluxeSystem &DS = static_cast(Unit::system()); if (!ExecutionPolicy || !ExecutionPolicy->canHandle(Self, DS)) { return false; } // All checks were successful, the invariant is held. return true; } DeluxeSensor::~DeluxeSensor(void) noexcept { ASSERT(inv()); LOG_TRACE("Destroying DeluxeSensor..."); // Make sure \p this object is not a registered *slave*. if (Master) { ASSERT(unwrapAgent(*Master).Kind == atoms::AgentKind); // Sanity check. DeluxeAgent &M = static_cast(unwrapAgent(*Master)); ASSERT(M.positionOfSlave(self()) != M.NumberOfInputs); // Sanity check. M.registerSlave(M.positionOfSlave(self()), {}); Master = {}; } } const DeluxeExecutionPolicy &DeluxeSensor::executionPolicy(void) const noexcept { ASSERT(inv()); return *ExecutionPolicy; } bool DeluxeSensor::setExecutionPolicy( std::unique_ptr &&EP) noexcept { ASSERT(inv()); + LOG_TRACE_STREAM << "DeluxeSensor " << FullName + << " setting execution policy " << *EP << std::endl; bool Success = false; // \note The \c rosa::System the \c rosa::Unit is created with is a // \c rosa::DeluxeSystem. const DeluxeSystem &DS = static_cast(Unit::system()); if (EP && EP->canHandle(self(), DS)) { ExecutionPolicy.swap(EP); Success = true; + } else { + LOG_TRACE_STREAM << "Execution policy " << *EP + << " cannot handle DeluxeSensor " << FullName << std::endl; } ASSERT(inv()); return Success; } Optional DeluxeSensor::master(void) const noexcept { ASSERT(inv()); return Master; } void DeluxeSensor::registerMaster(const Optional _Master) noexcept { ASSERT(inv() && (!_Master || unwrapAgent(*_Master).Kind == atoms::AgentKind)); Master = _Master; ASSERT(inv()); } void DeluxeSensor::clearSimulationDataSource(void) noexcept { ASSERT(inv()); SFP = nullptr; ASSERT(inv()); } bool DeluxeSensor::simulationDataSourceIsSet(void) const noexcept { ASSERT(inv()); return SFP != nullptr; } void DeluxeSensor::handleTrigger(atoms::Trigger) noexcept { ASSERT(inv()); // Use \c rosa::deluxe::DeluxeSensor::SFP if set, otherwise // \c rosa::deluxe::DeluxeSensor::FP. const H &F = SFP ? SFP : FP; F(); ASSERT(inv()); } } // End namespace deluxe } // End namespace rosa