diff --git a/examples/CSVFiles/main.cpp b/examples/CSVFiles/main.cpp index 2f74305..68e287a 100644 --- a/examples/CSVFiles/main.cpp +++ b/examples/CSVFiles/main.cpp @@ -1,126 +1,153 @@ //===-- examples/CSVFiles/main.cpp --------------------------------*- C++ -*-===// // // The RoSA Framework -- Example CSVFiles // //===----------------------------------------------------------------------===// /// /// \file examples/CSVFiles/main.cpp /// /// \author Edwin Willegger (edwin.willegger@tuwien.ac.at) /// /// \date 2019 /// /// \brief This example shows how you could use the CSVIterator class to /// get data into RoSA from a CSV-file. //===----------------------------------------------------------------------===// // To compile with dumping record layout: // $ clang++ -o variadic-tuple -Xclang -fdump-record-layouts variadic-tuple.cpp // -Wall -g -std=c++11 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "rosa/support/csv/CSVReader.hpp" +#include "rosa/support/csv/CSVWriter.hpp" const std::string AppName = "test-csvfiles"; //the example will be executed in the bin directory, but the data files are located in another the examples folder const std::string Path = "../examples/CSVFiles/"; -void testtuple(){ +void testtupleCSVReader(){ - //Different stream objects to work on CSV data and show the limitations of the current implementation. - //If you don't find any of these files, just create your own data files. + //different streams to get the csv data out of the files //file contains header and valid data entries, delimter = ',' - std::ifstream file_header_data(Path + "HR-New.csv"); + std::ifstream file_header_data("HR-New.csv"); //file contains header and valid data entries, delimter = ',' - std::ifstream file_header_data_2(Path + "HR-New.csv"); + std::ifstream file_header_data_2("HR-New.csv"); //file contains header and valid data entries, delimter = ',' - std::ifstream file_header_data_3(Path + "HR-New.csv"); + std::ifstream file_header_data_3("HR-New.csv"); //file contains header and valid data entries, delimter = ',' - std::ifstream file_header_data_4(Path + "HR-New.csv"); + std::ifstream file_header_data_4("HR-New.csv"); //file contains header and valid data entries, delimter = ',' - std::ifstream file_header_data_5(Path + "HR-New.csv"); + std::ifstream file_header_data_5("HR-New.csv"); //file contains header and valid data entries, delimter = ',' - std::ifstream file_header_data_6(Path + "HR-New.csv"); + std::ifstream file_header_data_6("HR-New.csv"); //file contains no header an valid data entries, delimter = ',' - std::ifstream file2(Path + "HR.csv"); + std::ifstream file2("HR.csv"); //file contains header and valid data entries, delimter = ';' - std::ifstream file3(Path + "HR-New-Semicolon.csv"); + std::ifstream file3("HR-New-Semicolon.csv"); rosa::csv::CSVIterator it(file_header_data); it.setDelimeter(','); it++; it++; //if you iterate over the end of file, the last values //of the file will remain in the data structure but no //error occurs. it++; it++; //------------------------------------------------------------------- // a possiblity to get the data out of the iterator std::tuple value = *it; std::cout << "Values are: " << std::get<0>(value) << " " << std::get<1>(value) << " ,are you now happy?" << std::endl; //-------------------------------------------------------------------- //testing differnet parameters to the constructor //uncomment to see that it is not possible to iterate over an vector in the tuple. //rosa::csv::CSVIterator> it2(file, 1); //try to skip a valid number of lines after the header rosa::csv::CSVIterator it2_0(file_header_data_2, 1); //try to skip a valid number of lines after the header, but you assume that the file has no header //uncomment this line to crash the programm //rosa::csv::CSVIterator it2_1(file_header_data_3, 0, rosa::csv::HeaderInformation::HasNoHeader); //try to skip a valid number of lines after the header, but you assume that the file has no header //uncomment this line to crash the program // rosa::csv::CSVIterator it2_2(file_header_data_4, 1, rosa::csv::HeaderInformation::HasNoHeader); //try to skip a valid number of lines of a file without header rosa::csv::CSVIterator it2_3(file2, 1, rosa::csv::HeaderInformation::HasNoHeader); //try to skip a valid number of lines after the header, but with different delimeter rosa::csv::CSVIterator it2_4(file3, 2,rosa::csv::HeaderInformation::HasHeader, ';'); // if you skip more lines than valid, you generate an infinte loop //rosa::csv::CSVIterator it3(file_header_data_5, 500); //if you don't need data from all columns just select the number of columns you //need. You get the data back from the first column (index 0) to the fourth column //all values from the fifth column are ignored. rosa::csv::CSVIterator it4(file_header_data_6); } + +void testtupleCSVWriter(){ + std::ofstream file_header_out("csvwriter_noheader.csv"); + rosa::csv::CSVTupleWriter wri(file_header_out); + + std::tuple values(5, 8.3, "hallo"); + std::tuple values2(3, 8.3, "end"); + + std::vector header; + header.push_back("first column"); + header.push_back("second column"); + header.push_back("third column"); + + + wri.writeHeader(header); + wri.write(values); + wri.write(values); + wri.write(values); + wri << values; + wri << values2; + +} + int main(void) { std::cout << "This is a short example to show you how you could use the CSVIterator class." << std::endl; std::cout << "There are also some limitations explained in the source code of the example." << std::endl; - testtuple(); + std::cout << "Testing CSVWriter CSVTupleItrator implementation: " << std::endl; + testtupleCSVWriter(); + + std::cout << "Testing CSVReader CSVTupleIterator implementation: " << std::endl; + testtupleCSVReader(); std::cout << "All tests finished sucessfully" << std::endl; return 0; } diff --git a/include/rosa/support/csv/CSVWriter.hpp b/include/rosa/support/csv/CSVWriter.hpp index 1c06bbb..b7d5389 100755 --- a/include/rosa/support/csv/CSVWriter.hpp +++ b/include/rosa/support/csv/CSVWriter.hpp @@ -1,161 +1,177 @@ //===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/csv/CSVWriter.hpp /// -/// \author David Juhasz (david.juhasz@tuwien.ac.at) +/// \authors David Juhasz (david.juhasz@tuwien.ac.at) +/// Edwin Willegger (edwin.willegger@tuwien.ac.at) /// -/// \date 2017 +/// \date 2017-2019 /// /// \brief Facitilities to write CSV files. /// //===----------------------------------------------------------------------===// #ifndef ROSA_SUPPORT_CSV_CSVWRITER_HPP #define ROSA_SUPPORT_CSV_CSVWRITER_HPP #include #include #include +#include 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 class CSVWriter { public: - /// \defgroup CSVWriterTypedefs Typedefs of rosa::csv::CSVWriter - /// - /// Useful `typedef`s for writers. - /// - ///@{ - typedef T value_type; ///< Type of values written - typedef T &reference; ///< Reference to the type written - ///@} - /// 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 tuple of values into a CSV file /// /// \tparam Ts tpyes of values to write template class CSVTupleWriter { 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. CSVTupleWriter(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; } template void write(std::tuple values) { size_t size = 0; std::cout << "Writing tuple values into file" << std::endl; std::cout << "Tuple has "; std::cout << std::tuple_size::value; std::cout << " elements." << std::endl; size = std::tuple_size::value; std::cout << std::get(values) << std::endl; if(Str){ if constexpr(i+1 != sizeof...(Ts)){ - *Str << std::get(values) << " ,"; + *Str << std::get(values) << ", "; write(values); }else if constexpr(i + 1 == sizeof...(Ts)){ *Str << std::get(values) << '\n'; } } } + void writeHeader(std::vector header){ + size_t index = 0; + if(Str){ + index = 0; + for (auto i = header.begin(); i != header.end(); ++i){ + index = index + 1; + if(index != header.size()){ + *Str << *i << ", "; + }else { + *Str << *i; + } + } + *Str << '\n'; + } + } + private: std::ostream *Str; ///< Output stream to write to. bool IsFirst; ///< Denotes if the next write would be the first one. }; +template +CSVTupleWriter &operator<<(CSVTupleWriter &W, const std::tuple V) +{ + W.write(V); + return W; +} + /// 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 CSVWriter &operator<<(CSVWriter &W, const T& V) { W.write(V); return W; } } // End namespace csv } // End namespace rosa #endif // ROSA_SUPPORT_CSV_CSVWRITER_HPP