Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F386697
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
39 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/examples/CSVFiles/main.cpp b/examples/CSVFiles/main.cpp
index a4d5b51..5fc6075 100644
--- a/examples/CSVFiles/main.cpp
+++ b/examples/CSVFiles/main.cpp
@@ -1,360 +1,360 @@
//===-- examples/CSVFiles/main.cpp ------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \file examples/basic-system/basic-system.cpp
///
/// \author Edwin Willegger (edwin.willegger@tuwien.ac.at)
///
/// \date 2019
///
/// \brief A simple example on the basic \c rosa::csv, \c rosa::iterator and
/// \c rosa::writer classes. Focus is on the tuple impementations.
///
//===----------------------------------------------------------------------===//
#include <cstdint>
#include <cstddef>
#include <iostream>
#include <istream>
#include <sstream>
#include <fstream>
#include <ostream>
#include <string>
#include <vector>
#include <typeinfo>
#include <map>
#include <algorithm>
#include <tuple>
#include <type_traits>
//includes for an complete example to read and write
//with sensors and agents.
#include "rosa/deluxe/DeluxeContext.hpp"
#include "rosa/config/version.h"
//includes to test the basic functionality
//to read and write tuples.
#include "rosa/support/csv/CSVReader.hpp"
#include "rosa/support/csv/CSVWriter.hpp"
#include "rosa/support/iterator/split_tuple_iterator.hpp"
#include "rosa/support/writer/split_tuple_writer.hpp"
/// the name of the example
const std::string ExampleName = "csvfiles";
/// How many cycles of simulation to perform.
const size_t NumberOfSimulationCycles = 10;
/// Paths for the CSV files for simulation.
/// input csv files
const std::string csvPath = "../examples/CSVFiles/";
const std::string csvFileWithHeader = csvPath + "HR-New.csv";
const std::string csvFileNoHeader = csvPath + "HR.csv";
const std::string csvFileHeaderSemi = csvPath + "HR-New-Semicolon.csv";
/// output csv files
const std::string csvFileWriteHea = csvPath + "csvwriter_noheader.csv";
const std::string csvFileWriteNoHeaSplit = csvPath + "csvSplitwriter_noheader.csv";
using namespace rosa;
///
/// This function tests the basic CSVIterator capablities, and shows you
/// how you could work with this class.
///
void testtupleCSVReader(void){
//different streams to get the csv data out of the files
//file contains header and valid data entries, delimter = ','
std::ifstream file_header_data(csvFileWithHeader);
//file contains header and valid data entries, delimter = ','
std::ifstream file_header_data_2(csvFileWithHeader);
//file contains header and valid data entries, delimter = ','
std::ifstream file_header_data_3(csvFileWithHeader);
//file contains header and valid data entries, delimter = ','
std::ifstream file_header_data_4(csvFileWithHeader);
//file contains header and valid data entries, delimter = ','
std::ifstream file_header_data_5(csvFileWithHeader);
//file contains header and valid data entries, delimter = ','
std::ifstream file_header_data_6(csvFileWithHeader);
//file contains no header an valid data entries, delimter = ','
std::ifstream file2(csvFileNoHeader);
//file contains header and valid data entries, delimter = ';'
std::ifstream file3(csvFileHeaderSemi);
csv::CSVIterator<int, std::string, std::string, int, int> it(file_header_data);
it.setDelimeter(',');
- it++;
- it++;
+ (void)++it;
+ (void)++it;
//if you iterate over the end of file, the last values
//of the file will remain in the data structure but no
//error occurs.
- it++;
- it++;
+ (void)++it;
+ (void)++it;
//-------------------------------------------------------------------
// a possiblity to get the data out of the iterator
std::tuple<int, std::string, std::string, int, int> value = *it;
//
// Show the value of one iterator
//
LOG_INFO( "Values are: ");
LOG_INFO(std::get<0>(value) );
LOG_INFO(std::get<1>(value) );
//--------------------------------------------------------------------
//testing differnet parameters to the constructor
//uncomment to see that it is not possible to iterate over an vector in the tuple.
//rosa::csv::CSVIterator<double, std::vector<int>> it2(file, 1);
//try to skip a valid number of lines after the header
csv::CSVIterator<double, float, int, int, float> it2_0(file_header_data_2, 1);
//try to skip a valid number of lines after the header, but you assume that the file has no header
//uncomment this line to crash the programm
//csv::CSVIterator<double, float, int, int, float> it2_1(file_header_data_3, 0, csv::HeaderInformation::HasNoHeader);
//try to skip a valid number of lines after the header, but you assume that the file has no header
//uncomment this line to crash the program
//csv::CSVIterator<double, float, int, int, float> it2_2(file_header_data_4, 1, csv::HeaderInformation::HasNoHeader);
//try to skip a valid number of lines of a file without header
csv::CSVIterator<double, float, int, int, float> it2_3(file2, 1, csv::HeaderInformation::HasNoHeader);
//try to skip a valid number of lines after the header, but with different delimeter
csv::CSVIterator<double, float, int, int, float> it2_4(file3, 2, csv::HeaderInformation::HasHeader, ';');
// if you skip more lines than valid, you generate an infinte loop
//csv::CSVIterator<double, float, int, int, float> it3(file_header_data_5, 500);
//if you don't need data from all columns just select the number of columns you
//need. You get the data back from the first column (index 0) to the fourth column
//all values from the fifth column are ignored.
csv::CSVIterator<double, float, int, float> it4(file_header_data_6);
}
///
/// This function tests the basic CSVTupleWriter capablities, and shows you
/// how you could work with this class.
///
void testtupleCSVWriter(void){
//
// Create output writer with an file
//
std::ofstream file_header_out(csvFileWriteHea);
csv::CSVTupleWriter<int, float, std::string> wri(file_header_out);
//
// Create test tuples
//
std::tuple<int, float, std::string> values(5, 8.3f, "hallo");
std::tuple<int, float, std::string> values2(3, 8.3f, "end");
//
// Create test header lines for the test tuples
//
std::array<std::string, 3> header{
{"zero column", "first column", "second column"}};
std::array<std::string, 4> headerWrong{
{"zero column", "first column", "second column", "third column"}};
std::array<std::string, 2> headerWrongShort{
{"zero column", "first column"}};
//if you uncomment this line than it would be possible for you to write the header into the stream
//in the next line.
//wri.write(values);
wri.writeHeader(header);
wri.write(values);
wri.write(values);
// it is not possible to write an additional header into the stream.
wri.writeHeader(header);
wri.write(values);
wri << values;
wri << values2;
//uncomment this line to see, that you can't write a header with the too many elements.
//wri.writeHeader(headerWrong);
//uncomment this line to see, that you can't write a header with the too few elements.
//wri.writeHeader(headerWrongShort);
}
///
/// This function tests the basic splitTupleIterator capablities, and shows you
/// how you could work with this class, this class is used if you want to split
/// a CSVIterator in separate parts.
///
void testsplitTupleIterator(void)
{
//
// Create deluxe context
//
std::unique_ptr<rosa::deluxe::DeluxeContext> C =
deluxe::DeluxeContext::create(ExampleName);
//
// 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.
// Three different sensors were created, this is just a random number taken.
AgentHandle Elem0Sensor = C->createSensor<int>("Element1 Sensor");
AgentHandle Elem1Sensor = C->createSensor<float>("Element2 Sensor");
AgentHandle Elem2Sensor = C->createSensor<std::string>("Element3 Sensor");
//
// Initialize deluxe context for simulation.
//
C->initializeSimulation();
// Type aliases for iterators
using Iterator = rosa::csv::CSVIterator<int, float, std::string>;
using IteratorValue = std::tuple<int, float, std::string>;
static_assert (std::is_same<typename Iterator::value_type, IteratorValue>::value, "Iterator must provide tuples" );
//
// Open CSV file and register the columns to the corresponding sensors.
//
std::ifstream TestCSV(csvFileWithHeader);
//
// Test data looks like:
// Element1, Element2, Element3, Element4, Element5 -- is the header line
// 3, 5, 8, 9.5, 17 -- first line of values
// 100, -8, 30, 18.8, 29 -- other line of values were also in the file
// 5, 20, -100, -200.1, -30 -- if you have less number of values than simulation rounds all values
// -- beyond your last value will be zero.
//get element iterator ranges
auto [Elem0Range, Elem1Range, Elem2Range] = iterator::splitTupleIterator(Iterator(TestCSV), Iterator());
//dissect a range into begin and end iterators by structred bindings
auto[Elem0Begin, Elem0End] = Elem0Range;
//deissect a range with functions
auto Elem1Begin = iterator::begin(Elem1Range);
auto Elem1End = iterator::end(Elem1Range);
C->registerSensorValues(Elem0Sensor, std::move(Elem0Begin), Elem0End);
C->registerSensorValues(Elem1Sensor, std::move(Elem1Begin), Elem1End);
C->registerSensorValues(Elem2Sensor, std::move(iterator::begin(Elem2Range)),
iterator::end(Elem2Range));
//
// Simulate.
//
C->simulate(NumberOfSimulationCycles);
}
///
/// This function tests the basic splitTupleWriter capablities, and shows you
/// how you could work with this class, this class is used if you want to split
/// a CSVWriter in separate parts.
///
void testsplitTupleWriter(void){
//
// Create output writer with an file
//
std::ofstream file_header_out(csvFileWriteNoHeaSplit);
csv::CSVTupleWriter<int, float, std::string> wri(file_header_out);
// if you omit, the type definition in the template, than auto generated types were used,
// and they may not fit to the used CSVTupleWriter.
wri << std::make_tuple<int, float, std::string>(1000, 50.6f, "tuple_created");
auto [T0Writer, T1Writer, T2Writer] = writer::splitTupleWriter(std::move(wri),
writer::IncompleteTuplePolicy::Ignore);
//writing elements in sequential order into the writer classes, but you can write the values into the writers in
//a random order.
T0Writer << (500);
T1Writer << (3.0);
T2Writer << "splitted writter";
T2Writer << "splitting is cool";
T0Writer << (-30);
T1Writer << (-0.004f);
// you can also write more often values into a writer and later into the other writers
// all data will be processed correctly into the right order.
T0Writer << (1);
T0Writer << (2);
T1Writer << (-0.4f);
T0Writer << (3);
T2Writer << "again";
T0Writer << (4);
T1Writer << (-0.1f);
T1Writer << (-0.2f);
T2Writer << "and";
T1Writer << (-0.3f);
T2Writer << "splitting";
T2Writer << "once again";
// again writing data of one tuple entry to the different writers in a random fashion.
T1Writer << (-0.004f);
T2Writer << "splitting is cool";
T0Writer << (-30);
}
int main(void){
LOG_INFO_STREAM << library_string() << " -- " << terminal::Color::Red
<< ExampleName << " example" << terminal::Color::Default << '\n';
//
// Testing CSVWriter.
//
LOG_INFO("Testing CSVWriter CSVTupleItrator implementation: ");
testtupleCSVWriter();
//
// Testing CSVReader.
//
LOG_INFO("Testing CSVReader CSVTupleIterator implementation: ");
testtupleCSVReader();
//
// Testing SplitTupleIterator.
//
LOG_INFO("Testing SplitTupleIterator: ");
testsplitTupleIterator();
//
// Testing SplitTupleWriter.
//
LOG_INFO("Testing SplitTupleWriter: ");
testsplitTupleWriter();
//
// info that user knows programm has finished.
//
LOG_INFO( "All tests finished.");
return 0;
}
diff --git a/include/rosa/deluxe/DeluxeSensor.hpp b/include/rosa/deluxe/DeluxeSensor.hpp
index ba521a7..15e9a81 100644
--- a/include/rosa/deluxe/DeluxeSensor.hpp
+++ b/include/rosa/deluxe/DeluxeSensor.hpp
@@ -1,674 +1,674 @@
//===-- rosa/deluxe/DeluxeSensor.hpp ----------------------------*- C++ -*-===//
//
// The RoSA Framework
//
// Distributed under the terms and conditions of the Boost Software License 1.0.
// See accompanying file LICENSE.
//
// If you did not receive a copy of the license file, see
// http://www.boost.org/LICENSE_1_0.txt.
//
//===----------------------------------------------------------------------===//
///
/// \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"
#include "rosa/deluxe/DeluxeTuple.hpp"
/// Local helper macros to deal with built-in types.
///
///@{
/// Creates function name for member functions in \c rosa::deluxe::DeluxeSensor.
///
/// \param N name suffix to use
#define DSMASTERHANDLERNAME(N) handleMaster_##N
/// Defines member functions for handling messages from *master* in
/// \c rosa::deluxe::DeluxeSensor.
///
/// \see \c DeluxeSensorMasterInputHandlers
///
/// \note No pre- and post-conditions are validated directly by these functions,
/// they rather rely on \c rosa::deluxe::DeluxeSensor::saveMasterInput to do
/// that.
///
/// \param T the type of input to handle
/// \param N name suffix for the function identifier
#define DSMASTERHANDLERDEFN(T, N) \
void DSMASTERHANDLERNAME(N)(atoms::Master, id_t MasterId, token_size_t Pos, \
T Value) noexcept { \
saveMasterInput(MasterId, Pos, Value); \
}
/// Convenience macro for \c DSMASTERHANDLERDEFN with identical arguments.
///
/// \see \c DSMASTERHANDLERDEFN
///
/// This macro can be used instead of \c DSMASTERHANDLERDEFN 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 DSMASTERHANDLERDEF(T) DSMASTERHANDLERDEFN(T, T)
/// Results in a \c THISMEMBER reference to a member function defined by
/// \c DSMASTERHANDLERDEFN.
///
/// Used in the constructor of \c rosa::deluxe::DeluxeSensor to initialize super
/// class \c rosa::Agent with member function defined by \c DSMASTERHANDLERDEFN.
///
/// \see \c DSMASTERHANDLERDEFN, \c THISMEMBER
///
/// \param N name suffix for the function identifier
#define DSMASTERHANDLERREF(N) THISMEMBER(DSMASTERHANDLERNAME(N))
///@}
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; the actual value in
/// \c rosa::deluxe::DeluxeSensor::MasterInputNextPos is valid with respect to
/// the corresponding types.
///
/// \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:
/// The type of values produced by \p this object.
///
/// That is the types of values \p this object sends to its *master* in a
/// \c rosa::deluxe::DeluxeTuple.
///
/// \see \c rosa::deluxe::DeluxeSensor::master
const Token OutputType;
/// The type of values \p this object processes from its *master*.
///
/// That is the types of values \p this object receives from its *master* in a
/// \c rosa::deluxe::DeluxeTuple.
///
/// \see \c rosa::deluxe::DeluxeSensor::master
const Token MasterInputType;
private:
/// Indicates which element of the master-input is expected from the *master*.
///
/// The *master* is supposed to send one \c rosa::deluxe::DeluxeTuple value
/// element by element in their order of definition. This member field tells
/// the element at which position should be received next.
///
/// \p this object is supposed to be triggered only when a complete
/// master-input has been received, that is the field should hold the value
/// `0`.
///
/// \see \c rosa::deluxe::DeluxeSensor::handleTrigger
/// \c rosa::deluxe::DeluxeSensor::saveMasterInput
token_size_t MasterInputNextPos;
/// Indicates whether the input value from the *master* has been changed since
/// the last trigger received from the system.
///
/// The flag is reset to \c false upon handling a trigger and then set to \c
/// true by \c rosa::deluxe::DeluxeSensor::saveMasterInput when storig a new
/// input value in \c rosa::deluxe::DeluxeSensor::MasterInputValue.
bool MasterInputChanged;
/// Stores the actual input value from *master*.
///
/// \note The type of the stored value matches the types indicated by \c
/// rosa::deluxe::DeluxeSensor::MasterInputType.
const std::unique_ptr<AbstractTokenizedStorage> MasterInputValue;
/// 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 and master-input processing function are
/// captured in lambda expressions that are in turn wrapped in \c
/// std::function objects. The lambda expression calls a processing function,
/// either to handle master-input or obtain the next sensory value from data
/// source. The next sensory value is sent it to *master* by calling \c
/// rosa::deluxe::DeluxeSensor::sendToMaster. Also, the flag \c
/// rosa::deluxe::DeluxeSensor::MasterInputChanged is reset when the current
/// value is passed to the master-input processing function. The function \c
/// rosa::deluxe::DeluxeSensor::handleTrigger needs only to call the proper
/// function object.
/// Processes master-input.
///
/// \ingroup DeluxeSensorTriggerHandlers
///
/// The function is called upon the sensor is trigged by the system.
const H MFP;
/// Produces the next sensory value 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;
/// Produces the next sensory value 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;
/// Tells the unique identifier of the *master* of \p this object, if any
/// registered.
///
/// \return the unique identifier of the *master*
///
/// \pre A *master* is registered for \p this object: \code
/// Master
/// \endcode
id_t masterId(void) const noexcept;
/// Wraps a master-input processing function into a trigger handler.
///
/// \see \c rosa::deluxe::DeluxeSensor::MFP and \c DeluxeSensorTriggerHandlers
///
/// \tparam Ts types of elements of master-input processed by \p MF
/// \tparam S0 indices for accessing master-input values
///
/// \param MF function that processes master-input
///
/// \note The second argument provides indices statically as template
/// arguments \p S0..., so its actual value is ignored.
///
/// \note A master-input type of \c rosa::deluxe::EmptyDeluxeTuple indicates
/// that \p this object does not receive master-input, \p MF is never called
/// if \p Ts is empty.
///
/// \return trigger handler function based on \p MF
///
/// \pre Statically, the indices match the elements: \code
/// sizeof...(Ts) == sizeof...(S0)
/// \endcode Dynamically, \p Ts... match \c
/// rosa::deluxe::DeluxeSensor::MasterInputType: \code
/// MasterInputType == DeluxeTuple<Ts...>::TT
/// \endcode
template <typename... Ts, size_t... S0>
H triggerHandlerFromProcessingFunction(
std::function<void(std::pair<DeluxeTuple<Ts...>, bool>)> &&MF,
Seq<S0...>) noexcept;
/// Wraps a data source function into a trigger handler.
///
/// \see \c rosa::deluxe::DeluxeSensor::FP, \c
/// rosa::deluxe::DeluxeSensor::SFP, and \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
///
/// \return trigger handler function based on \p F
///
/// \pre Statically, the type agument \p T is an instance of \c
/// rosa::deluxe::DeluxeTuple: \code
/// IsDeluxeTuple<T>::Value
/// \endcode Dynamically, \p T matches \c
/// rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == T::TT
/// \endcode
template <typename T>
H triggerHandlerFromDataSource(std::function<T(void)> &&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 \p F and \p MF do not potentially throw exception.
///
/// \tparam MT type of master-input handled by \p MF
/// \tparam T type of data to operate on
///
/// \note Instantiation fails if any of the type arguments \p MT and \p T is
/// not an instance of \c rosa::deluxe::DeluxeTuple or \p T is \c
/// rosa::deluxe::EmptyDeluxeTuple.
///
/// \note If \p MT is \c rosa::deluxe::EmptyDeluxeTuple, the constructed
/// object does not receive master-input.
///
/// \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 MF function to process master-input values with
/// \param F function to generate the next value with during normal operation
///
/// \pre Statically, \p MT and \p T are instances of \c
/// rosa::deluxe::DeluxeTuple and \p T contains at least one element:\code
/// TypeListAllDeluxeTuple<TypeList<MT, T>>::Value && T::Length > 0
/// \endcode
/// Dynamically, the instance is created as of kind
/// \c rosa::deluxe::atoms::SensorKind:
/// \code
/// Kind == rosa::deluxe::atoms::SensorKind
/// \endcode
///
/// \see \c rosa::deluxe::DeluxeTuple
template <
typename MT, typename T,
typename = std::enable_if_t<
TypeListAllDeluxeTuple<TypeList<MT, T>>::Value && (T::Length > 0)>>
DeluxeSensor(const AtomValue Kind, const id_t Id, const std::string &Name,
MessagingSystem &S,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&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*.
///
/// \note Any call to \c rosa::deluxe::DeluxeSensor::registerMaster should be
/// paired with a corresponding call of \c
/// rosa::deluxe::DeluxeAgent::registerSlave, which validates that
/// input/output types of master and slave matches.
///
/// \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 Ts types of elements of values provided by \p SF
///
/// \param SF function to generate value with
///
/// \pre \p Ts... match \c rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeToken<Ts...>::Value
/// \endcode
template <typename... Ts>
void registerSimulationDataSource(
std::function<DeluxeTuple<Ts...>(void)> &&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.
///
/// The elements from \p Value are sent one by one in separate messages to the
/// *master*.
///
/// \tparam Ts types of the elements in \p Value
/// \tparam S0 indices for accessing elements of \p Value
///
/// \param Value value to send
///
/// \note The second argument provides indices statically as template
/// arguments \p S0..., so its actual value is ignored.
///
/// \pre Statically, the indices match the elements: \code
/// sizeof...(Ts) == sizeof...(S0)
/// \endcode Dynamically, \p Ts match \c
/// rosa::deluxe::DeluxeSensor::OutputType: \code
/// OutputType == TypeToken<Ts...>::Value
/// \endcode
template <typename... Ts, size_t... S0>
void sendToMaster(const DeluxeTuple<Ts...> &Value, Seq<S0...>) noexcept;
/// Handles master-input and generates the next sensory value upon trigger
/// from the system.
///
/// Executes \c rosa::deluxe::DeluxeSensor::MFP for processing master-input
/// and data generating function \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.
///
/// \pre Master-input is supposed to be completely received upon triggering:
/// \code
/// MasterInputNextPos == 0
/// \endcode
void handleTrigger(atoms::Trigger) noexcept;
/// Stores a new input value from the *master*.
///
/// The function stores \p Value at position \p Pos in \c
/// rosa::deluxe::DeluxeSensor::MasterInputValue and also sets the
/// flag \c rosa::deluxe::DeluxeSensor::MasterInputChanged. The function also
/// takes care of checking and updating \c
/// rosa::deluxe::DeluxeSensor::MasterInputNextPos: increments its value and
/// resets it to `0` when the last element is received.
///
/// \note Utilized by member functions of group \c
/// DeluxeSensorMasterInputHandlers.
///
/// \tparam T type of input to store
///
/// \param Id unique identifier of the *master*
/// \param Pos position of the value in the \c rosa::deluxe::DeluxeTuple
/// \param Value the input value to store
///
/// \pre The *master* with \p Id is registered, \p Pos is the expected
/// position of master-input, and the input from the *master* at position \p
/// Pos is expected to be of type \p T: \code
/// Master && masterId() == Id && Pos == MasterInputNextPos &&
/// typeAtPositionOfToken(MasterInputType, Pos) == TypeNumberOf<T>::Value
/// \endcode
template <typename T>
void saveMasterInput(id_t Id, token_size_t Pos, T Value) noexcept;
/// \defgroup DeluxeSensorMasterInputHandlers Master-input handlers of
/// rosa::deluxe::DeluxeSensor
///
/// Definition of member functions handling messages from the *master* with
/// different types of input
///
/// A *slave* generally needs to be prepared to deal with values of any
/// built-in type to handle messages from its *master*. Each type requires a
/// separate message handler, which are implemented by these functions. The
/// functions instantiate \c rosa::deluxe::DeluxeSensor::saveMasterInput 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
/// DSMASTERHANDLERDEF.
///
/// \note Keep these definitions in sync with \c rosa::BuiltinTypes.
///
///@{
DSMASTERHANDLERDEF(AtomValue)
DSMASTERHANDLERDEF(int16_t)
DSMASTERHANDLERDEF(int32_t)
DSMASTERHANDLERDEF(int64_t)
DSMASTERHANDLERDEF(int8_t)
DSMASTERHANDLERDEFN(long double, long_double)
DSMASTERHANDLERDEFN(std::string, std__string)
DSMASTERHANDLERDEF(uint16_t)
DSMASTERHANDLERDEF(uint32_t)
DSMASTERHANDLERDEF(uint64_t)
DSMASTERHANDLERDEF(uint8_t)
DSMASTERHANDLERDEF(unit_t)
DSMASTERHANDLERDEF(bool)
DSMASTERHANDLERDEF(double)
DSMASTERHANDLERDEF(float)
/// @}
};
template <typename... Ts, size_t... S0>
DeluxeSensor::H DeluxeSensor::triggerHandlerFromProcessingFunction(
std::function<void(std::pair<DeluxeTuple<Ts...>, bool>)> &&MF,
Seq<S0...>) noexcept {
using MT = DeluxeTuple<Ts...>;
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
ASSERT(MasterInputType == MT::TT);
// NOTE: Clang 6 warns about unused lambda captures; we suppress that
// warning (those variables need to be captured).
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-lambda-capture"
#endif // defined __clang__
return [ this, MF ](void) noexcept {
// Do not do anything for master-input type \c
// rosa::deluxe::EmptyDeluxeTuple.
if constexpr (!std::is_same<MT, EmptyDeluxeTuple>::value) {
LOG_TRACE_STREAM << "DeluxeSensor " << FullName
<< " handles master-input." << std::endl;
// The assert must hold if \p this object was successfuuly constructed.
ASSERT((true && ... &&
(static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)));
const auto MasterInputArg = std::make_pair(
// Get all elements of the tuple in a fold expression.
DeluxeTuple<Ts...>(*static_cast<const Ts *>(
MasterInputValue->pointerTo(static_cast<token_size_t>(S0)))...),
MasterInputChanged);
MasterInputChanged = false;
MF(MasterInputArg);
}
};
#ifdef __clang__
#pragma clang diagnostic pop
#endif // defined __clang__
}
template <typename T>
DeluxeSensor::H
DeluxeSensor::triggerHandlerFromDataSource(std::function<T(void)> &&F,
bool inSimulation) noexcept {
STATIC_ASSERT(IsDeluxeTuple<T>::Value, "not tuple type argument");
ASSERT(OutputType == T::TT);
return [ this, F, inSimulation ](void) noexcept {
// Get value and send it to master only if \p ExecutionPolicy allows it.
if (ExecutionPolicy->shouldProcess({})) {
LOG_TRACE_STREAM << "DeluxeSensor " << Name << " obtains next value."
<< std::endl;
sendToMaster(F(), seq_t<T::Length>());
} else {
LOG_TRACE_STREAM << "DeluxeSensor " << Name << " skips next value."
<< std::endl;
if (inSimulation) {
// But read input value in Simulation anyway as input values are
// provided for the highest execution frequency for simulation
- F();
+ (void)F();
}
}
};
}
template <typename MT, typename T, typename>
DeluxeSensor::DeluxeSensor(const AtomValue Kind, const id_t Id,
const std::string &Name, MessagingSystem &S,
std::function<void(std::pair<MT, bool>)> &&MF,
std::function<T(void)> &&F) noexcept
: Agent(Kind, Id, Name, S, THISMEMBER(handleTrigger),
DSMASTERHANDLERREF(AtomValue), DSMASTERHANDLERREF(int16_t),
DSMASTERHANDLERREF(int32_t), DSMASTERHANDLERREF(int64_t),
DSMASTERHANDLERREF(int8_t), DSMASTERHANDLERREF(long_double),
DSMASTERHANDLERREF(std__string), DSMASTERHANDLERREF(uint16_t),
DSMASTERHANDLERREF(uint32_t), DSMASTERHANDLERREF(uint64_t),
DSMASTERHANDLERREF(uint8_t), DSMASTERHANDLERREF(unit_t),
DSMASTERHANDLERREF(bool), DSMASTERHANDLERREF(double),
DSMASTERHANDLERREF(float)),
ExecutionPolicy(DeluxeExecutionPolicy::decimation(1)), OutputType(T::TT),
MasterInputType(MT::TT), MasterInputChanged(false),
MasterInputValue(new typename TokenizedStorageForTypeList<
typename UnwrapDeluxeTuple<MT>::Type>::Type()),
MFP(triggerHandlerFromProcessingFunction(std::move(MF),
seq_t<MT::Length>())),
FP(triggerHandlerFromDataSource(std::move(F), false)), SFP(nullptr) {
ASSERT(Kind == atoms::SensorKind);
LOG_TRACE_STREAM << "DeluxeSensor " << FullName << " is created."
<< std::endl;
ASSERT(inv());
}
template <typename... Ts>
void DeluxeSensor::registerSimulationDataSource(
std::function<DeluxeTuple<Ts...>(void)> &&SF) noexcept {
ASSERT(OutputType == TypeToken<Ts...>::Value);
SFP = triggerHandlerFromDataSource(std::move(SF), true);
ASSERT(inv());
}
template <typename... Ts, size_t... S0>
void DeluxeSensor::sendToMaster(const DeluxeTuple<Ts...> &Value,
Seq<S0...>) noexcept {
STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0), "inconsistent arguments");
ASSERT(OutputType == TypeToken<Ts...>::Value);
// The assert must hold if \p this object was successfuuly constructed.
ASSERT((true && ... &&
(static_cast<size_t>(static_cast<token_size_t>(S0)) == S0)));
// Create a static constant array for these indices to be available as lvalue
// references when creating messages below. \c S0... when used directly in a
// fold expression is a temporary value, which would result in \c
// rosa::Message instances being created with rvalue references. Further, all
// other values would to copied into a temporary variable for making them
/// available as rvalue references (they are constant lvalue references here).
static constexpr std::array<token_size_t, sizeof...(S0)> Indices{{S0...}};
LOG_TRACE_STREAM << "DeluxeSensor " << FullName << "(" << Id
<< ") sends to master("
<< static_cast<bool>(Master && *Master) << "): " << Value
<< std::endl;
// There is a handle and the referred *master* is in a valid state.
if (Master && *Master) {
// Handle each element of the tuple in a fold expression.
(Master->sendMessage(Message::create(atoms::Slave::Value, Id, Indices[S0],
std::get<S0>(Value))),
...);
}
ASSERT(inv());
}
template <typename T>
void DeluxeSensor::saveMasterInput(id_t Id, token_size_t Pos,
T Value) noexcept {
ASSERT(Master && masterId() == Id && Pos == MasterInputNextPos &&
typeAtPositionOfToken(MasterInputType, Pos) == TypeNumberOf<T>::Value);
LOG_TRACE_STREAM << "DeluxeSensor " << FullName << "(" << Id
<< ") saves value from master: (" << static_cast<size_t>(Pos)
<< ") " << Value << std::endl;
// Save value.
*static_cast<T *>(MasterInputValue->pointerTo(Pos)) = Value;
// Update position of next value.
if (++MasterInputNextPos == lengthOfToken(MasterInputType)) {
MasterInputNextPos = 0;
}
// Set flag.
MasterInputChanged = true;
}
} // End namespace deluxe
} // End namespace rosa
#undef DSMASTERHANDLEREF
#undef DSMASTERHANDLEDEF
#undef DSMASTERHANDLEDEFN
#undef DSMASTERHANDLENAME
#endif // ROSA_DELUXE_DELUXESENSOR_HPP
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Fri, Jul 4, 5:03 AM (14 h, 25 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157466
Default Alt Text
(39 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment