Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F327843
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
124 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
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)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment