diff --git a/examples/CSVFiles/main.cpp b/examples/CSVFiles/main.cpp index 48fb631..bd8b61b 100644 --- a/examples/CSVFiles/main.cpp +++ b/examples/CSVFiles/main.cpp @@ -1,266 +1,345 @@ - -// To compile with dumping record layout: -// $ clang++ -o variadic-tuple -Xclang -fdump-record-layouts variadic-tuple.cpp -// -Wall -g -std=c++11 +//===-- examples/CSVFiles/main.cpp ------------------*- C++ -*-===// +// +// The RoSA Framework +// +//===----------------------------------------------------------------------===// +/// +/// \file examples/basic-system/basic-system.cpp +/// +/// \author Edwin Willegger (edwin.willegger@tuwien.ac.at) +/// +/// \date 2019 +/// +/// \brief A simple example on the basic \c rosa::csv, \c rosa::iterator and +/// \c rosa::writer classes. Focus is on the tuple impementations. +/// +//===----------------------------------------------------------------------===// #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //includes for an complete example to read and write //with sensors and agents. #include "rosa/deluxe/DeluxeContext.hpp" #include "rosa/config/version.h" //includes to test the basic functionality //to read and write tuples. #include "rosa/support/csv/CSVReader.hpp" #include "rosa/support/csv/CSVWriter.hpp" #include "rosa/support/iterator/split_tuple_iterator.hpp" #include "rosa/support/writer/split_tuple_writer.hpp" /// the name of the example const std::string ExampleName = "csvfiles"; /// How many cycles of simulation to perform. const size_t NumberOfSimulationCycles = 10; /// Paths for the CSV files for simulation. /// input csv files const std::string csvPath = "../examples/CSVFiles/"; const std::string csvFileWithHeader = csvPath + "HR-New.csv"; const std::string csvFileNoHeader = csvPath + "HR.csv"; const std::string csvFileHeaderSemi = csvPath + "HR-New-Semicolon.csv"; -/// output csv file -const std::string csvFileWriteNoHea = csvPath + "csvwriter_noheader.csv"; +/// output csv files +const std::string csvFileWriteHea = csvPath + "csvwriter_noheader.csv"; +const std::string csvFileWriteNoHeaSplit = csvPath + "csvSplitwriter_noheader.csv"; using namespace rosa; -void testtupleCSVReader(){ +/// +/// This function tests the basic CSVIterator capablities, and shows you +/// how you could work with this class. +/// +void testtupleCSVReader(void){ //different streams to get the csv data out of the files //file contains header and valid data entries, delimter = ',' std::ifstream file_header_data(csvFileWithHeader); //file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_2(csvFileWithHeader); //file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_3(csvFileWithHeader); //file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_4(csvFileWithHeader); //file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_5(csvFileWithHeader); //file contains header and valid data entries, delimter = ',' std::ifstream file_header_data_6(csvFileWithHeader); //file contains no header an valid data entries, delimter = ',' std::ifstream file2(csvFileNoHeader); //file contains header and valid data entries, delimter = ';' std::ifstream file3(csvFileHeaderSemi); 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; // // Show the value of one iterator // LOG_INFO( "Values are: "); LOG_INFO(std::get<0>(value) ); LOG_INFO(std::get<1>(value) ); //-------------------------------------------------------------------- //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 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 //csv::CSVIterator it2_1(file_header_data_3, 0, 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 //csv::CSVIterator it2_2(file_header_data_4, 1, csv::HeaderInformation::HasNoHeader); //try to skip a valid number of lines of a file without header csv::CSVIterator it2_3(file2, 1, csv::HeaderInformation::HasNoHeader); //try to skip a valid number of lines after the header, but with different delimeter csv::CSVIterator it2_4(file3, 2, csv::HeaderInformation::HasHeader, ';'); // if you skip more lines than valid, you generate an infinte loop //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. csv::CSVIterator it4(file_header_data_6); } - -void testtupleCSVWriter(){ +/// +/// This function tests the basic CSVTupleWriter capablities, and shows you +/// how you could work with this class. +/// +void testtupleCSVWriter(void){ // // Create output writer with an file // - std::ofstream file_header_out(csvFileWriteNoHea); + std::ofstream file_header_out(csvFileWriteHea); csv::CSVTupleWriter wri(file_header_out); // // Create test tuples // std::tuple values(5, 8.3, "hallo"); std::tuple values2(3, 8.3, "end"); // // Create test header lines for the test tuples // - std::array header {"first column", "second column", "third column"}; + std::array header {"zero column", "first column", "second column"}; - std::array headerWrong {"first column", "second column", "third column", "fourth column"}; + std::array headerWrong {"zero column", "first column", "second column", "third column"}; - std::array headerWrongShort {"first column", "second column"}; + std::array headerWrongShort {"zero column", "first column"}; wri.writeHeader(header); wri.write(values); wri.write(values); wri.write(values); wri << values; wri << values2; //uncomment this line to see, that you can't write a header with the too many elements. //wri.writeHeader(headerWrong); //uncomment this line to see, that you can't write a header with the too few elements. //wri.writeHeader(headerWrongShort); - + } - -void testsplitTupleIterator() +/// +/// This function tests the basic splitTupleIterator capablities, and shows you +/// how you could work with this class, this class is used if you want to split +/// a CSVIterator in separate parts. +/// +void testsplitTupleIterator(void) { // // Create deluxe context // std::unique_ptr C = deluxe::DeluxeContext::create(ExampleName); // // 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. // Three different sensors were created, this is just a random number taken. AgentHandle Elem0Sensor = C->createSensor("Element1 Sensor"); AgentHandle Elem1Sensor = C->createSensor("Element2 Sensor"); AgentHandle Elem2Sensor = C->createSensor("Element3 Sensor"); // // Initialize deluxe context for simulation. // C->initializeSimulation(); // Type aliases for iterators using Iterator = rosa::csv::CSVIterator; using IteratorValue = std::tuple; static_assert (std::is_same::value, "Iterator must provide tuples" ); // // Open CSV file and register the columns to the corresponding sensors. // std::ifstream TestCSV(csvFileWithHeader); // // Test data looks like: // Element1, Element2, Element3, Element4, Element5 -- is the header line // 3, 5, 8, 9.5, 17 -- first line of values // 100, -8, 30, 18.8, 29 -- other line of values were also in the file // 5, 20, -100, -200.1, -30 -- if you have less number of values than simulation rounds all values // -- beyond your last value will be zero. //get element iterator ranges auto [Elem0Range, Elem1Range, Elem2Range] = iterator::splitTupleIterator(Iterator(TestCSV), Iterator()); //dissect ranges into begin and end iterators by structred bindings auto[Elem0Begin, Elem0End] = Elem0Range; auto[Elem1Begin, Elem1End] = Elem1Range; auto[Elem2Begin, Elem2End] = Elem2Range; C->registerSensorValues(Elem0Sensor, std::move(Elem0Begin), Elem0End); C->registerSensorValues(Elem1Sensor, std::move(Elem1Begin), Elem1End); C->registerSensorValues(Elem2Sensor, std::move(Elem2Begin), Elem2End); // // Simulate. // C->simulate(NumberOfSimulationCycles); } +/// +/// This function tests the basic splitTupleWriter capablities, and shows you +/// how you could work with this class, this class is used if you want to split +/// a CSVWriter in separate parts. +/// +void testsplitTupleWriter(void){ + // + // Create output writer with an file + // + std::ofstream file_header_out(csvFileWriteNoHeaSplit); + csv::CSVTupleWriter wri(file_header_out); + + // if you omit, the type definition in the template, than auto generated types were used, + // and they may not fit to the used CSVTupleWriter. + wri << std::make_tuple(1000, 50.6, "tuple_created"); + auto [T0Writer, T1Writer, T2Writer] = writer::splitTupleWriter(std::move(wri), + writer::IncompleteTuplePolicy::Ignore); + //writing elements in sequential order into the writer classes, but you can write the values into the writers in + //a random order. + T0Writer << (500); + T1Writer << (3.0); + T2Writer << "splitted writter"; + + T2Writer << "splitting is cool"; + T0Writer << (-30); + T1Writer << (-0.004); + + // you can also write more often values into a writer and later into the other writers + // all data will be processed correctly into the right order. + T0Writer << (1); + T0Writer << (2); + T1Writer << (-0.4); + T0Writer << (3); + T2Writer << "again"; + T0Writer << (4); + T1Writer << (-0.1); + T1Writer << (-0.2); + T2Writer << "and"; + T1Writer << (-0.3); + T2Writer << "splitting"; + T2Writer << "once again"; + + // again writing data of one tuple entry to the different writers in a random fashion. + T1Writer << (-0.004); + T2Writer << "splitting is cool"; + T0Writer << (-30); + +} + int main(void){ LOG_INFO_STREAM << library_string() << " -- " << terminal::Color::Red << ExampleName << " example" << terminal::Color::Default << '\n'; // // Testing CSVWriter. // LOG_INFO("Testing CSVWriter CSVTupleItrator implementation: "); testtupleCSVWriter(); // // Testing CSVReader. // LOG_INFO("Testing CSVReader CSVTupleIterator implementation: "); testtupleCSVReader(); // // Testing SplitTupleIterator. // LOG_INFO("Testing SplitTupleIterator: "); testsplitTupleIterator(); + // + // Testing SplitTupleWriter. + // + LOG_INFO("Testing SplitTupleWriter: "); + testsplitTupleWriter(); + // // info that user knows programm has finished. // LOG_INFO( "All tests finished."); return 0; } diff --git a/include/rosa/support/csv/CSVWriter.hpp b/include/rosa/support/csv/CSVWriter.hpp index ecb9745..3ee9b6d 100755 --- a/include/rosa/support/csv/CSVWriter.hpp +++ b/include/rosa/support/csv/CSVWriter.hpp @@ -1,211 +1,215 @@ //===-- rosa/support/csv/CSVWriter.hpp --------------------------*- C++ -*-===// // // The RoSA Framework // //===----------------------------------------------------------------------===// /// /// \file rosa/support/csv/CSVWriter.hpp /// -/// \authors David Juhasz (david.juhasz@tuwien.ac.at) +/// \authors David Juhasz (david.juhasz@tuwien.ac.at) /// Edwin Willegger (edwin.willegger@tuwien.ac.at) /// /// \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 #include #include "../log.h" 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: /// 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 types of values to write template class CSVTupleWriter { public: + +// typedef value_type ; ///< Type of values written. + typedef std::tuple value_type; + /// 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) {} /// Tells if the last operation was successful. /// /// \return if the last operation was successful bool good(void) const noexcept { return Str != nullptr; } /// Write the values of a tuple to a CSV file with \c rosa::csv::CSVTupleWriter. /// /// \see rosa::csv::CSVTupleWriter /// /// /// \param [in,out] values tuple, which values are written in a recusive fashion into a stream. template void write(const std::tuple &values) { constexpr size_t size = sizeof...(Ts); std::string message = ""; LOG_TRACE("Writing tuple values into file \n"); message = " Tuple has " + std::to_string(size) + " elements. \n"; LOG_TRACE(message); message = " Value is "; LOG_TRACE(message); LOG_TRACE(std::get(values)); if(Str){ /// Write the current element of the tuple into the stream and add a separtor after it, /// and call the function for the next element in the tuple. if constexpr(i+1 != sizeof...(Ts)){ *Str << std::get(values) << ", "; write(values); /// If the last element is written into the stream than begin a new line. }else if constexpr(i + 1 == sizeof...(Ts)){ *Str << std::get(values) << '\n'; } } } /// Write the header values to a CSV file with \c rosa::csv::CSVTupleWriter. /// /// \see rosa::csv::CSVTupleWriter /// /// \param header the content of the header line. /// void writeHeader(const std::array &header){ size_t index = 0; /// write into the stream only, if it is not a nullptr. if(Str){ index = 0; for (auto i = header.begin(); i != header.end(); ++i){ index = index + 1; /// write into the stream every entry with a delimeter, in this case ", " until /// the last entry if(index != header.size()){ *Str << *i << ", "; /// write the last entry into the stream, without any delimeter }else { *Str << *i; } } /// finish the header line and start a new line. *Str << '\n'; } } private: std::ostream *Str; ///< Output stream to write to. }; /// Writes all values of a tuple to a CSV file with \c rosa::csv::CSVTupleWriter. /// /// \see rosa::csv::CSVTupleWriter /// /// \tparam Ts types of values to write /// /// \param [in,out] W object to write with /// \param V values to write /// /// \return \p W after writing \p V with it 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