Page MenuHomePhorge

No OneTemporary

Size
81 KB
Referenced Files
None
Subscribers
None
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

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)

Event Timeline