Page MenuHomePhorge

No OneTemporary

Size
36 KB
Referenced Files
None
Subscribers
None
diff --git a/docs/Issues.rst b/docs/Issues.rst
index 1e5a920..3f2a4b9 100755
--- a/docs/Issues.rst
+++ b/docs/Issues.rst
@@ -1,45 +1,54 @@
==================================================================
Known Issues with the Current Implementation of the RoSA Framework
==================================================================
.. contents::
:local:
TODO
====
* Project logo - `docs/_themes/rosa-theme/static/logo.png`
* License?
* Packaging with
`CPack <https://cmake.org/cmake/help/latest/module/CPack.html>`_.
* What about design documentation on the basics of RoSA?
* What about testing the framework?
Known Issues
============
* CMake
* VS2017 generates intermediate files for the `ZERO_CHECK` project out of the
build directory, see `CMake issue #16458`_.
* C++
* Mangled names of function pointers with non-throwing exception specification
in function signature will change in C++17. That renders binaries generated
with C++14 and C++17 incompatible (for linking).
* Since version 4.0.0, Clang warns about this compatibility issue as part
of `-Wc++1z-compat`. That warning is turned off in the build scripts.
* The langauge standard for building RoSA libraries and applications needs
to be lockstepped: now use C++14 only and step to C++17 later when it is
properly supported by all major compilers.
* Doxygen
* There are some strange warnings reported by doxygen when generating
documentation.
* There are some entities for which no or partial documentation is generated,
but no indication of any problem is reported by doxygen.
+* clang-tidy
+
+ * Clang-tidy reports warnings about `noexcept` marking for the move
+ constructor and move assignment operator of `rosa::Optional` in some
+ situations when the template with the non-specialized argument list is used
+ -- for example, in the file `example/deluxe-interface/deluxe-interface.cpp`.
+ However, the condition for the `noexcept` marking should be met and the
+ warning is pointless.
+
.. _CMake issue #16458: https://gitlab.kitware.com/cmake/cmake/issues/16458
diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt
index f39a687..276f940 100644
--- a/examples/CMakeLists.txt
+++ b/examples/CMakeLists.txt
@@ -1,7 +1,8 @@
# Add the different subdirectories
add_subdirectory(basic-system)
add_subdirectory(type-facilities)
add_subdirectory(messaging)
add_subdirectory(messaging-system)
add_subdirectory(agent-modules)
+add_subdirectory(deluxe-interface)
diff --git a/examples/deluxe-interface/CMakeLists.txt b/examples/deluxe-interface/CMakeLists.txt
new file mode 100755
index 0000000..7b5017b
--- /dev/null
+++ b/examples/deluxe-interface/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_executable(deluxe-interface deluxe-interface.cpp)
+ROSA_add_library_dependencies(deluxe-interface ROSAConfig)
+ROSA_add_library_dependencies(deluxe-interface ROSADeluxe)
+
diff --git a/examples/deluxe-interface/deluxe-interface.cpp b/examples/deluxe-interface/deluxe-interface.cpp
new file mode 100755
index 0000000..6f3b8e2
--- /dev/null
+++ b/examples/deluxe-interface/deluxe-interface.cpp
@@ -0,0 +1,312 @@
+//===-- 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/agent/Abstraction.hpp"
+#include "rosa/agent/Confidence.hpp"
+
+#include "rosa/config/version.h"
+
+#include "rosa/deluxe/DeluxeContext.hpp"
+
+#include "rosa/support/csv/CSVReader.hpp"
+#include "rosa/support/csv/CSVWriter.hpp"
+
+#include <fstream>
+
+using namespace rosa;
+using namespace rosa::agent;
+using namespace rosa::deluxe;
+using namespace rosa::terminal;
+
+/// Paths for the CSV files for simulation.
+///
+///@{
+const std::string HRCSVPath = "HR.csv";
+const std::string BRCSVPath = "BR.csv";
+const std::string SpO2CSVPath = "SpO2.csv";
+const std::string BPSysCSVPath = "BPSys.csv";
+const std::string BodyTempCSVPath = "BodyTemp.csv";
+const std::string ScoreCSVPath = "Score.csv";
+///@}
+
+/// How many cycles of simulation to perform.
+const size_t NumberOfSimulationCycles = 16;
+
+/// Warning levels for abstraction.
+enum WarningScore { No = 0, Low = 1, High = 2, Emergency = 3 };
+
+/// Helper function creating a deluxe agent for pre-processing sensory values.
+///
+/// Received values are first validated for confidence. Values which the
+/// validator does not mark confident are ignored. Confident values are
+/// abstracted into a \c WarningScore value, which is the result of the
+/// processing function.
+///
+/// \note The result, \c WarningScore, is returned as \c uint32_t because
+/// enumeration types are not integrated into built-in types. Hence, a master
+/// to these agents receives its input as \c uint32_t values, and may cast them
+/// to \c WarningScore explicitly.
+///
+/// \tparam T type of values to receive from the sensor
+///
+/// \param C the deluxe context to create the agent in
+/// \param Name name of the new agent
+/// \param CC confidence validator to use
+/// \param A abstraction to use
+///
+/// \return handle for the new agent
+template <typename T>
+AgentHandle createLowLevelAgent(std::unique_ptr<DeluxeContext> &C,
+ const std::string &Name,
+ const Confidence<T> &CC,
+ const Abstraction<T, WarningScore> &A) {
+ using handler = DeluxeAgent::D<uint32_t, T>;
+ using result = Optional<uint32_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.second && CC(I.first)) ? result(A(I.first)) : result();
+ }));
+}
+
+int main(void) {
+ LOG_INFO_STREAM
+ << '\n'
+ << library_string() << " -- " << Color::Red << "deluxe-interface example"
+ << Color::Default << '\n'
+ << Color::Yellow
+ << "CSV files are read from and written to the current working directory."
+ << 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 HRSensor = C->createSensor<int32_t>("HR Sensor");
+ AgentHandle BRSensor = C->createSensor<int32_t>("BR Sensor");
+ AgentHandle SpO2Sensor = C->createSensor<int32_t>("SpO2 Sensor");
+ AgentHandle BPSysSensor = C->createSensor<int32_t>("BPSys Sensor");
+ AgentHandle BodyTempSensor = C->createSensor<float>("BodyTemp Sensor");
+
+ //
+ // Create functionalities.
+ //
+ LOG_INFO("Creating Functionalities for Agents.");
+
+ //
+ // Define confidence validators.
+ //
+ // Lower bounds are inclusive and upper bounds are exclusive.
+
+ Confidence<int32_t> HRConfidence(0, 501);
+ Confidence<int32_t> BRConfidence(0, 301);
+ Confidence<int32_t> SpO2Confidence(0, 101);
+ Confidence<int32_t> BPSysConfidence(0,501);
+ Confidence<float> BodyTempConfidence(-60,
+ nextRepresentableFloatingPoint(50.0f));
+
+ //
+ // Define abstractions.
+ //
+
+ RangeAbstraction<int32_t, WarningScore> HRAbstraction(
+ {{{0, 40}, Emergency},
+ {{40, 51}, High},
+ {{51, 60}, Low},
+ {{60, 100}, No},
+ {{100, 110}, Low},
+ {{110, 129}, High},
+ {{129, 200}, Emergency}},
+ Emergency);
+
+ RangeAbstraction<int32_t, WarningScore> BRAbstraction({{{0, 9}, High},
+ {{9, 14}, No},
+ {{14, 20}, Low},
+ {{20, 29}, High},
+ {{29, 50}, Emergency}},
+ Emergency);
+
+ RangeAbstraction<int32_t, WarningScore> SpO2Abstraction({{{1, 85}, Emergency},
+ {{85, 90}, High},
+ {{90, 95}, Low},
+ {{95, 100}, No}},
+ Emergency);
+
+ RangeAbstraction<int32_t, WarningScore> BPSysAbstraction(
+ {{{0, 70}, Emergency},
+ {{70, 81}, High},
+ {{81, 101}, Low},
+ {{101, 149}, No},
+ {{149, 169}, Low},
+ {{169, 179}, High},
+ {{179, 200}, Emergency}},
+ Emergency);
+
+ RangeAbstraction<float, WarningScore> BodyTempAbstraction(
+ {{{0, 28}, Emergency},
+ {{28, 32}, High},
+ {{32, 35}, Low},
+ {{35, 38}, No},
+ {{38, 39.5}, High},
+ {{39.5, 100}, Emergency}},
+ Emergency);
+
+ //
+ // Create low-level deluxe agents with \c createLowLevelAgent.
+ //
+ LOG_INFO("Creating low-level agents.");
+
+ AgentHandle HRAgent =
+ createLowLevelAgent(C, "HR Agent", HRConfidence, HRAbstraction);
+ AgentHandle BRAgent =
+ createLowLevelAgent(C, "BR Agent", BRConfidence, BRAbstraction);
+ AgentHandle SpO2Agent =
+ createLowLevelAgent(C, "SpO2 Agent", SpO2Confidence, SpO2Abstraction);
+ AgentHandle BPSysAgent =
+ createLowLevelAgent(C, "BPSys Agent", BPSysConfidence, BPSysAbstraction);
+ AgentHandle BodyTempAgent = createLowLevelAgent(
+ C, "BodyTemp Agent", BodyTempConfidence, BodyTempAbstraction);
+
+ //
+ // Connect sensors to low-level agents.
+ //
+ LOG_INFO("Connect sensors to their corresponding low-level agents.");
+
+ C->connectSensor(HRAgent, 0, HRSensor, "HR Sensor Channel");
+ C->connectSensor(BRAgent, 0, BRSensor, "BR Sensor Channel");
+ C->connectSensor(SpO2Agent, 0, SpO2Sensor, "SpO2 Sensor Channel");
+ C->connectSensor(BPSysAgent, 0, BPSysSensor, "BPSys Sensor Channel");
+ C->connectSensor(BodyTempAgent, 0, BodyTempSensor, "BodyTemp 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 BodyAgent = C->createAgent(
+ "Body Agent",
+ DeluxeAgent::D<uint32_t, uint32_t, uint32_t, uint32_t, uint32_t,
+ uint32_t>(
+ [](std::pair<uint32_t, bool> HR, std::pair<uint32_t, bool> BR,
+ std::pair<uint32_t, bool> SpO2, std::pair<uint32_t, bool> BPSys,
+ std::pair<uint32_t, bool> BodyTemp) -> Optional<uint32_t> {
+ LOG_INFO_STREAM << "\n*******\nBody Agent trigged with values:\n"
+ << (HR.second ? "<New>" : "<Old>")
+ << " HR warning score: " << HR.first << "\n"
+ << (BR.second ? "<New>" : "<Old>")
+ << " BR warning score: " << BR.first << "\n"
+ << (SpO2.second ? "<New>" : "<Old>")
+ << " SpO2 warning score: " << SpO2.first << "\n"
+ << (BPSys.second ? "<New>" : "<Old>")
+ << " BPSys warning score: " << BPSys.first << "\n"
+ << (BodyTemp.second ? "<New>" : "<Old>")
+ << " BodyTemp warning score: " << BodyTemp.first
+ << "\n******\n";
+ return {HR.first + BR.first + SpO2.first + BPSys.first +
+ BodyTemp.first};
+ }));
+
+ //
+ // Connect low-level agents to the high-level agent.
+ //
+ LOG_INFO("Connect low-level agents to the high-level agent.");
+
+ C->connectAgents(BodyAgent, 0, HRAgent, "HR Agent Channel");
+ C->connectAgents(BodyAgent, 1, BRAgent, "BR Agent Channel");
+ C->connectAgents(BodyAgent, 2, SpO2Agent, "SpO2 Agent Channel");
+ C->connectAgents(BodyAgent, 3, BPSysAgent, "BPSys Agent Channel");
+ C->connectAgents(BodyAgent, 4, BodyTempAgent, "BodyTemp Agent Channel");
+
+ //
+ // For simulation output, create a logger agent writing the output of the
+ // high-level agent into a CSV file.
+ //
+ LOG_INFO("Create a logger agent.");
+
+ // Create CSV writer.
+ std::ofstream ScoreCSV(ScoreCSVPath);
+ csv::CSVWriter<uint32_t> ScoreWriter(ScoreCSV);
+
+ // The agent writes each new input value into a CSV file and produces nothing.
+ AgentHandle LoggerAgent = C->createAgent(
+ "Logger Agent",
+ DeluxeAgent::D<unit_t, uint32_t>(
+ [&ScoreWriter](std::pair<uint32_t, bool> Score) -> Optional<unit_t> {
+ if (Score.second) {
+ // The state of \p ScoreWriter is not checked, expecting good.
+ ScoreWriter << Score.first;
+ }
+ 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, BodyAgent, "Body Agent Channel");
+
+ //
+ // Do simulation.
+ //
+ LOG_INFO("Setting up and performing simulation.");
+
+ //
+ // Initialize deluxe context for simulation.
+ //
+
+ C->initializeSimulation();
+
+ //
+ // Open CSV files and register them for their corresponding sensors.
+ //
+
+ // Type aliases for iterators.
+ using CSVInt = csv::CSVFlatIterator<int32_t>;
+ using CSVFloat = csv::CSVFlatIterator<float>;
+
+ std::ifstream HRCSV(HRCSVPath);
+ C->registerSensorValues(HRSensor, CSVInt(HRCSV), CSVInt());
+
+ std::ifstream BRCSV(BRCSVPath);
+ C->registerSensorValues(BRSensor, CSVInt(BRCSV), CSVInt());
+
+ std::ifstream SpO2CSV(SpO2CSVPath);
+ C->registerSensorValues(SpO2Sensor, CSVInt(SpO2CSV), CSVInt());
+
+ std::ifstream BPSysCSV(BPSysCSVPath);
+ C->registerSensorValues(BPSysSensor, CSVInt(BPSysCSV), CSVInt());
+
+ std::ifstream BodyTempCSV(BodyTempCSVPath);
+ C->registerSensorValues(BodyTempSensor, CSVFloat(BodyTempCSV), CSVFloat());
+
+ //
+ // Simulate.
+ //
+
+ C->simulate(NumberOfSimulationCycles);
+
+ return 0;
+}
diff --git a/include/rosa/support/csv/CSVReader.hpp b/include/rosa/support/csv/CSVReader.hpp
new file mode 100755
index 0000000..cd625b4
--- /dev/null
+++ b/include/rosa/support/csv/CSVReader.hpp
@@ -0,0 +1,373 @@
+//===-- rosa/support/csv/CSVReader.hpp --------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file rosa/support/csv/CSVReader.hpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2017
+///
+/// \brief Facitilities to read CSV files.
+///
+/// \note The implementation is based on the solution at
+/// https://stackoverflow.com/a/1120224
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ROSA_SUPPORT_CSV_CSVREADER_HPP
+#define ROSA_SUPPORT_CSV_CSVREADER_HPP
+
+#include "rosa/support/debug.hpp"
+
+#include <istream>
+#include <sstream>
+#include <vector>
+
+namespace rosa {
+namespace csv {
+
+/// Anonymous namespace providing implementation details for
+/// \c rosa::csv::CSVIterator, consider it private.
+namespace {
+
+/// Provides facility for parsing values from one row CSV data.
+///
+/// \tparam T type of values to parse from the line
+/// \tparam IsSignedInt if \p T is a signed integral type, always use default
+/// \tparam IsUnsignedInt if \p T is an unsigned integral type, always use
+/// default
+/// \tparam IsFloat if \p T is a floating-point type, always use default
+/// \tparam IsString if \p T is \c std::string, always use default
+///
+/// \note Specializations of this `struct` are provided for arithmentic types
+/// and \c std::string.
+template <typename T, bool IsSignedInt = (std::is_integral<T>::value &&
+ std::is_signed<T>::value),
+ bool IsUnsignedInt =
+ (std::is_integral<T>::value && std::is_unsigned<T>::value),
+ bool IsFloat = std::is_floating_point<T>::value,
+ bool IsString = std::is_same<T, std::string>::value>
+struct CSVRowParser;
+
+/// Specialization for signed integral types.
+///
+/// \tparam T type of values to parse from the line
+///
+/// \pre \p T is a signed integral type:\code
+/// std::is_integral<T>::value && std::is_signed<T>::value
+/// \code
+template <typename T> struct CSVRowParser<T, true, false, false, false> {
+ STATIC_ASSERT((std::is_integral<T>::value && std::is_signed<T>::value),
+ "wrong type"); // Sanity check.
+
+ /// Parses a given row of CSV data into a given container.
+ ///
+ /// \p Data is cleared and then filled with values parsed from \p LineStream.
+ /// Entries in the line are to be separated by commas, the character `,`. A
+ /// trailing comma results in an empty entry at the end of the line. No empty
+ /// entry should be present otherwise.
+ ///
+ /// \param [in,out] LineStream the line to parse
+ /// \param [in,out] Data the container to store the parsed values
+ static void parse(std::stringstream &LineStream, std::vector<T> &Data) {
+ std::string Cell;
+ Data.clear();
+ while (std::getline(LineStream, Cell, ',')) {
+ Data.push_back(std::stoll(Cell));
+ }
+ // This checks for a trailing comma with no data after it.
+ if (!LineStream && Cell.empty()) {
+ // If there was a trailing comma then add an empty element.
+ Data.push_back(0);
+ }
+ }
+};
+
+/// Specialization for unsigned integral types.
+///
+/// \tparam T type of values to parse from the line
+///
+/// \pre \p T is an unsigned integral type:\code
+/// std::is_integral<T>::value && std::is_unsigned<T>::value
+/// \code
+template <typename T> struct CSVRowParser<T, false, true, false, false> {
+ STATIC_ASSERT((std::is_integral<T>::value && std::is_unsigned<T>::value),
+ "wrong type"); // Sanity check.
+
+ /// Parses a given row of CSV data into a given container.
+ ///
+ /// \p Data is cleared and then filled with values parsed from \p LineStream.
+ /// Entries in the line are to be separated by commas, the character `,`. A
+ /// trailing comma results in an empty entry at the end of the line. No empty
+ /// entry should be present otherwise.
+ ///
+ /// \param [in,out] LineStream the line to parse
+ /// \param [in,out] Data the container to store the parsed values
+ static void parse(std::stringstream &LineStream, std::vector<T> &Data) {
+ std::string Cell;
+ Data.clear();
+ while (std::getline(LineStream, Cell, ',')) {
+ Data.push_back(std::stoull(Cell));
+ }
+ // This checks for a trailing comma with no data after it.
+ if (!LineStream && Cell.empty()) {
+ // If there was a trailing comma then add an empty element.
+ Data.push_back(0);
+ }
+ }
+};
+
+/// Specialization for floating-point types.
+///
+/// \tparam T type of values to parse from the line
+///
+/// \pre \p T is a floating-point type:\code
+/// std::is_floating_point<T>::value
+/// \code
+template <typename T> struct CSVRowParser<T, false, false, true, false> {
+ STATIC_ASSERT((std::is_floating_point<T>::value),
+ "wrong type"); // Sanity check.
+
+ /// Parses a given row of CSV data into a given container.
+ ///
+ /// \p Data is cleared and then filled with values parsed from \p LineStream.
+ /// Entries in the line are to be separated by commas, the character `,`. A
+ /// trailing comma results in an empty entry at the end of the line. No empty
+ /// entry should be present otherwise.
+ ///
+ /// \param [in,out] LineStream the line to parse
+ /// \param [in,out] Data the container to store the parsed values
+ static void parse(std::stringstream &LineStream, std::vector<T> &Data) {
+ std::string Cell;
+ Data.clear();
+ while (std::getline(LineStream, Cell, ',')) {
+ Data.push_back(std::stold(Cell));
+ }
+ // This checks for a trailing comma with no data after it.
+ if (!LineStream && Cell.empty()) {
+ // If there was a trailing comma then add an empty element.
+ Data.push_back(0);
+ }
+ }
+};
+
+/// Specialization for \c std::string.
+///
+/// \tparam T type of values to parse from the line
+///
+/// \pre \p T is \c std::string:\code
+/// std::is_same<T, std::string>::value
+/// \code
+template <typename T> struct CSVRowParser<T, false, false, false, true> {
+ STATIC_ASSERT((std::is_same<T, std::string>::value),
+ "wrong type"); // Sanity check.
+
+ /// Parses a given row of CSV data into a given container.
+ ///
+ /// \p Data is cleared and then filled with values parsed from \p LineStream.
+ /// Entries in the line are to be separated by commas, the character `,`. A
+ /// trailing comma results in an empty entry at the end of the line. No empty
+ /// entry should be present otherwise.
+ ///
+ /// \param [in,out] LineStream the line to parse
+ /// \param [in,out] Data the container to store the parsed values
+ static void parse(std::stringstream &LineStream, std::vector<T> &Data) {
+ std::string Cell;
+ Data.clear();
+ while (std::getline(LineStream, Cell, ',')) {
+ Data.push_back(Cell);
+ }
+ // This checks for a trailing comma with no data after it.
+ if (!LineStream && Cell.empty()) {
+ // If there was a trailing comma then add an empty element.
+ Data.push_back("");
+ }
+ }
+};
+
+/// Parses and stores entries from a row of CSV data.
+///
+/// \tparam T type of values to parse and store, i.e. entries in the row
+///
+/// \note The implementation relies on \c rosa::csv::CSVRowParser, which is
+/// implemented only for `arithmetic` types -- signed and unsigned integral and
+/// floating-point types -- and for \c std::string. Those are the valid values
+/// for \p T.
+template <typename T>
+class CSVRow {
+public:
+ /// Gives a constant reference for an entry at a given position of the row.
+ ///
+ /// \note No bounds checking is performed.
+ ///
+ /// \param Index the position of the entry
+ ///
+ /// \return constant reference for the stored entry at position \p Index
+ const T &operator[](const size_t Index) const noexcept {
+ return Data[Index];
+ }
+
+ /// Tells the number of entries stored in the row.
+ ///
+ /// \return number of stored entries.
+ size_t size(void) const noexcept { return Data.size(); }
+
+ /// Parses and stores one row of CSV data.
+ ///
+ /// The function reads one line from \p Str and parses it into
+ /// \c rosa::csv::CSVRow::Data using \c rosa::csv::CSVRowParser.
+ ///
+ /// \param [in,out] Str input stream of a CSV file
+ void readNextRow(std::istream &Str) {
+ std::string Line;
+ std::getline(Str, Line);
+ std::stringstream LineStream(Line);
+ CSVRowParser<T>::parse(LineStream, Data);
+ }
+
+private:
+ std::vector<T> Data; ///< Stores parsed entries
+};
+
+/// Reads a row of CSV data into \c rosa::csv::CSVRow.
+///
+/// The next line is read from \p Str by calling
+/// \c rosa::csv::CSVRow::readNextRow on \p Data.
+///
+/// \note A CSV file should contain no empty lines.
+///
+/// \param [in,out] Str input stream of a CSV file
+/// \param [in,out] Data object to read the next line into
+///
+/// \return \p Str after reading one line from it
+template <typename T>
+std::istream &operator>>(std::istream &Str, CSVRow<T> &Data) {
+ Data.readNextRow(Str);
+ return Str;
+}
+
+} // End namespace
+
+/// Provides `InputIterator` features for iterating over a CSV file in a
+/// flat way.
+///
+/// The iterator hides rows of the CSV file, and iterates over the entries
+/// row-by-row.
+///
+/// \note A CSV file should contain no empty lines.
+///
+/// \tparam T type of values to iterate over, i.e. entries in the CSV file.
+///
+/// \note The implementation relies on \c rosa::csv::CSVRow, which in turn
+/// relies on \c rosa::csv::CSVRowParser, which is implemented only for
+/// `arithmetic` types -- signed and unsigned integral types and floating-point
+/// types -- and for \c std::string. Those are the valid values for \p T.
+template <typename T>
+class CSVFlatIterator {
+public:
+ /// \defgroup CSVIteratorTypedefs
+ ///
+ /// Standard `typedef`s for iterators.
+ ///
+ ///@{
+ typedef std::input_iterator_tag
+ iterator_category; ///< Category of the iterator.
+ typedef T value_type; ///< Type of values iterated over.
+ typedef std::size_t difference_type; ///< Type to identify distance.
+ typedef T *pointer; ///< Pointer to the type iterated over.
+ typedef T &reference; ///< Reference to the type iterated over.
+ ///@}
+
+ /// Creates a new instance.
+ ///
+ /// \param [in,out] S input stream to iterate over
+ CSVFlatIterator(std::istream &S) : Str(S.good() ? &S : nullptr) { ++(*this); }
+
+ /// Creates an empty new instance.
+ CSVFlatIterator(void) noexcept : Str(nullptr) {}
+
+ /// Pre-increment operator.
+ ///
+ /// The implementation moves over the entries in the current row and advances
+ /// to the next row when the end of the current row is reached. If the end of
+ /// the input stream is reached, the operator becomes empty and has no
+ /// further effect.
+ ///
+ /// \return \p this object after incrementing it.
+ CSVFlatIterator &operator++() {
+ if (Pos < Row.size()) {
+ ++Pos;
+ } else if (Str) {
+ if (!((*Str) >> Row)) {
+ Str = nullptr;
+ } else {
+ Pos = 0;
+ }
+ }
+ return *this;
+ }
+
+ /// Post-increment operator.
+ ///
+ /// The implementation uses the pre-increment operator and returns a copy of
+ /// the original state of \p this object.
+ ///
+ /// \return \p this object before incrementing it.
+ CSVFlatIterator operator++(int) {
+ CSVFlatIterator Tmp(*this);
+ ++(*this);
+ return Tmp;
+ }
+
+ /// Returns a constant reference to the current entry.
+ ///
+ /// \note Should not dereference the iterator when it is empty.
+ ///
+ /// \return constant reference to the current entry.
+ const T &operator*(void)const noexcept {
+ return Row[Pos];
+ }
+
+ /// Returns a constant pointer to the current entry.
+ ///
+ /// \note Should not dereference the iterator when it is empty.
+ ///
+ /// \return constant pointer to the current entry.
+ const T *operator->(void)const noexcept { return &Row[Pos]; }
+
+ /// Tells if \p this object is equal to another one.
+ ///
+ /// Two \c rosa::csv::CSVReader instances are equal if and only if they are
+ /// the same or both are empty.
+ ///
+ /// \param RHS other object to compare to
+ ///
+ /// \return whether \p this object is equal with \p RHS
+ bool operator==(const CSVFlatIterator &RHS) const noexcept {
+ return ((this == &RHS) || ((this->Str == nullptr) && (RHS.Str == nullptr)));
+ }
+
+ /// Tells if \p this object is not equal to another one.
+ ///
+ /// \see rosa::csv::CSVReader::operator==
+ ///
+ /// \param RHS other object to compare to
+ ///
+ /// \return whether \p this object is not equal with \p RHS.
+ bool operator!=(const CSVFlatIterator &RHS) const noexcept {
+ return !((*this) == RHS);
+ }
+
+private:
+ std::istream *Str; ///< Input stream of a CSV file to iterate over.
+ CSVRow<T> Row; ///< Content of the current row iterating over.
+ size_t Pos; ///< Current position within the current row.
+};
+
+} // End namespace csv
+} // End namespace rosa
+
+#endif // ROSA_SUPPOR_CSV_CSVREADER_HPP
diff --git a/include/rosa/support/csv/CSVWriter.hpp b/include/rosa/support/csv/CSVWriter.hpp
new file mode 100755
index 0000000..17046a4
--- /dev/null
+++ b/include/rosa/support/csv/CSVWriter.hpp
@@ -0,0 +1,99 @@
+//===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file rosa/support/csv/CSVWriter.hpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2017
+///
+/// \brief Facitilities to write CSV files.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ROSA_SUPPORT_CSV_CSVWRITER_HPP
+#define ROSA_SUPPORT_CSV_CSVWRITER_HPP
+
+#include <ostream>
+
+namespace rosa {
+namespace csv {
+
+/// Provides facilities to write values into a CSV file.
+///
+/// The writer emits a comma, the character `,`, between each written values.
+/// The resulted stream is a flat CSV file as it consists of onlyone row, no new
+/// line is emitted.
+///
+/// \tparam T type of values to write
+template <typename T>
+class CSVWriter {
+public:
+ /// Creates a new instance.
+ ///
+ /// \param [in,out] S output stream to write to
+ ///
+ /// \note The writer operates on non-binary outputs as long as \p S is in
+ /// good state.
+ CSVWriter(std::ostream &S)
+ : Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr),
+ IsFirst(true) {}
+
+ /// Tells if the last operation was successful.
+ ///
+ /// \return if the last operation was successful
+ bool good(void) const noexcept {
+ return Str != nullptr;
+ }
+
+ /// Writes an entry to the output stream.
+ ///
+ /// The implementation does anything only if the last operation was
+ /// successful. If so, \p V is written to \c rosa::csv::CSVWriter::Str.
+ /// The emitted value is preceded with a comma if the actual call is not the
+ /// first one for \p this object. Success of the operation is checked at the
+ /// end.
+ ///
+ /// \param V value to write
+ void write(const T &V) {
+ if (Str) {
+ if (!IsFirst) {
+ *Str << ',';
+ } else {
+ IsFirst = false;
+ }
+ *Str << V;
+ if (!Str->good()) {
+ Str = nullptr;
+ }
+ }
+ }
+
+private:
+ std::ostream *Str; ///< Output stream to write to.
+ bool IsFirst; ///< Denotes if the next write would be the first one.
+};
+
+/// Writes a value to a CSV file with \c rosa::csv::CSVWriter.
+///
+/// \see rosa::csv::CSVWriter
+///
+/// \tparam T type of value to write
+///
+/// \param [in,out] W object to write with
+/// \param [in,out] V value to write
+///
+/// \return \p W after writing \p V with it
+template <typename T>
+CSVWriter<T> &operator<<(CSVWriter<T> &W, const T& V) {
+ W.write(V);
+ return W;
+}
+
+} // End namespace csv
+} // End namespace rosa
+
+#endif // ROSA_SUPPORT_CSV_CSVWRITER_HPP
diff --git a/include/rosa/support/csv/namespace.h b/include/rosa/support/csv/namespace.h
new file mode 100755
index 0000000..85ad49e
--- /dev/null
+++ b/include/rosa/support/csv/namespace.h
@@ -0,0 +1,25 @@
+//===-- rosa/support/csv/namespace.h ----------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file rosa/support/csv/namespace.h
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2017
+///
+/// \brief Documentation for the namespace \c rosa::csv.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ROSA_SUPPORT_CSV_NAMESPACE_H
+#define ROSA_SUPPORT_CSV_NAMESPACE_H
+
+namespace rosa {
+/// Provides facilities to work with CSV files.
+namespace csv {}
+} // End namespace rosa
+
+#endif // ROSA_SUPPORT_CSV_NAMESPACE_H
diff --git a/include/rosa/support/math.hpp b/include/rosa/support/math.hpp
index 768079f..f88a13d 100644
--- a/include/rosa/support/math.hpp
+++ b/include/rosa/support/math.hpp
@@ -1,35 +1,57 @@
//===-- rosa/support/math.hpp -----------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/math.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Math helpers.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_MATH_HPP
#define ROSA_SUPPORT_MATH_HPP
+#include <cmath>
#include <cstdlib>
+#include <limits>
+#include <type_traits>
namespace rosa {
/// Computes log base 2 of a number.
///
/// \param N the number to compute log base 2 for
///
/// \return log base 2 of \p N
constexpr size_t log2(const size_t N) {
return ((N < 2) ? 1 : 1 + log2(N / 2));
}
+/// Tells the next representable floating point value.
+///
+/// \tparam T type to operate on
+///
+/// \note The second type argument enforces \p T being a floating point type,
+/// always use the default value!
+///
+/// \param V value to which find the next representable one
+///
+/// \return the next representable value of type \p T after value \p V
+///
+/// \pre Type \p T must be a floating point type, which is enforced by
+/// `std::enable_if` in the second type argument.
+template <typename T,
+ typename = std::enable_if_t<std::is_floating_point<T>::value>>
+T nextRepresentableFloatingPoint(const T V) {
+ return std::nextafter(V, std::numeric_limits<T>::infinity());
+}
+
} // End namespace rosa
#endif // ROSA_SUPPORT_MATH_HPP
diff --git a/lib/support/CMakeLists.txt b/lib/support/CMakeLists.txt
index 1a7ea9b..6e191ef 100644
--- a/lib/support/CMakeLists.txt
+++ b/lib/support/CMakeLists.txt
@@ -1,32 +1,38 @@
set(LIB_INCLUDE_DIR ${ROSA_MAIN_INCLUDE_DIR}/rosa/support)
add_library(ROSASupport
${LIB_INCLUDE_DIR}/debug.hpp
debug.cpp
${LIB_INCLUDE_DIR}/terminal_colors.h
terminal_colors.cpp
${LIB_INCLUDE_DIR}/log.h
log.cpp
${LIB_INCLUDE_DIR}/math.hpp
math.cpp
${LIB_INCLUDE_DIR}/type_helper.hpp
type_helper.cpp
${LIB_INCLUDE_DIR}/types.hpp
types.cpp
${LIB_INCLUDE_DIR}/atom.hpp
atom.cpp
${LIB_INCLUDE_DIR}/type_pair.hpp
type_pair.cpp
${LIB_INCLUDE_DIR}/type_list.hpp
type_list.cpp
${LIB_INCLUDE_DIR}/squashed_int.hpp
squashed_int.cpp
${LIB_INCLUDE_DIR}/type_numbers.hpp
type_numbers.cpp
${LIB_INCLUDE_DIR}/type_token.hpp
type_token.cpp
${LIB_INCLUDE_DIR}/tokenized_storages.hpp
tokenized_storages.cpp
${LIB_INCLUDE_DIR}/sequence.hpp
sequence.cpp
+ ${LIB_INCLUDE_DIR}/csv/namespace.h
+ csv/namespace.cpp
+ ${LIB_INCLUDE_DIR}/csv/CSVReader.hpp
+ csv/CSVReader.cpp
+ ${LIB_INCLUDE_DIR}/csv/CSVWriter.hpp
+ csv/CSVWriter.cpp
)
diff --git a/lib/support/csv/CSVReader.cpp b/lib/support/csv/CSVReader.cpp
new file mode 100755
index 0000000..bf055fb
--- /dev/null
+++ b/lib/support/csv/CSVReader.cpp
@@ -0,0 +1,20 @@
+//===-- support/csv/CSVReader.cpp -------------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file support/csv/CSVReader.cpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2017
+///
+/// \brief Implementation for rosa/support/csv/CSVReader.hpp.
+///
+/// \note Empty implementation, source file here to have a compile database
+/// entry for rosa/support/csv/CSVReader.hpp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "rosa/support/csv/CSVReader.hpp"
diff --git a/lib/support/csv/CSVWriter.cpp b/lib/support/csv/CSVWriter.cpp
new file mode 100755
index 0000000..4310703
--- /dev/null
+++ b/lib/support/csv/CSVWriter.cpp
@@ -0,0 +1,20 @@
+//===-- support/csv/CSVWriter.cpp -------------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file support/csv/CSVWriter.cpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2017
+///
+/// \brief Implementation for rosa/support/csv/CSVWriter.hpp.
+///
+/// \note Empty implementation, source file here to have a compile database
+/// entry for rosa/support/csv/CSVWriter.hpp.
+///
+//===----------------------------------------------------------------------===//
+
+#include "rosa/support/csv/CSVWriter.hpp"
diff --git a/lib/support/csv/namespace.cpp b/lib/support/csv/namespace.cpp
new file mode 100755
index 0000000..744e6c1
--- /dev/null
+++ b/lib/support/csv/namespace.cpp
@@ -0,0 +1,20 @@
+//===-- support/csv/namespace.cpp -------------------------------*- C++ -*-===//
+//
+// The RoSA Framework
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file support/csv/namespace.cpp
+///
+/// \author David Juhasz (david.juhasz@tuwien.ac.at)
+///
+/// \date 2017
+///
+/// \brief Placeholder for rosa/support/csv/namespace.h.
+///
+/// \note Empty implementation, source file here to have a compile database
+/// entry for rosa/support/csv/namespace.h.
+///
+//===----------------------------------------------------------------------===//
+
+#include "rosa/support/csv/namespace.h"

File Metadata

Mime Type
text/x-diff
Expires
Sat, Mar 15, 3:08 PM (1 d, 1 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
129088
Default Alt Text
(36 KB)

Event Timeline