Page MenuHomePhorge

No OneTemporary

Size
43 KB
Referenced Files
None
Subscribers
None
diff --git a/include/rosa/support/csv/CSVReader.hpp b/include/rosa/support/csv/CSVReader.hpp
index d21cf07..6fbdd46 100755
--- a/include/rosa/support/csv/CSVReader.hpp
+++ b/include/rosa/support/csv/CSVReader.hpp
@@ -1,829 +1,1108 @@
//===-- 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 {
/// Provides facility for parsing values from one row CSV data.
///
/// \tparam T type of values to parse from the line
/// \tparam IsSignedInt if \p T is a signed integral type, always use default
/// \tparam IsUnsignedInt if \p T is an unsigned integral type, always use
/// default
/// \tparam IsFloat if \p T is a floating-point type, always use default
/// \tparam IsString if \p T is \c std::string, always use default
///
/// \note Specializations of this `struct` are provided for arithmentic types
/// and \c std::string.
template <typename T, bool IsSignedInt = (std::is_integral<T>::value &&
std::is_signed<T>::value),
bool IsUnsignedInt =
(std::is_integral<T>::value && std::is_unsigned<T>::value),
bool IsFloat = std::is_floating_point<T>::value,
bool IsString = std::is_same<T, std::string>::value>
struct CSVRowParser;
/// Specialization for signed integral types.
///
/// \tparam T type of values to parse from the line
///
/// \pre \p T is a signed integral type:\code
/// std::is_integral<T>::value && std::is_signed<T>::value
/// \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.
/// 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::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.
///
/// \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);
}
}
};
/// 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),
"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);
}
}
/// 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);
}
}
};
/// 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> {
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);
}
}
};
/// 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> {
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);
}
}
};
+
+/// 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
///
/// \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>
+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.
///
/// \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]; }
+ //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.
///
/// \return number of stored entries.
- size_t size(void) const noexcept { return Data.size(); }
+ //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
+ template<size_t... S0>
void readNextRow(std::istream &Str) {
std::string Line;
std::getline(Str, Line);
std::stringstream LineStream(Line);
RowNumber = RowNumber + 1;
- CSVRowParser<T>::parse(LineStream, Data, Delimeter);
+ 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;
+ }
+
private:
- std::vector<T> Data; ///< Stores parsed entries
+ 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) {
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;
}
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;
}
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
};
/// 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.
+///
+/// \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 ... 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;
+ */
+ return Str;
+}
} // End namespace
/// Provides `InputIterator` features for iterating over a CSV file in a
/// flat way.
///
/// The iterator hides rows of the CSV file, and iterates over the entries
/// row-by-row.
///
/// \note A CSV file should contain no empty lines.
///
/// \tparam T type of values to iterate over, i.e. entries in the CSV file.
///
/// \note The implementation relies on \c rosa::csv::CSVRow, which in turn
/// relies on \c rosa::csv::CSVRowParser, which is implemented only for
/// `arithmetic` types -- signed and unsigned integral types and floating-point
/// types -- and for \c std::string. Those are the valid values for \p T.
template <typename T>
class CSVFlatIterator {
public:
/// \defgroup CSVFlatIteratorTypedefs Typedefs of rosa::csv::CSVFlatIterator
///
/// Standard `typedef`s for iterators.
///
///@{
typedef std::input_iterator_tag
iterator_category; ///< Category of the iterator.
typedef T value_type; ///< Type of values iterated over.
typedef std::size_t difference_type; ///< Type to identify distance.
typedef T *pointer; ///< Pointer to the type iterated over.
typedef T &reference; ///< Reference to the type iterated over.
///@}
/// Creates a new instance.
///
/// \param [in,out] S input stream to iterate over
CSVFlatIterator(std::istream &S, 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((size_t)(-1)), Column(Column), HeaderInfo(HeaderInfo),
+ 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.
CSVFlatIterator(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.
CSVFlatIterator &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];
}
}
/// 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);
+ ++(*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();
+ }
+ }
+
+ /// 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();
+ }
+ }
+
+ /// 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 {
+ 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 {
+ 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.
+
+};
+
} // End namespace csv
} // End namespace rosa
#endif // ROSA_SUPPORT_CSV_CSVREADER_HPP
diff --git a/include/rosa/support/csv/CSVWriter.hpp b/include/rosa/support/csv/CSVWriter.hpp
index b67de6a..0e79928 100755
--- a/include/rosa/support/csv/CSVWriter.hpp
+++ b/include/rosa/support/csv/CSVWriter.hpp
@@ -1,99 +1,100 @@
//===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/csv/CSVWriter.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Facitilities to write CSV files.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_CSV_CSVWRITER_HPP
#define ROSA_SUPPORT_CSV_CSVWRITER_HPP
+#include <iostream>
#include <ostream>
namespace rosa {
namespace csv {
/// Provides facilities to write values into a CSV file.
///
/// The writer emits a comma, the character `,`, between each written values.
/// The resulted stream is a flat CSV file as it consists of onlyone row, no new
/// line is emitted.
///
/// \tparam T type of values to write
template <typename T>
class CSVWriter {
public:
/// Creates a new instance.
///
/// \param [in,out] S output stream to write to
///
/// \note The writer operates on non-binary outputs as long as \p S is in
/// good state.
CSVWriter(std::ostream &S)
: Str(S.good() && !(S.flags() & std::ios::binary) ? &S : nullptr),
IsFirst(true) {}
/// Tells if the last operation was successful.
///
/// \return if the last operation was successful
bool good(void) const noexcept {
return Str != nullptr;
}
/// Writes an entry to the output stream.
///
/// The implementation does anything only if the last operation was
/// successful. If so, \p V is written to \c rosa::csv::CSVWriter::Str.
/// The emitted value is preceded with a comma if the actual call is not the
/// first one for \p this object. Success of the operation is checked at the
/// end.
///
/// \param V value to write
void write(const T &V) {
if (Str) {
if (!IsFirst) {
*Str << ',';
} else {
IsFirst = false;
}
*Str << V;
if (!Str->good()) {
Str = nullptr;
}
}
}
private:
std::ostream *Str; ///< Output stream to write to.
bool IsFirst; ///< Denotes if the next write would be the first one.
};
/// Writes a value to a CSV file with \c rosa::csv::CSVWriter.
///
/// \see rosa::csv::CSVWriter
///
/// \tparam T type of value to write
///
/// \param [in,out] W object to write with
/// \param V value to write
///
/// \return \p W after writing \p V with it
template <typename T>
CSVWriter<T> &operator<<(CSVWriter<T> &W, const T& V) {
W.write(V);
return W;
}
} // End namespace csv
} // End namespace rosa
#endif // ROSA_SUPPORT_CSV_CSVWRITER_HPP
diff --git a/include/rosa/support/sequence.hpp b/include/rosa/support/sequence.hpp
index 5764a80..abdc699 100755
--- a/include/rosa/support/sequence.hpp
+++ b/include/rosa/support/sequence.hpp
@@ -1,51 +1,56 @@
//===-- rosa/support/sequence.hpp -------------------------------*- C++ -*-===//
//
// The RoSA Framework
//
//===----------------------------------------------------------------------===//
///
/// \file rosa/support/sequence.hpp
///
/// \author David Juhasz (david.juhasz@tuwien.ac.at)
///
/// \date 2017
///
/// \brief Template facilities to statically generate a sequence of numbers.
///
//===----------------------------------------------------------------------===//
#ifndef ROSA_SUPPORT_SEQUENCE_HPP
#define ROSA_SUPPORT_SEQUENCE_HPP
#include <cstddef>
namespace rosa {
/// \defgroup Seq Implementation of rosa::Seq
///
/// Facility to statically generate sequences of numbers.
///
///@{
/// Template with an empty struct to store a sequence of numbers in compile time
/// as template arguments.
///
/// Generate a sequence of numbers from `0` up to (including) `(N - 1)` like
/// \code
/// typename GenSeq<N>::Type
/// \endcode
template <size_t...> struct Seq {};
/// Sequence generator, the general case when counting down by extending the
/// sequence.
template <size_t N, size_t... S> struct GenSeq : GenSeq<N - 1, N - 1, S...> {};
/// Sequence generator, the terminal case when storing the generated sequence
/// into \c Seq.
template <size_t... S> struct GenSeq<0, S...> { using Type = Seq<S...>; };
///@}
+/// Convenience template alias for using \c rosa::GenSeq to obtain an instance
+ /// of \c rosa::Seq.
+ ///
+ /// \see \c rosa::Seq and \c rosa::GenSeq
+ template <size_t... S> using seq_t = typename GenSeq<S...>::Type;
} // End namespace rosa
#endif // ROSA_SUPPORT_SEQUENCE_HPP

File Metadata

Mime Type
text/x-diff
Expires
Mon, Oct 20, 10:19 AM (21 h, 40 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
199688
Default Alt Text
(43 KB)

Event Timeline