Page MenuHomePhorge

No OneTemporary

Size
124 KB
Referenced Files
None
Subscribers
None
diff --git a/examples/agent-functionalities/agent-functionalities.cpp b/examples/agent-functionalities/agent-functionalities.cpp
index 8f111db..0766f28 100644
--- a/examples/agent-functionalities/agent-functionalities.cpp
+++ b/examples/agent-functionalities/agent-functionalities.cpp
@@ -1,211 +1,188 @@
//===-- examples/agent-functionalities/agent-functionalities.cpp *-- C++-*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file examples/agent-functionalities/agent-functionalities.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief A simple example on defining \c rosa::Agent instances using
/// \c rosa::agent::Functionality object as components.
///
//===----------------------------------------------------------------------===//
+// Make sure M_PI is available, needed for _WIN32
+#define _USE_MATH_DEFINES
+#include <cmath>
+
#include "rosa/agent/Abstraction.hpp"
#include "rosa/agent/Confidence.hpp"
#include "rosa/agent/FunctionAbstractions.hpp"
#include "rosa/agent/RangeConfidence.hpp"
#include "rosa/config/version.h"
#include "rosa/core/Agent.hpp"
#include "rosa/core/MessagingSystem.hpp"
#include "rosa/support/log.h"
#include "rosa/support/terminal_colors.h"
#include <vector>
using namespace rosa;
using namespace rosa::agent;
using namespace rosa::terminal;
+// We use pi as float rather than double, which M_PI is.
+constexpr float Pi = (float) M_PI;
+
/// A dummy wrapper for testing \c rosa::MessagingSystem.
///
/// \note Since we test \c rosa::MessagingSystem directly here, we need to get
/// access to its protected members. That we do by imitating to be a decent
/// subclass of \c rosa::MessagingSystem, while calling protected member
/// functions on an object of a type from which we actually don't inherit.
struct SystemTester : protected MessagingSystem {
template <typename T, typename... Funs>
static AgentHandle createMyAgent(MessagingSystem *S, const std::string &Name,
Funs &&... Fs) {
return ((SystemTester *)S)->createAgent<T>(Name, std::move(Fs)...);
}
static void destroyMyAgent(MessagingSystem *S, const AgentHandle &H) {
((SystemTester *)S)->destroyUnit(unwrapAgent(H));
}
};
/// A special \c rosa::Agent with its own state.
class MyAgent : public Agent {
public:
using Tick = AtomConstant<atom("tick")>;
private:
enum class Categories { Bad, Normal, Good };
static const std::map<Categories, const char *> CategoryNames;
StaticLengthHistory<uint8_t, 10, HistoryPolicy::FIFO> H;
Confidence<uint8_t> C;
RangeAbstraction<uint8_t, Categories> A;
PartialFunction<int, int> L;
RangeConfidence<float, Categories, float> RCL;
RangeConfidence<float, Categories, float> RCS;
public:
void handler(Tick, uint8_t V) noexcept {
// Record \p V to the \c rosa::agent::History, then print state info.
H << V;
ASSERT(H.entry() == V); // Sanity check.
LOG_INFO_STREAM << "\nNext value: " << PRINTABLE(V)
<< ", confidence: " << C(H)
<< ", category: " << CategoryNames.at(A(H.entry()))
<< ", partial: " << int(L(H.entry()))
<< ", range-confidence-linear: ";
std::map<Categories, float> ResLin = RCL(H.entry());
for (auto Con : ResLin) {
LOG_INFO_STREAM << " " << CategoryNames.at(Con.first) << " " << Con.second
<< ",";
}
LOG_INFO_STREAM << " range-confidence-sine: ";
std::map<Categories, float> ResSine = RCS(H.entry());
for (auto Con : ResSine) {
LOG_INFO_STREAM << " " << CategoryNames.at(Con.first) << " " << Con.second
<< ",";
}
LOG_INFO_STREAM << '\n';
}
MyAgent(const AtomValue Kind, const rosa::id_t Id, const std::string &Name,
MessagingSystem &S)
: Agent(Kind, Id, Name, S, THISMEMBER(handler)), H(), C(5, 20, 1),
A({{{(uint8_t)10, (uint8_t)14}, Categories::Normal},
{{(uint8_t)15, (uint8_t)17}, Categories::Good},
{{(uint8_t)18, (uint8_t)19}, Categories::Normal}},
Categories::Bad),
L({{{0, 2}, std::make_shared<LinearFunction<int, int>>(0, 1)},
{{2, 4}, std::make_shared<LinearFunction<int, int>>(2, 0)},
{{4, 6}, std::make_shared<LinearFunction<int, int>>(6, -1)}},
0),
- RCL({{Categories::Bad,
- PartialFunction<float, float>(
- {
- {{0, 3},
- std::make_shared<LinearFunction<float, float>>(0,
- 1.0 / 3)},
- {{3, 6},
- std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{6, 9},
- std::make_shared<LinearFunction<float, float>>(
- 3.0, -1.0 / 3)},
- },
- 0)},
- {Categories::Normal,
- PartialFunction<float, float>(
- {
- {{6, 9},
- std::make_shared<LinearFunction<float, float>>(-2,
- 1.0 / 3)},
- {{9, 12},
- std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{12, 15},
- std::make_shared<LinearFunction<float, float>>(
- 5, -1.0 / 3)},
- },
- 0)},
- {Categories::Good,
- PartialFunction<float, float>(
- {
- {{12, 15},
- std::make_shared<LinearFunction<float, float>>(-4,
- 1.0 / 3)},
- {{15, 18},
- std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{18, 21},
- std::make_shared<LinearFunction<float, float>>(
- 7, -1.0 / 3)},
- },
- 0)}}),
- RCS({{Categories::Bad,
- PartialFunction<float, float>(
- {
- {{0, 3},
- std::make_shared<SineFunction<float, float>>(
- M_PI / 3, 0.5, -M_PI / 2, 0.5)},
- {{3, 6},
- std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{6, 9},
- std::make_shared<SineFunction<float, float>>(
- M_PI / 3, 0.5, -M_PI / 2 + 3, 0.5)},
- },
- 0)},
- {Categories::Normal,
- PartialFunction<float, float>(
- {
- {{6, 9},
- std::make_shared<SineFunction<float, float>>(
- M_PI / 3, 0.5, -M_PI / 2, 0.5)},
- {{9, 12},
- std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{12, 15},
- std::make_shared<SineFunction<float, float>>(
- M_PI / 3, 0.5, -M_PI / 2 + 3, 0.5)},
- },
- 0)},
- {Categories::Good,
- PartialFunction<float, float>(
- {
- {{12, 15},
- std::make_shared<SineFunction<float, float>>(
- M_PI / 3, 0.5, -M_PI / 2, 0.5)},
- {{15, 18},
- std::make_shared<LinearFunction<float, float>>(1, 0)},
- {{18, 21},
- std::make_shared<SineFunction<float, float>>(
- M_PI / 3, 0.5, -M_PI / 2 + 3, 0.5)},
- },
- 0)}},
- true) {}
+ RCL({
+ {Categories::Bad, PartialFunction<float, float>({
+ {{0.f, 3.f}, std::make_shared<LinearFunction<float, float>>
+ (0.f, 1.f/3)},
+ {{3.f, 6.f}, std::make_shared<LinearFunction<float, float>>
+ (1.f, 0.f)},
+ {{6.f, 9.f}, std::make_shared<LinearFunction<float, float>>
+ (3.f, -1.f/3)},
+ },0)},
+ {Categories::Normal, PartialFunction<float, float>({
+ {{6.f, 9.f}, std::make_shared<LinearFunction<float, float>>
+ (-2.f, 1.f/3)},
+ {{9.f, 12.f}, std::make_shared<LinearFunction<float, float>>
+ (1.f, 0.f)},
+ {{12.f, 15.f}, std::make_shared<LinearFunction<float, float>>
+ (5.f, -1.f/3)},
+ },0)},
+ {Categories::Good, PartialFunction<float, float>({
+ {{12.f, 15.f}, std::make_shared<LinearFunction<float, float>>
+ (-4.f, 1.f/3)},
+ {{15.f, 18.f}, std::make_shared<LinearFunction<float, float>>
+ (1.f, 0.f)},
+ {{18.f, 21.f}, std::make_shared<LinearFunction<float, float>>
+ (7.f, -1.f/3)},
+ },0)}
+ }),
+ RCS({
+ {Categories::Bad, PartialFunction<float, float>({
+ {{0.f, 3.f}, std::make_shared<SineFunction<float, float>>
+ (Pi/3, 0.5f, -Pi/2, 0.5f)},
+ {{3.f, 6.f}, std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
+ {{6.f, 9.f}, std::make_shared<SineFunction<float, float>>
+ (Pi/3, 0.5f, -Pi/2 + 3, 0.5f)},
+ },0)},
+ {Categories::Normal, PartialFunction<float, float>({
+ {{6.f, 9.f}, std::make_shared<SineFunction<float, float>>
+ (Pi/3, 0.5f, -Pi/2, 0.5f)},
+ {{9.f, 12.f}, std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
+ {{12.f, 15.f}, std::make_shared<SineFunction<float, float>>
+ (Pi/3, 0.5f, -Pi/2 + 3, 0.5f)},
+ },0)},
+ {Categories::Good, PartialFunction<float, float>({
+ {{12.f, 15.f}, std::make_shared<SineFunction<float, float>>
+ (Pi/3, 0.5f, -Pi/2, 0.5f)},
+ {{15.f, 18.f}, std::make_shared<LinearFunction<float, float>>(1.f, 0.f)},
+ {{18.f, 21.f}, std::make_shared<SineFunction<float, float>>
+ (Pi/3, 0.5f, -Pi/2 + 3, 0.5f)},
+ },0)}
+ }, true){}
};
const std::map<MyAgent::Categories, const char *> MyAgent::CategoryNames{
{Categories::Bad, "Bad"},
{Categories::Normal, "Normal"},
{Categories::Good, "Good"}};
int main(void) {
LOG_INFO_STREAM << library_string() << " -- " << Color::Red
<< "agent-functionalities example" << Color::Default << '\n';
std::unique_ptr<MessagingSystem> S = MessagingSystem::createSystem("Sys");
MessagingSystem *SP = S.get();
AgentHandle A = SystemTester::createMyAgent<MyAgent>(SP, "MyAgent");
std::vector<uint8_t> Vs{0, 1, 2, 3, 4, 5, 6, 7, 9, 10,
11, 13, 15, 14, 15, 16, 19, 20, 21};
for (auto I = Vs.begin(); I != Vs.end(); ++I) {
A.send<MyAgent::Tick, uint8_t>(MyAgent::Tick::Value, *I);
}
SystemTester::destroyMyAgent(SP, A);
return 0;
}
diff --git a/examples/deluxe-interface/deluxe-interface.cpp b/examples/deluxe-interface/deluxe-interface.cpp
index d50396e..43222e4 100755
--- a/examples/deluxe-interface/deluxe-interface.cpp
+++ b/examples/deluxe-interface/deluxe-interface.cpp
@@ -1,177 +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 <algorithm>
#include <cmath>
#include <vector>
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 <typename T>
AgentHandle createLowLevelAgent(std::unique_ptr<DeluxeContext> &C,
const std::string &Name) {
using handler = DeluxeAgent::D<T, T>;
using result = Optional<T>;
return C->createAgent(
Name, handler([&, Name](std::pair<T, bool> I) -> result {
LOG_INFO_STREAM << "\n******\n"
<< Name << " " << (I.second ? "<New>" : "<Old>")
<< " 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<DeluxeContext> 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<int32_t>("IntSensor");
AgentHandle FloatSensor = C->createSensor<float>("FloatSensor");
+ // Check and set execution policy for sensors.
+ LOG_INFO("Execution policies for sensors.");
+
+ LOG_INFO(std::to_string(*C->getExecutionPolicy(IntSensor)));
+ C->setExecutionPolicy(IntSensor, DeluxeExecutionPolicy::decimation(2));
+ C->setExecutionPolicy(FloatSensor, DeluxeExecutionPolicy::decimation(2));
+ 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<int32_t>(C, "IntAgent");
AgentHandle FloatAgent = createLowLevelAgent<float>(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<double, int32_t, float>(
[](std::pair<int32_t, bool> I1,
std::pair<float, bool> I2) -> Optional<double> {
LOG_INFO_STREAM
<< "\n*******\nSum Agent triggered with values:\n"
<< (I1.second ? "<New>" : "<Old>")
<< " int value: " << I1.first << "\n"
<< (I2.second ? "<New>" : "<Old>")
<< " 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<unit_t, double>(
[](std::pair<double, bool> Sum) -> Optional<unit_t> {
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<int32_t> IntValues(NumberOfSimulationCycles);
std::generate(IntValues.begin(), IntValues.end(),
[i = 0](void) mutable { return ++i; });
C->registerSensorValues(IntSensor, IntValues.begin(), IntValues.end());
std::vector<float> 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/DeluxeAgent.hpp b/include/rosa/deluxe/DeluxeAgent.hpp
index 0e83a7c..48555ab 100755
--- a/include/rosa/deluxe/DeluxeAgent.hpp
+++ b/include/rosa/deluxe/DeluxeAgent.hpp
@@ -1,673 +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 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.
+/// \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 {
- 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);
+ // Call the processing function only if \p ExecutionPolicy allows.
+ 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)),
- OutputType(TypeNumberOf<T>::Value),
- NumberOfInputs(sizeof...(As)),
+ 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/DeluxeContext.hpp b/include/rosa/deluxe/DeluxeContext.hpp
index 29794a1..6ee0c03 100755
--- a/include/rosa/deluxe/DeluxeContext.hpp
+++ b/include/rosa/deluxe/DeluxeContext.hpp
@@ -1,294 +1,336 @@
//===-- rosa/deluxe/DeluxeContext.hpp ---------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeContext.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Public interface for the *deluxe interface* for working with agent
/// systems.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXECONTEXT_HPP
#define ROSA_DELUXE_DELUXECONTEXT_HPP
#include "rosa/deluxe/DeluxeSystem.hpp"
#include "rosa/support/types.hpp"
#include <iterator>
#include <memory>
#include <set>
/// Local helper macro to log and return a
/// \c rosa::deluxe::DeluxeContext::ErrorCode value.
///
/// Creates a debug message with the stringified value and returns the value.
///
/// \param Err \c rosa::deluxe::DeluxeContext::ErrorCode value to log and
/// return
#define DCRETERROR(Err) \
{ \
LOG_DEBUG(#Err); \
return Err; \
}
namespace rosa {
namespace deluxe {
/// Defines the *deluxe interface*.
class DeluxeContext {
/// A system owned by \p this object.
///
/// \note The reference is kept in a \c std::shared_ptr because of the member
/// function \c rosa::deluxe::DeluxeContext::getSystem.
std::shared_ptr<DeluxeSystem> System;
/// References to all *sensors* and *agents* created by \p this object.
std::set<AgentHandle> DeluxeUnits;
public:
/// Errors that may be resulted by some of the member functions of the class.
enum struct ErrorCode {
NoError,
TypeMismatch,
NotSensor,
NotAgent,
+ NotUnit,
WrongPosition,
AlreadyHasSlave,
AlreadyHasMaster,
- AlreadyHasValueStream
+ AlreadyHasValueStream,
+ UnsuitableExecutionPolicy
};
/// Returns a new instance of \c rosa::deluxe::DeluxeContext.
///
/// \param Name name of the underlying \c rosa::DeluxeSystem
///
/// \return \c std::unique_ptr for the new instance of
/// \c rosa::deluxe::DeluxeContext with a new, empty \c rosa::DeluxeSystem
static std::unique_ptr<DeluxeContext>
create(const std::string &Name) noexcept;
private:
/// Creates a new instance.
///
/// \note Private constructor restricts instantiation to member functions of
/// the class.
///
/// \param Name name of the underlying \c rosa::MessagingSystem
DeluxeContext(const std::string &Name) noexcept;
public:
/// Destroys \p this object.
~DeluxeContext(void) noexcept;
/// Returns a reference for the underlying \c rosa::MessagingSystem.
///
/// \note One cannot do much with a \c rosa::MessagingSystem currently, this
/// is for future use.
///
/// \return reference for the underlying \c rosa::MessagingSystem.
std::weak_ptr<MessagingSystem> getSystem(void) const noexcept;
/// Creates a new *sensor* in the context of \p this object.
///
/// \tparam T type of data the new *sensor* operates on
///
/// \param Name name of the new *sensor*
/// \param F function for the new *sensor* to generate the next value with
/// during normal operation
///
/// \note \p F is not used during simulation, in which case
/// \c rosa::deluxe::DeluxeContext::registerSensorValues is used to register
/// an alternative simulation data source with
/// \c rosa::deluxe::DeluxeSensor::registerSimulationDataSource. One may
/// safely keep relying on the default value of \p F as long as only
/// simulation of the system is to be done.
///
/// \return \c rosa::AgentHandle for the new *sensor*
template <typename T>
AgentHandle createSensor(const std::string &Name,
DeluxeSensor::D<T> &&F = [](void) {
return T();
}) noexcept;
/// Creates a new *agent* in the context of \p this object.
///
/// \tparam T type of data the new *agent* outputs
/// \tparam As types of inputs the new *agent* takes
///
/// \param Name name of the new *agent*
/// \param F function for the new *agent* to process input values and
/// generate output with
///
/// \return \c rosa::AgentHandle for the new *agent*
template <typename T, typename... As>
AgentHandle createAgent(const std::string &Name,
DeluxeAgent::D<T, As...> &&F) noexcept;
+ /// Returns the current execution policy of the referred \p Unit
+ ///
+ /// \see \c rosa::deluxe::DeluxeExecutionPolicy
+ ///
+ /// \note The referred \p Unit is either *sensor* or *agent*.
+ ///
+ /// \note The returned reference is valid only as long as \c
+ /// rosa::deluxe::DeluxeContext::setExecutionPolicy() is not called with the
+ /// *unit* referred by \p Unit and the *unit* is not destroyed.
+ ///
+ /// \param Unit the *unit* whose execution policy is to be obtained
+ ///
+ /// \return the \c rosa::deluxe::DeluxeExecutionPolicy from \p Unit if \p Unit
+ /// is valid
+ Optional<const DeluxeExecutionPolicy &>
+ getExecutionPolicy(AgentHandle Unit) const noexcept;
+
+ /// Sets the current execution policy of the referred \p Unit to \p
+ /// ExecutionPolicy.
+ ///
+ /// \see \c rosa::deluxe::DeluxeExecutionPolicy
+ ///
+ /// \note The referred \p Unit is either *sensor* or *agent*.
+ ///
+ /// \param Unit the *unit* whose execution policy is to be set
+ /// \param ExecutionPolicy the new execution policy for \p Unit
+ ///
+ /// \return how successful setting \p ExecutionPolicy for \p Unit was
+ ///
+ /// \note The function may return the following
+ /// \c rosa::deluxe::DeluxeContext::ErrorCode values:
+ /// `ErrorCode` | Comment
+ /// ----------- | -------
+ /// `NoError` | Success
+ /// `NotUnit` | Referred \p Unit is not valid
+ /// `UnsuitableExecutionPolicy` | \p ExecutionPolicy cannot handle \p Unit
+ ErrorCode setExecutionPolicy(
+ AgentHandle Unit,
+ std::unique_ptr<DeluxeExecutionPolicy> &&ExecutionPolicy) noexcept;
+
/// Connectes a *sensor* to an *agent* in the context of \p this object.
///
/// \param Agent the *agent* to connect to
/// \param Pos the index of slot of \p Agent to connect \p Sensor to
/// \param Sensor the *sensor* to connect
/// \param Description optional textual description of the connection
///
/// \return how successfull connecting \p Sensor to \p Agent at slot index
/// \p Pos was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Agent is not \c rosa::deluxe::DeluxeAgent
/// `NotSensor` | Referred \p Sensor is not \c rosa::deluxe::DeluxeSensor
/// `WrongPosition` | \p Pos is not a valid input position of \p Agent
/// `TypeMismatch` | Expected input type at position \p Pos of \p Agent is other than the output type of \p Sensor
/// `AlreadyHasSlave` | \p Agent at position \p Pos already has a *slave* registered
/// `AlreadyHasMaster` | \p Sensor already has a *master* registered
ErrorCode connectSensor(AgentHandle Agent, const size_t Pos,
AgentHandle Sensor,
const std::string &Description = "") noexcept;
/// Connectes two *agents* in the context of \p this object.
///
/// \param Master the *agent* to connect to
/// \param Pos the index of slot of \p Master to connect \p Slave to
/// \param Slave the *agent* to connect
/// \param Description optional textual description of the connection
///
/// \return how succesfull connecting \p Slave to \p Master at slot index
/// \p Pos was
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `NotAgent` | Referred \p Master or \p Slave is not \c rosa::deluxe::DeluxeAgent
/// `WrongPosition` | \p Pos is not a valid input position of \p Master
/// `TypeMismatch` | Expected input type at position \p Pos of \p Master is other than the output type of \p Slave
/// `AlreadyHasSlave` | \p Master at position \p Pos already has a *slave* registered
/// `AlreadyHasMaster` | \p Slave already has a *master* registered
ErrorCode connectAgents(AgentHandle Master, const size_t Pos,
AgentHandle Slave,
const std::string &Description = "") noexcept;
/// Initializes \c this object and others managed by \p this object for
/// setting up and performing simulation.
///
/// \see \c rosa::deluxe::DeluxeContext::registerSensorValues,
/// \c rosa::deluxe::DeluxeContext::simulate
///
/// Need to clear simulation data sources from all the *sensors*.
void initializeSimulation(void) noexcept;
/// Registers a stream providing values for a *sensor* during simulation.
///
/// \tparam Iterator type of iterator providing values for \p Sensor
/// \tparam T type of values \p Sensor is operating on, always use default!
///
/// \param Sensor the *sensor* to register values for
/// \param Start provides values for \p Sensor
/// \param End denotes the end of stream of values
/// \param Default value to be used when input stream is depleted during
/// simulation
///
/// \return how successful registering \p Source for \p Sensor
///
/// \note The function may return the following
/// \c rosa::deluxe::DeluxeContext::ErrorCode values:
/// `ErrorCode` | Comment
/// ----------- | -------
/// `NoError` | Success
/// `TypeMismatch` | \p Sensor generates values of a type other than \p T
/// `NotSensor` | Referred \p Sensor is not \c rosa::deluxe::DeluxeSensor
/// `AlreadyHasValueStream` | \p Sensor already has simulation data source set
template <typename Iterator, typename T = typename Iterator::value_type>
ErrorCode registerSensorValues(AgentHandle Sensor, Iterator &&Start,
const Iterator &End, T Default = {}) noexcept;
/// Performs the system contained by \p this object.
///
/// The function performs \p NumCycles cycle of simulation. In each cycle,
/// all the *agents* and *sensors* registered in
/// \c rosa::deluxe::DeluxeContext::DeluxeUnits are trigged for execution.
///
/// \param NumCycles number of cycles to perform
///
/// \pre All the *sensors* in the system contained by \p this object generate
/// their output from simulation data sources.
void simulate(const size_t NumCycles) const noexcept;
};
template <typename T>
AgentHandle DeluxeContext::createSensor(const std::string &Name,
DeluxeSensor::D<T> &&F) noexcept {
AgentHandle H = System->createSensor<T>(Name, std::move(F));
DeluxeUnits.emplace(H);
return H;
}
template <typename T, typename... As>
AgentHandle DeluxeContext::createAgent(const std::string &Name,
DeluxeAgent::D<T, As...> &&F) noexcept {
AgentHandle H = System->createAgent(Name, std::move(F));
DeluxeUnits.emplace(H);
return H;
}
template <typename Iterator, typename T>
DeluxeContext::ErrorCode
DeluxeContext::registerSensorValues(AgentHandle Sensor, Iterator &&Start,
const Iterator &End, T Default) noexcept {
// Get the type of values provided by \p Iterator.
STATIC_ASSERT((std::is_same<T, typename Iterator::value_type>::value),
"type mismatch");
// Make sure preconditions are met.
if (!System->isDeluxeSensor(Sensor)) {
DCRETERROR(ErrorCode::NotSensor);
}
auto S = System->getDeluxeSensor(Sensor);
ASSERT(S); // Sanity check.
if (S->OutputType != TypeNumberOf<T>::Value) {
DCRETERROR(ErrorCode::TypeMismatch);
} else if (S->simulationDataSourceIsSet()) {
DCRETERROR(ErrorCode::AlreadyHasValueStream);
}
// Register input stream.
// \note Need to capture parameters by value so having local copies.
S->registerSimulationDataSource(
DeluxeSensor::D<T>([=](void) mutable noexcept {
if (Start != End) {
LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
<< "': " << *Start << '\n';
return *Start++;
} else {
LOG_TRACE_STREAM << "Providing default value for sensor '"
<< S->FullName << "': " << Default << '\n';
return Default;
}
}));
return ErrorCode::NoError;
}
} // End namespace deluxe
} // End namespace rosa
// Undef local macro if not used in the corresponding implementation.
#ifndef ROSA_LIB_DELUXE_DELUXECONTEXT_CPP
#undef DCRETERROR
#endif
#endif // ROSA_DELUXE_DELUXECONTEXT_HPP
diff --git a/include/rosa/deluxe/DeluxeExecutionPolicy.h b/include/rosa/deluxe/DeluxeExecutionPolicy.h
new file mode 100644
index 0000000..caaad92
--- /dev/null
+++ b/include/rosa/deluxe/DeluxeExecutionPolicy.h
@@ -0,0 +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::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 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 46ca0c1..55e766c 100755
--- a/include/rosa/deluxe/DeluxeSensor.hpp
+++ b/include/rosa/deluxe/DeluxeSensor.hpp
@@ -1,257 +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) noexcept;
+ 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) noexcept {
+DeluxeSensor::H
+DeluxeSensor::triggerHandlerFromDataSource(D<T> &&F,
+ bool inSimulation) noexcept {
ASSERT(OutputType == TypeNumberOf<T>::Value);
- return [this, F](void) noexcept { sendToMaster(F()); };
+ return [ this, F, inSimulation ](void) noexcept {
+ // Get value and send it to master only if \p ExecutionPolicy allows it.
+ 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))),
- SFP(nullptr) {
+ 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(OutputType == TypeNumberOf<T>::Value);
- SFP = triggerHandlerFromDataSource(std::move(SF));
+ 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(OutputType == TypeNumberOf<T>::Value);
+ 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/include/rosa/deluxe/DeluxeSystem.hpp b/include/rosa/deluxe/DeluxeSystem.hpp
index 1be3bbd..7e08e82 100755
--- a/include/rosa/deluxe/DeluxeSystem.hpp
+++ b/include/rosa/deluxe/DeluxeSystem.hpp
@@ -1,210 +1,211 @@
//===-- rosa/deluxe/DeluxeSystem.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/deluxe/DeluxeSystem.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief Specialization of \c rosa::MessagingSystem for the *deluxe
/// interface*.
///
/// \see \c rosa::deluxe::DeluxeContext
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_DELUXE_DELUXESYSTEM_HPP
#define ROSA_DELUXE_DELUXESYSTEM_HPP
#include "rosa/core/MessagingSystem.hpp"
#include "rosa/deluxe/DeluxeAgent.hpp"
#include "rosa/deluxe/DeluxeSensor.hpp"
namespace rosa {
namespace deluxe {
/// Implements and extends the \c rosa::MessagingSystem interface to be
/// used by \c rosa::deluxe::DeluxeContext.
///
/// The class is a specialization of \c rosa::MessagingSystem, where objects
/// of two specialized subtypes of \c rosa::Agent, \c rosa::deluxe::DeluxeSensor
/// and \c rosa::deluxe::DeluxeAgent, constitute a system. The class extends the
/// \c rosa::MessagingSystem interface with features required to implement the
/// *deluxe interface*.
///
/// \see rosa::deluxe::DeluxeContext
class DeluxeSystem : public MessagingSystem {
friend class DeluxeContext;
+ friend class DeluxeExecutionPolicy;
public:
/// Returns an object implementing the \c rosa::deluxe::DeluxeSystem
/// interface.
///
/// \param Name name of the new instance
///
/// \return \c std::unique_ptr for the new instance of
/// \c rosa::DeluxeSystem
static std::unique_ptr<DeluxeSystem>
createSystem(const std::string &Name) noexcept;
protected:
/// Creates a new instance.
///
/// \note Protected constructor restricts instantiation for subclasses.
DeluxeSystem(void) noexcept = default;
public:
/// Creates a \c rosa::deluxe::DeluxeSensor instance owned by \p this object
/// and returns a \p rosa::AgentHandle for it.
///
/// \tparam T type of data the new \c rosa::deluxe::DeluxeSensor operates on
///
/// \param Name name of the new \c rosa::deluxe::DeluxeSensor
/// \param F function to generate the next value with during normal operation
///
/// \return \c rosa::AgentHandle for new \c rosa::deluxe::DeluxeSensor
template <typename T>
AgentHandle createSensor(const std::string &Name,
DeluxeSensor::D<T> &&F) noexcept;
/// Creates a \c rosa::deluxe::DeluxeAgent instance owned by \p this object
/// and returns a \c rosa::AgentHandle for it.
///
/// \tparam T type of data the new \c rosa::deluxe::DeluxeAgent outputs
/// \tparam As types of inputs the new \c rosa::deluxe::DeluxeAgent takes
///
/// \param Name name of the new \c rosa::deluxe::DeluxeAgent
/// \param F function for the new \c rosa::deluxe::DeluxeAgent to process
/// input values and generate output with
///
/// \return \c rosa::AgentHandle for new \c rosa::deluxe::DeluxeAgent
template <typename T, typename... As>
AgentHandle createAgent(const std::string &Name,
DeluxeAgent::D<T, As...> &&F) noexcept;
protected:
/// Tells whether a \c rosa::AgentHandle refers to a
/// \c rosa::deluxe::DeluxeSensor owned by \p this object.
///
/// \param H \c rosa::AgentHandle to check
///
/// \return whether \p H refers to a \c rosa::deluxe::DeluxeSensor owned by
/// \p this object
virtual bool isDeluxeSensor(const AgentHandle &H) const noexcept = 0;
/// Extracts a const qualified \c rosa::deluxe::DeluxeSensor reference from a
/// const qualified \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a const
/// qualified reference to a \c rosa::deluxe::DeluxeSensor object extracted
/// from a const qualified \c rosa::AgentHandle instance if the referred
/// object is of type \c rosa::deluxeDeluxeSensor and owned by \p this object.
/// The returned \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeSensor
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeSensor
/// from
///
/// \return const qualified reference to \c rosa::deluxe::DeluxeSensor if
/// \p H refers to an object which is of that type and is owned by \p this
/// object
Optional<const DeluxeSensor &> getDeluxeSensor(const AgentHandle &H) const
noexcept;
/// Extracts a \c rosa::deluxe::DeluxeSensor reference from a
/// \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a reference to
/// a \c rosa::deluxe::DeluxeSensor object extracted from a
/// \c rosa::AgentHandle instance if the referred object is of type
/// \c rosa::deluxeDeluxeSensor and owned by \p this object. The returned
/// \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeSensor
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeSensor
/// from
///
/// \return reference to \c rosa::deluxe::DeluxeSensor if \p H refers to an
/// object which is of that type and is owned by \p this object
Optional<DeluxeSensor &> getDeluxeSensor(AgentHandle &H) const noexcept;
/// Tells whether a \c rosa::AgentHandle refers to a
/// \c rosa::deluxe::DeluxeAgent owned by \p this object.
///
/// \param H \c rosa::AgentHandle to check
///
/// \return whether \p H refers to a \c rosa::deluxe::DeluxeAgent owned by
/// \p this object
virtual bool isDeluxeAgent(const AgentHandle &H) const noexcept = 0;
/// Extracts a const qualified \c rosa::deluxe::DeluxeAgent reference from a
/// const qualified \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a const
/// qualified reference to a \c rosa::deluxe::DeluxeAgent object extracted
/// from a const qualified \c rosa::AgentHandle instance if the referred
/// object is of type \c rosa::deluxeDeluxeAgent and owned by \p this object.
/// The returned \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeAgent
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeAgent
/// from
///
/// \return const qualified reference to \c rosa::deluxe::DeluxeAgent if \p H
/// refers to an object which is of that type and is owned by \p this object
Optional<const DeluxeAgent &> getDeluxeAgent(const AgentHandle &H) const
noexcept;
/// Extracts a \c rosa::deluxe::DeluxeAgent reference from a
/// \c rosa::AgentHandle if possible.
///
/// The function returns a \c rosa::Optional object containing a reference to
/// a \c rosa::deluxe::DeluxeAgent object extracted from a
/// \c rosa::AgentHandle instance if the referred object is of type
/// \c rosa::deluxeDeluxeAgent and owned by \p this object. The returned
/// \c rosa::Optional object is empty otherwise.
///
/// \see rosa::deluxe::DeluxeSystem::isDeluxeAgent
///
/// \param H \c rosa::AgentHandle to extract a \c rosa::deluxe::DeluxeAgent
/// from
///
/// \return reference to \c rosa::deluxe::DeluxeAgent if \p H refers to an
/// object which is of that type and is owned by \p this object
Optional<DeluxeAgent &> getDeluxeAgent(AgentHandle &H) const noexcept;
};
template <typename T>
AgentHandle DeluxeSystem::createSensor(const std::string &Name,
DeluxeSensor::D<T> &&F) noexcept {
Agent &DS = createUnit<DeluxeSensor, MessagingSystem>(
[&](const id_t Id, MessagingSystem &S) {
return new DeluxeSensor(atoms::SensorKind, Id, Name, S, std::move(F));
});
return {DS};
}
template <typename T, typename... As>
AgentHandle DeluxeSystem::createAgent(const std::string &Name,
DeluxeAgent::D<T, As...> &&F) noexcept {
Agent &DA = createUnit<DeluxeAgent, DeluxeSystem>(
[&](const id_t Id, DeluxeSystem &S) {
return new DeluxeAgent(atoms::AgentKind, Id, Name, S, std::move(F));
});
return {DA};
}
} // End namespace deluxe
} // End namespace rosa
#endif // ROSA_DELUXE_DELUXESYSTEM_HPP
diff --git a/lib/deluxe/CMakeLists.txt b/lib/deluxe/CMakeLists.txt
index 41a22b3..ab86f2c 100755
--- a/lib/deluxe/CMakeLists.txt
+++ b/lib/deluxe/CMakeLists.txt
@@ -1,20 +1,30 @@
set(LIB_INCLUDE_DIR ${ROSA_MAIN_INCLUDE_DIR}/rosa/deluxe)
add_library(ROSADeluxe
${LIB_INCLUDE_DIR}/namespace.h
namespace.cpp
${LIB_INCLUDE_DIR}/DeluxeAtoms.hpp
DeluxeAtoms.cpp
+ executionpolicies/Decimation.h
+ executionpolicies/Decimation.cpp
+ executionpolicies/AwaitBase.h
+ executionpolicies/AwaitBase.cpp
+ executionpolicies/AwaitAll.h
+ executionpolicies/AwaitAll.cpp
+ executionpolicies/AwaitAny.h
+ executionpolicies/AwaitAny.cpp
+ ${LIB_INCLUDE_DIR}/DeluxeExecutionPolicy.h
+ DeluxeExecutionPolicy.cpp
${LIB_INCLUDE_DIR}/DeluxeSensor.hpp
DeluxeSensor.cpp
${LIB_INCLUDE_DIR}/DeluxeAgent.hpp
DeluxeAgent.cpp
${LIB_INCLUDE_DIR}/DeluxeSystem.hpp
DeluxeSystem.cpp
DeluxeSystemImpl.hpp
DeluxeSystemImpl.cpp
${LIB_INCLUDE_DIR}/DeluxeContext.hpp
DeluxeContext.cpp
)
ROSA_add_library_dependencies(ROSADeluxe ROSACore)
diff --git a/lib/deluxe/DeluxeAgent.cpp b/lib/deluxe/DeluxeAgent.cpp
index 78d1cd4..0096b02 100755
--- a/lib/deluxe/DeluxeAgent.cpp
+++ b/lib/deluxe/DeluxeAgent.cpp
@@ -1,205 +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/DeluxeSensor.hpp"
+#include "rosa/deluxe/DeluxeSystem.hpp"
#include <algorithm>
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<DeluxeSystem &>(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<id_t, size_t> 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<const DeluxeSensor &>(A).OutputType == T) ||
(A.Kind == atoms::AgentKind &&
static_cast<const DeluxeAgent &>(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<AgentHandle> &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<DeluxeAgent&>(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<DeluxeExecutionPolicy> &&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<DeluxeSystem &>(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<AgentHandle> DeluxeAgent::master(void) const noexcept {
ASSERT(inv());
return Master;
}
void DeluxeAgent::registerMaster(const Optional<AgentHandle> _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<AgentHandle> DeluxeAgent::slave(const size_t Pos) const noexcept {
ASSERT(inv() && Pos < NumberOfInputs);
return Slaves[Pos];
}
void DeluxeAgent::registerSlave(const size_t Pos,
const Optional<AgentHandle> Slave) noexcept {
ASSERT(inv() && Pos < NumberOfInputs &&
(!Slave ||
(unwrapAgent(*Slave).Kind == atoms::SensorKind &&
static_cast<const DeluxeSensor &>(unwrapAgent(*Slave)).OutputType ==
InputTypes[Pos]) ||
(unwrapAgent(*Slave).Kind == atoms::AgentKind &&
static_cast<const DeluxeAgent &>(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<AgentHandle>();
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<DeluxeAgent &>(A).registerMaster({});
} else {
ASSERT(A.Kind == atoms::SensorKind); // Sanity check.
static_cast<DeluxeSensor &>(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/DeluxeContext.cpp b/lib/deluxe/DeluxeContext.cpp
index f3fb417..0e363fe 100755
--- a/lib/deluxe/DeluxeContext.cpp
+++ b/lib/deluxe/DeluxeContext.cpp
@@ -1,151 +1,197 @@
//===-- deluxe/DeluxeContext.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file deluxe/DeluxeContext.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Implementation for rosa/deluxe/DeluxeContext.hpp.
///
//===----------------------------------------------------------------------===//
#define ROSA_LIB_DELUXE_DELUXECONTEXT_CPP // For including helper macros.
#include "rosa/deluxe/DeluxeContext.hpp"
#include <algorithm>
namespace rosa {
namespace deluxe {
std::unique_ptr<DeluxeContext>
DeluxeContext::create(const std::string &Name) noexcept {
return std::unique_ptr<DeluxeContext>(new DeluxeContext(Name));
}
DeluxeContext::DeluxeContext(const std::string &Name) noexcept
: System(DeluxeSystem::createSystem(Name)) {
LOG_TRACE("DeluxeContext for '" + System->name() + "' is created.");
}
DeluxeContext::~DeluxeContext(void) noexcept {
// \c rosa::deluxe::DeluxeContext::System is not used outside, just clean it.
for(auto U : DeluxeUnits) {
System->destroyAgent(U);
}
// \note \c System will be marked clean by SystemImpl::~SystemImpl.
LOG_TRACE("DeluxeContext for '" + System->name() +
"' prepared for destruction.");
}
+Optional<const DeluxeExecutionPolicy &>
+DeluxeContext::getExecutionPolicy(AgentHandle Unit) const noexcept {
+ if (System->isDeluxeSensor(Unit)) {
+ return {System->getDeluxeSensor(Unit)->executionPolicy()};
+ } else if (System->isDeluxeAgent(Unit)) {
+ return {System->getDeluxeAgent(Unit)->executionPolicy()};
+ } else {
+ return {};
+ }
+}
+
+DeluxeContext::ErrorCode DeluxeContext::setExecutionPolicy(
+ AgentHandle Unit,
+ std::unique_ptr<DeluxeExecutionPolicy> &&ExecutionPolicy) noexcept {
+ // Generate trace log.
+ auto &Trace = LOG_TRACE_STREAM;
+ Trace << "Setting execution policy of " << System->unwrapAgent(Unit).FullName
+ << " to ";
+ if (ExecutionPolicy) {
+ Trace << "'" << ExecutionPolicy->dump() << "'\n";
+ } else {
+ Trace << "[]\n";
+ DCRETERROR(ErrorCode::UnsuitableExecutionPolicy);
+ }
+
+ if (System->isDeluxeSensor(Unit)) {
+ const bool Success = System->getDeluxeSensor(Unit)->setExecutionPolicy(
+ std::move(ExecutionPolicy));
+ if (!Success) {
+ DCRETERROR(ErrorCode::UnsuitableExecutionPolicy);
+ } else {
+ return ErrorCode::NoError;
+ }
+ } else if (System->isDeluxeAgent(Unit)) {
+ const bool Success = System->getDeluxeAgent(Unit)->setExecutionPolicy(
+ std::move(ExecutionPolicy));
+ if (!Success) {
+ DCRETERROR(ErrorCode::UnsuitableExecutionPolicy);
+ } else {
+ return ErrorCode::NoError;
+ }
+ } else {
+ DCRETERROR(ErrorCode::NotUnit);
+ }
+}
+
DeluxeContext::ErrorCode
DeluxeContext::connectSensor(AgentHandle Agent, const size_t Pos,
AgentHandle Sensor,
const std::string &Description) noexcept {
// Generate trace log.
auto &Trace = LOG_TRACE_STREAM;
Trace << "Establishing connection";
if (!Description.empty()) {
Trace << " '" << Description << "'";
}
Trace << " between '" << System->unwrapAgent(Sensor).FullName << "' and '"
<< System->unwrapAgent(Agent).FullName << "'\n";
// Make sure preconditions are met.
if (!System->isDeluxeAgent(Agent)) {
DCRETERROR(ErrorCode::NotAgent);
} else if (!System->isDeluxeSensor(Sensor)) {
DCRETERROR(ErrorCode::NotSensor);
}
auto A = System->getDeluxeAgent(Agent);
auto S = System->getDeluxeSensor(Sensor);
ASSERT(A && S); // Sanity check.
if (Pos >= A->NumberOfInputs) {
DCRETERROR(ErrorCode::WrongPosition);
} else if (A->inputType(Pos) != S->OutputType) {
DCRETERROR(ErrorCode::TypeMismatch);
} else if (A->slave(Pos)) {
DCRETERROR(ErrorCode::AlreadyHasSlave);
} else if (S->master()) {
DCRETERROR(ErrorCode::AlreadyHasMaster);
}
// Do register.
A->registerSlave(Pos, {Sensor});
S->registerMaster({Agent});
return ErrorCode::NoError;
}
DeluxeContext::ErrorCode
DeluxeContext::connectAgents(AgentHandle Master, const size_t Pos,
AgentHandle Slave,
const std::string &Description) noexcept {
// Generate trace log.
auto &Trace = LOG_TRACE_STREAM;
Trace << "Establishing connection";
if (!Description.empty()) {
Trace << " '" << Description << "'";
}
Trace << " between '" << System->unwrapAgent(Slave).FullName << "' and '"
<< System->unwrapAgent(Master).FullName << "'\n";
// Make sure preconditions are met.
if (!(System->isDeluxeAgent(Master) && System->isDeluxeAgent(Slave))) {
DCRETERROR(ErrorCode::NotAgent);
}
auto M = System->getDeluxeAgent(Master);
auto S = System->getDeluxeAgent(Slave);
ASSERT(M && S); // Sanity check.
if (Pos >= M->NumberOfInputs) {
DCRETERROR(ErrorCode::WrongPosition);
} else if (M->inputType(Pos) != S->OutputType) {
DCRETERROR(ErrorCode::TypeMismatch);
} else if (M->slave(Pos)) {
DCRETERROR(ErrorCode::AlreadyHasSlave);
} else if (S->master()) {
DCRETERROR(ErrorCode::AlreadyHasMaster);
}
// Do register.
M->registerSlave(Pos, {Slave});
S->registerMaster({Master});
return ErrorCode::NoError;
}
std::weak_ptr<MessagingSystem> DeluxeContext::getSystem(void) const noexcept {
return std::weak_ptr<MessagingSystem>(System);
}
void DeluxeContext::initializeSimulation(void) noexcept {
// Clear simulation data sources from sensors.
for (auto U : DeluxeUnits) {
if (auto S = System->getDeluxeSensor(U)) {
S->clearSimulationDataSource();
}
}
}
void DeluxeContext::simulate(const size_t NumCycles) const noexcept {
ASSERT(std::all_of(
DeluxeUnits.begin(), DeluxeUnits.end(), [&](const AgentHandle &H) {
return System->isDeluxeAgent(H) ||
System->isDeluxeSensor(H) &&
System->getDeluxeSensor(H)->simulationDataSourceIsSet();
}));
for (size_t I = 1; I <= NumCycles; ++I) {
LOG_TRACE("Simulation cycle: " + std::to_string(I));
for (auto U : DeluxeUnits) {
U.sendMessage(Message::create(atoms::Trigger::Value));
}
}
}
} // End namespace deluxe
} // End namespace rosa
diff --git a/lib/deluxe/DeluxeExecutionPolicy.cpp b/lib/deluxe/DeluxeExecutionPolicy.cpp
new file mode 100644
index 0000000..bbea1ea
--- /dev/null
+++ b/lib/deluxe/DeluxeExecutionPolicy.cpp
@@ -0,0 +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>
+DeluxeExecutionPolicy::decimation(const size_t D) {
+ return std::unique_ptr<DeluxeExecutionPolicy>(new Decimation(D));
+}
+
+std::unique_ptr<DeluxeExecutionPolicy>
+DeluxeExecutionPolicy::awaitAll(const std::set<size_t> &S) {
+ return std::unique_ptr<DeluxeExecutionPolicy>(new AwaitAll(S));
+}
+
+std::unique_ptr<DeluxeExecutionPolicy>
+DeluxeExecutionPolicy::awaitAny(const std::set<size_t> &S) {
+ return std::unique_ptr<DeluxeExecutionPolicy>(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 c55ef7f..c5269f7 100755
--- a/lib/deluxe/DeluxeSensor.cpp
+++ b/lib/deluxe/DeluxeSensor.cpp
@@ -1,63 +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/DeluxeAgent.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<DeluxeSystem &>(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<DeluxeAgent&>(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<DeluxeExecutionPolicy> &&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<DeluxeSystem &>(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<AgentHandle> DeluxeSensor::master(void) const noexcept {
+ ASSERT(inv());
return Master;
}
void DeluxeSensor::registerMaster(const Optional<AgentHandle> _Master) noexcept {
- ASSERT(!_Master || unwrapAgent(*_Master).Kind == atoms::AgentKind);
+ 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
diff --git a/lib/deluxe/executionpolicies/AwaitAll.cpp b/lib/deluxe/executionpolicies/AwaitAll.cpp
new file mode 100644
index 0000000..70740b2
--- /dev/null
+++ b/lib/deluxe/executionpolicies/AwaitAll.cpp
@@ -0,0 +1,34 @@
+//===-- deluxe/executionpolicies/AwaitAll.cpp -------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file deluxe/executionpolicies/AwaitAll.cpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2019
+///
+/// \brief Implementation for deluxe/executionpolicies/AwaitAll.h.
+///
+//===----------------------------------------------------------------------===//
+
+#include "AwaitAll.h"
+
+#include <algorithm>
+
+namespace rosa {
+namespace deluxe {
+
+AwaitAll::AwaitAll(const std::set<size_t> &S)
+ : AwaitBase(S,
+ CheckerType(std::all_of<std::set<size_t>::const_iterator,
+ std::function<bool(const size_t)>>)) {}
+
+std::string AwaitAll::dump(void) const noexcept {
+ return "Await all of " + dumpS();
+}
+
+} // End namespace deluxe
+} // End namespace rosa
diff --git a/lib/deluxe/executionpolicies/AwaitAll.h b/lib/deluxe/executionpolicies/AwaitAll.h
new file mode 100644
index 0000000..1374f90
--- /dev/null
+++ b/lib/deluxe/executionpolicies/AwaitAll.h
@@ -0,0 +1,48 @@
+//===-- deluxe/executionpolicies/AwaitAll.h ---------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file deluxe/executionpolicies/AwaitAll.h
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2019
+///
+/// \brief Declaration of the *execution policy* *await all*.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITALL_H
+#define ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITALL_H
+
+#include "AwaitBase.h"
+
+namespace rosa {
+namespace deluxe {
+
+/// Implementation of the *execution policy* *await all*.
+///
+/// \see \c rosa::deluxe::DeluxeExecutionPolicy::awaitAll()
+class AwaitAll : public AwaitBase {
+public:
+ /// Constructor.
+ ///
+ /// The constructor instatiates \c rosa::deluxe::AwaitBase so that execution
+ /// is allowed when all *slave* positions included in \p S have received new
+ /// input since the last triggering.
+ ///
+ /// \param S set of *slave* positoins to check
+ AwaitAll(const std::set<size_t> &S);
+
+ /// 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_AWAITALL_H
diff --git a/lib/deluxe/executionpolicies/AwaitAny.cpp b/lib/deluxe/executionpolicies/AwaitAny.cpp
new file mode 100644
index 0000000..109c4cd
--- /dev/null
+++ b/lib/deluxe/executionpolicies/AwaitAny.cpp
@@ -0,0 +1,34 @@
+//===-- deluxe/executionpolicies/AwaitAny.cpp -------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file deluxe/executionpolicies/AwaitAny.cpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2019
+///
+/// \brief Implementation for deluxe/executionpolicies/AwaitAny.h.
+///
+//===----------------------------------------------------------------------===//
+
+#include "AwaitAny.h"
+
+#include <algorithm>
+
+namespace rosa {
+namespace deluxe {
+
+AwaitAny::AwaitAny(const std::set<size_t> &S)
+ : AwaitBase(S,
+ CheckerType(std::any_of<std::set<size_t>::const_iterator,
+ std::function<bool(const size_t)>>)) {}
+
+std::string AwaitAny::dump(void) const noexcept {
+ return "Await any of " + dumpS();
+}
+
+} // End namespace deluxe
+} // End namespace rosa
diff --git a/lib/deluxe/executionpolicies/AwaitAny.h b/lib/deluxe/executionpolicies/AwaitAny.h
new file mode 100644
index 0000000..d69df29
--- /dev/null
+++ b/lib/deluxe/executionpolicies/AwaitAny.h
@@ -0,0 +1,48 @@
+//===-- deluxe/executionpolicies/AwaitAny.h ---------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file deluxe/executionpolicies/AwaitAny.h
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2019
+///
+/// \brief Declaration of the *execution policy* *await any*.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITANY_H
+#define ROSA_LIB_DELUXE_EXECUTIONPOLICIES_AWAITANY_H
+
+#include "AwaitBase.h"
+
+namespace rosa {
+namespace deluxe {
+
+/// Implementation of the *execution policy* *await any*.
+///
+/// \see \c rosa::deluxe::DeluxeExecutionPolicy::awaitAny()
+class AwaitAny : public AwaitBase {
+public:
+ /// Constructor.
+ ///
+ /// The constructor instatiates \c rosa::deluxe::AwaitBase so that execution
+ /// is allowed when any of the *slave* positions included in \p S has received
+ /// new input since the last triggering.
+ ///
+ /// \param S set of *slave* positoins to check
+ AwaitAny(const std::set<size_t> &S);
+
+ /// 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_AWAITANY_H
diff --git a/lib/deluxe/executionpolicies/AwaitBase.cpp b/lib/deluxe/executionpolicies/AwaitBase.cpp
new file mode 100644
index 0000000..d4ec684
--- /dev/null
+++ b/lib/deluxe/executionpolicies/AwaitBase.cpp
@@ -0,0 +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::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
new file mode 100644
index 0000000..e196701
--- /dev/null
+++ b/lib/deluxe/executionpolicies/AwaitBase.h
@@ -0,0 +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::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::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 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
new file mode 100644
index 0000000..2f324f9
--- /dev/null
+++ b/lib/deluxe/executionpolicies/Decimation.cpp
@@ -0,0 +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::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
new file mode 100644
index 0000000..b4d826c
--- /dev/null
+++ b/lib/deluxe/executionpolicies/Decimation.h
@@ -0,0 +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 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
diff --git a/modules/CMakeLists.txt b/modules/CMakeLists.txt
index 218a65a..6979d5e 100644
--- a/modules/CMakeLists.txt
+++ b/modules/CMakeLists.txt
@@ -1,14 +1,19 @@
if ( ROSA_COMPILER_IS_GCC_COMPATIBLE )
# Allow exceptions by removing restricting flag (needed by cxxopts)
remove("-fno-exceptions" CMAKE_CXX_FLAGS)
# Allow dynamic casts by removing restriction flag (needed by cxxopts)
remove("-fno-rtti" CMAKE_CXX_FLAGS)
+elseif ( MSVC )
+
+ # Exceptions enabled for MSVC by default but need to allow RTTI
+ # (needed by cxxopts)
+ remove("/GR-" CMAKE_CXX_FLAGS)
endif()
execute_process(COMMAND git submodule update --init --recursive
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR})
# Add the different subdirectories
ADDALLSUBDIRS()

File Metadata

Mime Type
text/x-diff
Expires
Tue, Jan 28, 8:35 PM (1 d, 4 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
126003
Default Alt Text
(124 KB)

Event Timeline