Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F386520
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Size
81 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/apps/sa-ews1/sa-ews1.cpp b/apps/sa-ews1/sa-ews1.cpp
index 67a1ac6..23b02b8 100644
--- a/apps/sa-ews1/sa-ews1.cpp
+++ b/apps/sa-ews1/sa-ews1.cpp
@@ -1,316 +1,316 @@
//===-- apps/sa-ews1/sa-ews1.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application SA-EWS1
//
//===----------------------------------------------------------------------===//
///
/// \file apps/sa-ews1/sa-ews1.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief The application SA-EWS1 implements the case study from the paper:
/// M. Götzinger, N. Taherinejad, A. M. Rahmani, P. Liljeberg, A. Jantsch, and
/// H. Tenhunen: Enhancing the Early Warning Score System Using Data Confidence
/// DOI: 10.1007/978-3-319-58877-3_12
//===----------------------------------------------------------------------===//
#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;
const std::string AppName = "SA-EWS1";
/// 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 << AppName << "app"
<< 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(AppName);
//
// 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.f, 28.f}, Emergency},
{{28.f, 32.f}, High},
{{32.f, 35.f}, Low},
{{35.f, 38.f}, No},
{{38.f, 39.5f}, High},
{{39.5f, 100.f}, 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>;
+ using CSVInt = csv::CSVIterator<int32_t>;
+ using CSVFloat = csv::CSVIterator<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/examples/CSVFiles/CMakeLists.txt b/examples/CSVFiles/CMakeLists.txt
index fe4cdb3..cfc92e7 100644
--- a/examples/CSVFiles/CMakeLists.txt
+++ b/examples/CSVFiles/CMakeLists.txt
@@ -1,3 +1,3 @@
add_executable(csvfiles main.cpp)
ROSA_add_library_dependencies(csvfiles ROSAConfig)
-ROSA_add_library_dependencies(csvfiles ROSASupport)
+ROSA_add_library_dependencies(csvfiles ROSADeluxe)
diff --git a/examples/CSVFiles/main.cpp b/examples/CSVFiles/main.cpp
index 6ca7342..23f3955 100644
--- a/examples/CSVFiles/main.cpp
+++ b/examples/CSVFiles/main.cpp
@@ -1,328 +1,328 @@
//===-- apps/sa-ews1/sa-ews1.cpp --------------------------------*- C++ -*-===//
//
// The RoSA Framework -- Application SA-EWS1
//
//===----------------------------------------------------------------------===//
///
/// \file apps/sa-ews1/sa-ews1.cpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \brief The application SA-EWS1 implements the case study from the paper:
/// M. Götzinger, N. Taherinejad, A. M. Rahmani, P. Liljeberg, A. Jantsch, and
/// H. Tenhunen: Enhancing the Early Warning Score System Using Data Confidence
/// DOI: 10.1007/978-3-319-58877-3_12
//===----------------------------------------------------------------------===//
#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;
const std::string AppName = "Test-CSVFiles";
/// Paths for the CSV files for simulation.
///
///@{
//const std::string HRCSVPath = "HR.csv";
const std::string HRCSVPathOld = "HR-New.csv";
const std::string HRCSVPath = "HR-New-Semicolon.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 << AppName << "app"
<< 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(AppName);
//
// 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.f, 28.f}, Emergency},
{{28.f, 32.f}, High},
{{32.f, 35.f}, Low},
{{35.f, 38.f}, No},
{{38.f, 39.5f}, High},
{{39.5f, 100.f}, 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.
//parseparse
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>;
+ using CSVInt = csv::CSVIterator<int32_t>;
+ using CSVFloat = csv::CSVIterator<float>;
//std::ifstream HRCSV(HRCSVPath);
//CSVInt testIt(HRCSV);
/* std::ifstream HRCSV(HRCSVPath);
C->registerSensorValues(HRSensor, CSVInt(HRCSV, 5, false, ';', '\n'), CSVInt()); */
std::ifstream HRCSVOld(HRCSVPathOld);
- C->registerSensorValues(HRSensor, CSVInt(HRCSVOld, 2), CSVInt());
+ C->registerSensorValues(HRSensor, CSVInt(HRCSVOld/*, 2*/), CSVInt());
/*
std::ifstream BRCSV(HRCSVPath);
C->registerSensorValues(BRSensor, CSVInt(BRCSV, 4, false, ';', '\n'), CSVInt()); */
std::ifstream SpO2CSV(HRCSVPath);
- C->registerSensorValues(SpO2Sensor, CSVInt(SpO2CSV, 2, false, ';', '\n'), CSVInt());
+ C->registerSensorValues(SpO2Sensor, CSVInt(SpO2CSV/*, 2, false, ';', '\n'*/), CSVInt());
/*
std::ifstream BPSysCSV(BPSysCSVPath);
C->registerSensorValues(BPSysSensor, CSVInt(BPSysCSV), CSVInt());*/
std::ifstream BodyTempCSV(HRCSVPath);
- C->registerSensorValues(BodyTempSensor, CSVFloat(BodyTempCSV, 2, false, ';', '\n'), CSVFloat());
+ C->registerSensorValues(BodyTempSensor, CSVFloat(BodyTempCSV/*, 2, false, ';', '\n'*/), CSVFloat());
//
// Simulate.
//
C->simulate(NumberOfSimulationCycles);
return 0;
}
diff --git a/include/rosa/deluxe/DeluxeContext.hpp b/include/rosa/deluxe/DeluxeContext.hpp
index 29794a1..646e866 100755
--- a/include/rosa/deluxe/DeluxeContext.hpp
+++ b/include/rosa/deluxe/DeluxeContext.hpp
@@ -1,294 +1,333 @@
//===-- 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,
WrongPosition,
AlreadyHasSlave,
AlreadyHasMaster,
AlreadyHasValueStream
};
/// 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
///
+ /// \todo The current implementation is an intermediate state, handles
+ /// built-in types and std::tuple, but the latter with with one element only.
+ /// Fix it when merging with DeluxeTuple.
+ ///
/// \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;
/// 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;
}
+/// Anonymous namespace for helper facilities, consider it private.
+namespace {
+
+/// \todo Document...
+template <typename T> struct UnwrapSensorType { using Type = T; };
+
+template <typename... Ts> struct UnwrapSensorType<std::tuple<Ts...>> {
+ using Type = typename std::tuple_element<0, std::tuple<Ts...>>::type;
+};
+
+} // End namespace
+
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");
+ constexpr bool isBuiltin = TypeListContains<BuiltinTypes, T>::Value;
+ if constexpr (!isBuiltin) {
+ // T must be a std::tuple.
+ STATIC_ASSERT(std::tuple_size<T>::value == 1, "Wrong tuple type");
+ STATIC_ASSERT(
+ (TypeListContains<BuiltinTypes,
+ typename std::tuple_element<0, T>::type>::Value),
+ "Wrong element type in tuple");
+ }
+ using TT = typename UnwrapSensorType<T>::Type;
// 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) {
+ if (S->OutputType != TypeNumberOf<TT>::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 {
+ DeluxeSensor::D<TT>([=](void) mutable noexcept {
if (Start != End) {
+ TT Value;
+ if constexpr (isBuiltin) {
+ Value = *Start;
+ } else {
+ Value = std::get<0>(*Start);
+ }
+ ++Start;
LOG_TRACE_STREAM << "Reading next value for sensor '" << S->FullName
- << "': " << *Start << '\n';
- return *Start++;
+ << "': " << Value << '\n';
+ return Value;
} else {
+ TT Value;
+ if constexpr (isBuiltin) {
+ Value = Default;
+ } else {
+ Value = std::get<0>(Default);
+ }
LOG_TRACE_STREAM << "Providing default value for sensor '"
- << S->FullName << "': " << Default << '\n';
- return Default;
+ << S->FullName << "': " << Value << '\n';
+ return Value;
}
}));
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/support/csv/CSVReader.hpp b/include/rosa/support/csv/CSVReader.hpp
index 6fbdd46..45c6e20 100755
--- a/include/rosa/support/csv/CSVReader.hpp
+++ b/include/rosa/support/csv/CSVReader.hpp
@@ -1,1108 +1,307 @@
//===-- rosa/support/csv/CSVReader.hpp --------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/csv/CSVReader.hpp
///
/// \authors David Juhasz (david.juhasz@tuwien.ac.at), Edwin Willegger (edwin.willegger@tuwien.ac.at)
///
/// \date 2017-2019
///
/// \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 "rosa/support/sequence.hpp"
#include <istream>
#include <sstream>
#include <vector>
#include <map>
#include <algorithm>
#include <set>
-
namespace rosa {
namespace csv {
/// Indicating it the CSV file contains any header or not
enum class HeaderInformation {
HasHeader,
HasNoHeader
};
/// Anonymous namespace providing implementation details for
/// \c rosa::csv::CSVIterator, consider it private.
-namespace {
+namespace {
-/// Provides facility for parsing values from one row CSV data.
+/// Provides facility for parsing one value from a string.
///
-/// \tparam T type of values to parse from the line
+/// \tparam T type of value to parse
/// \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
+/// \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),
+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
-/// \endcode
-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.
+struct ValueParser {
- /// 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.
///
- /// \note Parsed values are silently converted to type \p T.
+ /// \param Cell the \c std::string to parse
///
- /// \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, char Delimeter = ',') {
- std::string Cell;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- Data.push_back(static_cast<T>(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);
- }
- }
-
- /// Parses a given column of a given row of CSV data into a given container.
+ /// \return the parsed value
///
- /// \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.
- ///
- /// \note Parsed values are silently converted to type \p T.
- ///
- /// \param [in,out] LineStream the line to parse
- /// \param [in,out] Data the container to store the parsed values
- static void parseValue(std::stringstream &LineStream, std::vector<T> &Data, size_t Column = 0, char Delimeter = ',') {
- std::string Cell;
- size_t currentColumn = 0;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- if(currentColumn == Column){
- Data.push_back(static_cast<T>(std::stoll(Cell)));
- break;
- }
- currentColumn = currentColumn + 1;
- }
- // 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);
- }
- }
+ /// \note The function silently fails if cannot parse \p Cell for type \p T.
+ static T parse(const std::string &Cell) noexcept;
};
-/// 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
-/// \endcode
-template <typename T> struct CSVRowParser<T, false, true, false, false> {
- STATIC_ASSERT((std::is_integral<T>::value && std::is_unsigned<T>::value),
+template <typename T>
+struct ValueParser<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.
- ///
- /// \note Parsed values are silently converted to type \p T.
- ///
- /// \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, char Delimeter = ',') {
- std::string Cell;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- Data.push_back(static_cast<T>(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);
- }
+ static T parse(const std::string &Cell) noexcept {
+ return static_cast<T>(std::stoll(Cell));
}
+};
- /// Parses a given column of 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.
- ///
- /// \note Parsed values are silently converted to type \p T.
- ///
- /// \param [in,out] LineStream the line to parse
- /// \param [in,out] Data the container to store the parsed values
- static void parseValue(std::stringstream &LineStream, std::vector<T> &Data, size_t Column = 0, char Delimeter = ',') {
- std::string Cell;
- size_t currentColumn = 0;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- if(currentColumn == Column){
- Data.push_back(static_cast<T>(std::stoll(Cell)));
- break;
- }
- currentColumn = currentColumn + 1;
- }
- // 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);
- }
+template <typename T>
+struct ValueParser<T, false, true, false, false> {
+ STATIC_ASSERT((std::is_integral<T>::value && std::is_unsigned<T>::value),
+ "wrong type"); // Sanity check.
+ static T parse(const std::string &Cell) noexcept {
+ return static_cast<T>(std::stoull(Cell));
}
};
-/// 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
-/// \endcode
-template <typename T> struct CSVRowParser<T, false, false, true, false> {
+template <typename T>
+struct ValueParser<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.
- ///
- /// \note Parsed values are silently converted to type \p T.
- ///
- /// \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, char Delimeter = ',') {
- std::string Cell;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- Data.push_back(static_cast<T>(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);
- }
- }
-
- /// Parses a given column of 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.
- ///
- /// \note Parsed values are silently converted to type \p T.
- ///
- /// \param [in,out] LineStream the line to parse
- /// \param [in,out] Data the container to store the parsed values
- static void parseValue(std::stringstream &LineStream, std::vector<T> &Data, size_t Column = 0, char Delimeter = ',') {
- std::string Cell;
- size_t currentColumn = 0;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- if(currentColumn == Column){
- Data.push_back(static_cast<T>(std::stold(Cell)));
- break;
- }
- currentColumn = currentColumn + 1;
- }
- // 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);
- }
+ static T parse(const std::string &Cell) noexcept {
+ return static_cast<T>(std::stold(Cell));
}
};
-/// 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
-/// \endcode
-template <typename T> struct CSVRowParser<T, false, false, false, true> {
+template <typename T>
+struct ValueParser<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, char Delimeter = ',') {
- std::string Cell;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- 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 a given column of 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.
- ///
- /// \note Parsed values are silently converted to type \p T.
- ///
- /// \param [in,out] LineStream the line to parse
- /// \param [in,out] Data the container to store the parsed values
- static void parseValue(std::stringstream &LineStream, std::vector<T> &Data, size_t Column = 0, char Delimeter = ',') {
- std::string Cell;
- size_t currentColumn = 0;
- Data.clear();
- while (std::getline(LineStream, Cell, Delimeter)) {
- if(currentColumn == Column){
- Data.push_back(static_cast<T>(std::stoll(Cell)));
- break;
- }
- currentColumn = currentColumn + 1;
- }
- // 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);
- }
- }
+ static T parse(const std::string &Cell) noexcept { return Cell; }
};
-
-/// generic basic class for specialization of the function
-/// it is not allowed to derive partial special functions from function templates
-/// so thats the reason for this workaround.
-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 CSVTupleRowParser;
-
- template <typename T>struct CSVTupleRowParser <T, true, false, false, false> {
- STATIC_ASSERT((std::is_integral<T>::value && std::is_signed<T>::value), "wrong type");
- static T parseValue(const std::string &Cell) noexcept {
- return static_cast<T>(std::stoll(Cell));
- }
- };
-
-
/// 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
+/// \tparam Ts types 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... Ts>
-class CSVRow {
-public:
- CSVRow() : isHeaderRead(false), Delimeter(','),
- EndOfLine(','), Column(1){}
-
- /// Gives a constant reference for an entry at a given position of the row.
+/// 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 Ts.
+template <typename... Ts> class CSVRow {
+private:
+ /// Parses a given row of CSV data into \c CSVRow::Data.
///
- /// \note No bounds checking is performed.
+ /// \ CSVRow::Data is filled with values parsed from \p LineStream. Entries
+ /// in the line are to be separated by commas, the character `,`.
///
- /// \param Index the position of the entry
+ /// \note Parsed values are silently converted to types \p Ts.
///
- /// \return constant reference for the stored entry at position \p Index
- //const T &operator[](const size_t Index) const noexcept { return Data[Index]; }
-
- template<size_t... S0>
- void parseRow(std::stringstream &LineStream, Seq<S0...>){
- STATIC_ASSERT(sizeof... (Ts) == sizeof... (S0),
- "Not matching template arguments.");
-
- std::string Cell;
- // Get fields and parse the values into the proper element of the tuple one
- // by one in a fold expression.
- ((std::getline(LineStream, Cell, ','),
- std::get<S0>(Data) = CSVTupleRowParser<Ts>::parseValue(((Cell)), ...)));
- }
-
- /// Tells the number of entries stored in the row.
+ /// \note Parsing silently fails if values do not match \p Ts.
///
- /// \return number of stored entries.
- //size_t size(void) const noexcept { return Data.size(); }
-
- /// Parses and stores one row of CSV data.
+ /// \tparam S0 indices to access tuple elements.
///
- /// 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] LineStream the line to parse
///
- /// \param [in,out] Str input stream of a CSV file
- template<size_t... S0>
- void readNextRow(std::istream &Str) {
- std::string Line;
- std::getline(Str, Line);
- std::stringstream LineStream(Line);
-
- RowNumber = RowNumber + 1;
- parseRow(LineStream, typename GenSeq<sizeof...(S0)>::Type());
-
- // typename GenSeq<sizeof...(As)>::Type;
- //CSVRowParser<T>::parse(LineStream, Data, Delimeter);
- }
-
- bool isNumeric(const std::string& input){
- return std::all_of(input.begin(), input.end(), ::isdigit);
- }
-
- void readHeaderRow(std::istream &Str){
- std::string Line;
- std::getline(Str, Line);
- std::stringstream LineStream(Line);
-
- CSVRowParser<std::string>::parse(LineStream, Header, Delimeter);
-
- RowNumber = RowNumber + 1;
- isHeaderRead = true;
- }
-
- inline bool isHeaderAlreadyRead(){
- return isHeaderRead;
- }
-
-
- HeaderInformation isHeaderSet(){
- return HeaderInfo;
- }
-
- inline void setDelimeter(char Delimeter){
- this->Delimeter = Delimeter;
- }
-
- inline char getDelimeter(){
- return this->Delimeter;
- }
-
- inline void setEndOfLine(char EndOfLine){
- this->EndOfLine = EndOfLine;
- }
-
- inline char getEndOfLine(){
- return this->EndOfLine;
- }
-
- inline bool isThisFirstRow(){
- return this->isFirstRow;
- }
-
- inline void setColumn(const size_t & Column){
- this->Column = Column;
- }
-
- inline void setHeaderInfo(const HeaderInformation HeaderInfo){
- this->HeaderInfo = HeaderInfo;
- }
-
- inline void setSkipRows(const size_t &SkipRows){
- this->SkipRows = SkipRows;
- }
-
- inline const size_t & getSkipRows(){
- return this->SkipRows;
- }
-
- inline uint64_t getRowNumber(){
- return this->RowNumber;
- }
-
- inline const std::tuple<Ts...> &tuple(void) const noexcept {
- return Data;
+ /// \note The last argument is used only to get \p S0, the actual value of
+ /// the parameter is ignored.
+ template <size_t... S0>
+ void parseRow(std::stringstream &LineStream, Seq<S0...>) {
+ STATIC_ASSERT(sizeof...(Ts) == sizeof...(S0),
+ "Not matching template arguments.");
+ std::string Cell;
+ // Get fields and parse the values into the proper element of the tuple
+ // one by one in a fold expression.
+ ((std::getline(LineStream, Cell, ','),
+ std::get<S0>(Data) = ValueParser<Ts>::parse(Cell)),
+ ...);
}
-private:
- std::tuple<Ts...> Data; ///< Stores parsed entries
- uint64_t RowNumber; ///< Current row number
- std::vector<std::string> Header; ///< Stores the header entries if available
- char Delimeter; ///< Stores the delimeter between data entries
- char EndOfLine; ///< Stores the end of line character
- size_t Column; ///< Stores the column to get the data out of the row
- HeaderInformation HeaderInfo; ///< Indicates if CSV file contains a header row (expected first row to be the header).
- size_t SkipRows; ///< Number of Rows to skip at the beginning of the file.
- bool isHeaderRead; ///< Indicates if header was read
-};
-
-/// Parses and stores entries from a row of CSV data.
-/// It parses an entire row and takes only the value of the corresponding column.
-///
-/// \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 CSVValue {
public:
- CSVValue() : isHeaderRead(false), Delimeter(','),
- EndOfLine(','), Column(0), RowNumber(0) { }
-
- /// 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 readNextValue(std::istream &Str) {
+ void readNextRow(std::istream &Str) {
std::string Line;
std::getline(Str, Line);
std::stringstream LineStream(Line);
-
- CSVRowParser<T>::parseValue(LineStream, Data, Column, Delimeter);
-
- RowNumber = RowNumber + 1;
- }
-
- bool isNumeric(const std::string& input){
- return std::all_of(input.begin(), input.end(), ::isdigit);
- }
-
- void readHeaderRow(std::istream &Str){
- std::string Line;
- std::getline(Str, Line);
- std::stringstream LineStream(Line);
-
- CSVRowParser<std::string>::parse(LineStream, Header, Delimeter);
-
- isHeaderRead = true;
-
- RowNumber = RowNumber + 1;
- }
-
-
- inline bool isHeaderAlreadyRead(){
- return isHeaderRead;
- }
-
- inline HeaderInformation isHeaderSet(){
- return HeaderInfo;
- }
-
- inline void setDelimeter(char Delimeter){
- this->Delimeter = Delimeter;
- }
-
- inline char getDelimeter(){
- return this->Delimeter;
+ parseRow(LineStream, seq_t<sizeof...(Ts)>());
}
- inline void setEndOfLine(char EndOfLine){
- this->EndOfLine = EndOfLine;
- }
-
- inline char getEndOfLine(){
- return this->EndOfLine;
- }
-
- inline bool isThisFirstRow(){
- return this->isFirstRow;
- }
-
- inline void setColumn(const size_t &Column){
- this->Column = Column;
- }
-
- inline void setHeaderInfo(const HeaderInformation HeaderInfo){
- this->HeaderInfo = HeaderInfo;
- }
-
- inline void setSkipRows(const size_t &SkipRows){
- this->SkipRows = SkipRows;
- }
-
- inline const size_t & getSkipRows(){
- return this->SkipRows;
- }
-
- inline uint64_t getRowNumber(){
- return this->RowNumber;
- }
+ /// Gives a constant references for the \c std::tuple containing the values
+ /// read by \p this object.
+ ///
+ /// \return \c CSVRow::Data
+ const std::tuple<Ts...> &tuple(void) const noexcept { return Data; }
private:
- std::vector<T> Data; ///< Stores parsed entries
- uint64_t RowNumber; ///< Current row number
- std::vector<std::string> Header; ///< Stores the header entries if available
- char Delimeter; ///< Stores the delimeter between data entries
- char EndOfLine; ///< Stores the end of line character
- size_t Column; ///< Stores the column to get the data out of the row
- HeaderInformation HeaderInfo; ///< Indicates if CSV file contains a header row (expected first row to be the header).
- size_t SkipRows; ///< Number of Rows to skip at the beginning of the file.
- bool isHeaderRead; ///< Indicates if header was read
+ std::tuple<Ts...> 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) {
- size_t SkipRowsCorrected = 0;
-
- if (Data.isHeaderSet() == HeaderInformation::HasHeader && !Data.isHeaderAlreadyRead()){
- Data.readHeaderRow(Str);
- }
-
- if (Data.isHeaderSet() == HeaderInformation::HasHeader){
-
- }
-
- SkipRowsCorrected = Data.getSkipRows();
- if (Data.isHeaderSet() == HeaderInformation::HasHeader){
- SkipRowsCorrected = SkipRowsCorrected + 1;
- }
-
- while (Data.getRowNumber() < SkipRowsCorrected){
- Data.readNextRow(Str);
- }
-
- Data.readNextRow(Str);
- /* // just for debugging purpose
- char c;
- while(Str.get(c)){
- std::cout << c;
- }
- std::cout << std::endl;
- */
- return Str;
-}
-
-/// Reads a value of CSV data into \c rosa::csv::CSVValue.
-///
-/// The next line is read from \p Str by calling
-/// \c rosa::csv::CSVValue::readNextValue on \p Data.
-/// If the file contains a header, the first row and the second row
-/// is read, so after the first read always valid data is available.
-///
-/// \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, CSVValue<T> &Data) {
- size_t SkipRowsCorrected = 0;
-
- if (Data.isHeaderSet() == HeaderInformation::HasHeader && !Data.isHeaderAlreadyRead()){
- Data.readHeaderRow(Str);
- }
-
- SkipRowsCorrected = Data.getSkipRows();
- if (Data.isHeaderSet() == HeaderInformation::HasHeader){
- SkipRowsCorrected = SkipRowsCorrected + 1;
- }
-
- while (Data.getRowNumber() < SkipRowsCorrected){
- Data.readNextValue(Str);
- }
-
- Data.readNextValue(Str);
- /* // just for debugging purpose
- char c;
- while(Str.get(c)){
- std::cout << c;
- }
- std::cout << std::endl;
- */
- return Str;
-}
-
-
-
-/// Reads a value of CSV data into \c rosa::csv::CSVValue.
-///
-/// The next line is read from \p Str by calling
-/// \c rosa::csv::CSVValue::readNextValue on \p Data.
-/// If the file contains a header, the first row and the second row
-/// is read, so after the first read always valid data is available.
+/// \tparam Ts type of values to read from the row
///
-/// \note A CSV file should contain no empty lines.
+/// \note The CSV file should contain a line with fields matching \p Ts...
///
/// \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 ... Ts>
+template <typename... Ts>
std::istream &operator>>(std::istream &Str, CSVRow<Ts...> &Data) {
- size_t SkipRowsCorrected = 0;
-
- Data.readNextRow(Str);
- if (Data.isHeaderSet() == HeaderInformation::HasHeader && !Data.isHeaderAlreadyRead()){
- Data.readHeaderRow(Str);
- }
-
- SkipRowsCorrected = Data.getSkipRows();
- if (Data.isHeaderSet() == HeaderInformation::HasHeader){
- SkipRowsCorrected = SkipRowsCorrected + 1;
- }
-
- while (Data.getRowNumber() < SkipRowsCorrected){
- // Data.readNextValue(Str);
- }
-
- //Data.readNextValue(Str);
- /* // just for debugging purpose
- char c;
- while(Str.get(c)){
- std::cout << c;
- }
- std::cout << std::endl;
- */
+ Data.readNextRow(Str);
return Str;
}
-} // End namespace
+} // End namespace
-/// Provides `InputIterator` features for iterating over a CSV file in a
-/// flat way.
+/// Provides `InputIterator` features for iterating over a CSV file.
///
-/// The iterator hides rows of the CSV file, and iterates over the entries
-/// row-by-row.
+/// The iterator parses rows into `std::tuple` values and iterates over the
+/// file row by row.
///
-/// \note A CSV file should contain no empty lines.
+/// \tparam Ts types of values stored in one row of the CSV file
///
-/// \tparam T type of values to iterate over, i.e. entries in the CSV file.
+/// \note The iterator expects each row to consists of fields matching \p Ts.
///
/// \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 {
+/// types -- and for \c std::string. Those are the valid values for \p Ts
+template <typename... Ts> class CSVIterator {
public:
- /// \defgroup CSVFlatIteratorTypedefs Typedefs of rosa::csv::CSVFlatIterator
+ /// \defgroup CSVIteratorTypedefs Typedefs of rosa::csv::CSVIterator
///
/// 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.
+ iterator_category; ///< Category of the iterator.
+ typedef std::tuple<Ts...> value_type; ///< Type of values iterated over.
+ typedef std::size_t difference_type; ///< Type to identify distance.
+ typedef std::tuple<Ts...> *pointer; ///< Pointer to the type iterated over.
+ typedef std::tuple<Ts...>
+ &reference; ///< Reference to the type iterated over.
///@}
/// Creates a new instance.
///
/// \param [in,out] S input stream to iterate over
- CSVFlatIterator(std::istream &S, size_t Column = 0, HeaderInformation HeaderInfo = HeaderInformation::HasHeader,
- bool MultipleRow = true, size_t SkipRows = 0, const char Delimeter = ',', const char EndOfLine = '\n')
- : Str(S.good() ? &S : nullptr),
- Pos(static_cast<size_t>(-1)), Column(Column), HeaderInfo(HeaderInfo),
- MultipleRow(MultipleRow), SkipRows(SkipRows),
- Delimeter(Delimeter), EndOfLine(EndOfLine)
- {
- Row.setHeaderInfo(HeaderInfo);
- Row.setSkipRows(SkipRows);
- Row.setDelimeter(Delimeter);
- Row.setEndOfLine(EndOfLine);
- Row.setColumn(Column);
-
- Value.setHeaderInfo(HeaderInfo);
- Value.setSkipRows(SkipRows);
- Value.setDelimeter(Delimeter);
- Value.setEndOfLine(EndOfLine);
- Value.setColumn(Column);
- // \c rosa::csv::CSVFlatIterator::Pos is initialized to `-1` so the first
- // incrementation here will set it properly.
+ CSVIterator(std::istream &S) : Str(S.good() ? &S : nullptr), Row() {
+ // \c rosa::csv::CSVIterator::Row is initialized empty so the first
+ // incrementation here will read the first row.
++(*this);
}
/// Creates an empty new instance.
- CSVFlatIterator(void) noexcept : Str(nullptr), MultipleRow(true) {}
+ CSVIterator(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.
+ /// The implementation reads the next row. 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++() {
+ CSVIterator &operator++() {
if (Str) {
- ++Pos;
- if(MultipleRow){
- if (Pos == Row.size()) {
- if (!((*Str) >> Row)) {
- Str = nullptr;
- --Pos; // Stay on the last entry forever.
- } else {
- Pos = 0;
- }
- }
- }else{
- if (Pos == Value.size()) {
- if (!((*Str) >> Value)) {
- Str = nullptr;
- --Pos; // Stay on the last entry forever.
- } 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 constanStartt reference to the current entry.
- const T &operator*(void)const noexcept {
- if(MultipleRow){
- return Row[Pos];
- }else {
- return Value[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 {
- if(MultipleRow){
- return &Row[Pos];
- }else {
- return &Value[Pos];
+ if (!((*Str) >> Row)) {
+ Str = nullptr;
}
- }
-
- /// 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);
- }
-
- inline void setDelimeter(char Delimter){
- this->Delimeter = Delimter;
- }
-
- inline char getDelimeter(){
- return this->Delimeter;
- }
-
-private:
- std::istream *Str; ///< Input stream of a CSV file to iterate over.
- CSVRow<T> Row; ///< Content of the current row iterating over.
- CSVValue<T> Value; ///< Content of the specified column in the current row.
- size_t Pos; ///< Current position within the current row.
- char Delimeter; ///< Delimeter between the entries
- char EndOfLine; ///< stores the end of line character
- size_t Column; ///< Index of the column to get data out of it, starts at zero.
- HeaderInformation HeaderInfo; ///< Indicates if CSV file contains a header row (expected first row to be the header).
- bool MultipleRow; ///< Indicates if you want to read a row or only one column out of a row. true = use CSVRow
- size_t SkipRows; ///< Number of Rows to skip at the beginning of the file.
-
-};
-
-
-/// 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... Ts>
-class CSVTupleIterator {
-public:
- /// \defgroup CSVTupleIteratorTypedefs Typedefs of rosa::csv::CSVTupleIterator
- ///
- /// Standard `typedef`s for iterators.
- ///
- ///@{
- typedef std::input_iterator_tag
- iterator_category; ///< Category of the iterator.
- typedef std::tuple<Ts...> value_type; ///< Type of values iterated over.
- typedef std::size_t difference_type; ///< Type to identify distance.
- typedef std::tuple<Ts...> *pointer; ///< Pointer to the type iterated over.
- typedef std::tuple<Ts...> &reference; ///< Reference to the type iterated over.
- ///@}
-
-
- /// Creates a new instance.
- ///
- /// \param [in,out] S input stream to iterate over
-
-
- CSVTupleIterator(std::istream &S, size_t Column = 0, HeaderInformation HeaderInfo = HeaderInformation::HasHeader,
- bool MultipleRow = true, size_t SkipRows = 0, const char Delimeter = ',', const char EndOfLine = '\n')
- : Str(S.good() ? &S : nullptr),
- Pos(static_cast<size_t>(-1)), Column(Column), HeaderInfo(HeaderInfo),
- MultipleRow(MultipleRow), SkipRows(SkipRows),
- Delimeter(Delimeter), EndOfLine(EndOfLine)
- {
- Row.setHeaderInfo(HeaderInfo);
- Row.setSkipRows(SkipRows);
- Row.setDelimeter(Delimeter);
- Row.setEndOfLine(EndOfLine);
- Row.setColumn(Column);
-
- /*Value.setHeaderInfo(HeaderInfo);
- Value.setSkipRows(SkipRows);
- Value.setDelimeter(Delimeter);
- Value.setEndOfLine(EndOfLine);
- Value.setColumn(Column);*/
- // \c rosa::csv::CSVFlatIterator::Pos is initialized to `-1` so the first
- // incrementation here will set it properly.
- ++(*this);
- }
-
-
-
- /// Creates an empty new instance.
- CSVTupleIterator(void) noexcept : Str(nullptr), MultipleRow(true) {}
-
- /// 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.
- CSVTupleIterator &operator++() {
- if (Str) {
- ++Pos;
- if (!((*Str) >> Row)){
- Str = nullptr;
- --Pos;
- }else {
- Pos = 0;
- }
-
- /*
- if(MultipleRow){
- //if (Pos == Row.size()) {
- if (!((*Str) >> Row)) {
- Str = nullptr;
- --Pos; // Stay on the last entry forever.
- } else {
- Pos = 0;
- }
- // }
- }else{
- if (Pos == Value.size()) {
- if (!((*Str) >> Value)) {
- Str = nullptr;
- --Pos; // Stay on the last entry forever.
- } 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.
- CSVTupleIterator operator++(int) {
- CSVTupleIterator Tmp(*this);
+ CSVIterator operator++(int) {
+ CSVIterator Tmp(*this);
++(*this);
return Tmp;
}
/// Returns a constant reference to the current entry.
///
/// \note Should not dereference the iterator when it is empty.
///
- /// \return constanStartt reference to the current entry.
- const std::tuple<Ts...> &operator*(void)const noexcept {
- if(MultipleRow){
- return Row.tuple();
- }else {
- //return Value.tuple();
- }
- }
+ /// \return constant reference to the current entry.
+ const std::tuple<Ts...> &operator*(void)const noexcept { return Row.tuple(); }
/// 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 std::tuple<Ts...> *operator->(void)const noexcept {
- if(MultipleRow){
- return &Row.tuple();
- }else {
- //return &Value.tuple();
- }
+ const std::tuple<Ts...> *operator->(void)const noexcept {
+ return &Row.tuple();
}
/// 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 CSVTupleIterator &RHS) const noexcept {
+ bool operator==(const CSVIterator &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 CSVTupleIterator &RHS) const noexcept {
+ bool operator!=(const CSVIterator &RHS) const noexcept {
return !((*this) == RHS);
}
- inline void setDelimeter(char Delimter){
- this->Delimeter = Delimter;
- }
-
- inline char getDelimeter(){
- return this->Delimeter;
- }
-
private:
- std::istream *Str; ///< Input stream of a CSV file to iterate over.
- CSVRow<Ts...> Row; ///< Content of the current row iterating over.
- //CSVValue<Ts...> Value; ///< Content of the specified column in the current row.
- size_t Pos; ///< Current position within the current row.
- char Delimeter; ///< Delimeter between the entries
- char EndOfLine; ///< stores the end of line character
- size_t Column; ///< Index of the column to get data out of it, starts at zero.
- HeaderInformation HeaderInfo; ///< Indicates if CSV file contains a header row (expected first row to be the header).
- bool MultipleRow; ///< Indicates if you want to read a row or only one column out of a row. true = use CSVRow
- size_t SkipRows; ///< Number of Rows to skip at the beginning of the file.
-
+ std::istream *Str; ///< Input stream of a CSV file to iterate over.
+ CSVRow<Ts...> Row; ///< Content of the current row.
};
} // End namespace csv
} // End namespace rosa
#endif // ROSA_SUPPORT_CSV_CSVREADER_HPP
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Jul 3, 7:35 PM (13 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
157328
Default Alt Text
(81 KB)
Attached To
Mode
R20 SoC_Rosa_repo
Attached
Detach File
Event Timeline
Log In to Comment