integrate CSV handling into the new data table type

This commit is contained in:
Fischlurch 2021-09-17 15:01:28 +02:00
parent b6a2eec94c
commit a42de3ee1b
5 changed files with 108 additions and 4 deletions

View file

@ -151,6 +151,12 @@ public:
and not curr_->empty();
}
bool isParseFail()
{
return curr_ == end()
and not isValid();
}
void fail()
{
if (curr_ == end())

View file

@ -54,8 +54,10 @@
//#include <string>
//#include <memory>
#include <type_traits>
#include <utility>
#include <vector>
#include <limits>
#include <tuple>
@ -92,6 +94,8 @@ struct Column : util::NonCopyable
string header;
vector<VAL> data;
using ValueType = VAL;
Column(string headerID)
: header{headerID}
@ -126,6 +130,8 @@ class DataFile
{
public:
static constexpr size_t columnCnt = std::tuple_size_v<decltype(std::declval<TAB>().allColumns())>;
DataFile()
{
newRow();
@ -149,6 +155,61 @@ public:
});
}
void appendRowFromCSV(string line)
{
newRow();
CsvLine csv(line);
forEach(TAB::allColumns(),
[&](auto& col)
{
if (!csv)
if (csv.isParseFail())
csv.fail();
else
throw error::Invalid("Insufficient data; only "
+formatVal(csv.getParsedFieldCnt())
+" fields. Line="+line);
using Value = typename std::remove_reference<decltype(col)>::type::ValueType;
col.get() = parseAs<Value>(*csv);
++csv;
});
}
string formatCSVRow(size_t rownum)
{
if (this->empty())
throw error::LogicBroken("Attempt to access data from empty DataTable.");
if (rownum >= this->size())
throw error::LogicBroken("Attempt to access row #"+str(rownum)
+" beyond range [0.."+str(size()-1)+"].");
string csvLine;
forEach(TAB::allColumns(),
[&](auto& col)
{
appendCsvField(csvLine, col.data.at(rownum));
});
return csvLine;
}
size_t size() const
{
if (0 == columnCnt) return 0;
size_t rowCnt = std::numeric_limits<size_t>::max();
forEach(unConst(this)->allColumns(),
[&](auto& col)
{
rowCnt = std::min(rowCnt, col.data.size());
});
return rowCnt;
}
bool empty() const
{
return 0 == this->size();
}
template<size_t i>
decltype(auto) getCol()
{

View file

@ -30,7 +30,8 @@
#define TESTRUNNER_UTIL_FORMAT_HPP_
//#include <algorithm>
#include "util/utils.hpp"
#include <string>
#include <sstream>
@ -77,5 +78,23 @@ inline string formatVal(float f)
return oss.str();
}
/** parse string representation into typed value */
template<typename TAR>
inline TAR parseAs(string const& encodedVal)
{
std::istringstream converter{encodedVal};
TAR value;
converter >> value;
return value;
}
inline bool parseAs(string const& encodedBool)
{
return util::boolVal(encodedBool);
}
}//namespace util
#endif /*TESTRUNNER_UTIL_FORMAT_HPP_*/

View file

@ -26,8 +26,8 @@
#ifndef TESTRUNNER_UTIL_PARSE_HPP_
#define TESTRUNNER_UTIL_PARSE_HPP_
#ifndef TESTRUNNER_UTIL_REGEX_HPP_
#define TESTRUNNER_UTIL_REGEX_HPP_
#include <regex>
@ -54,4 +54,4 @@ struct MatchSeq
}//(End)namespace util
#endif /*TESTRUNNER_UTIL_PARSE_HPP_*/
#endif /*TESTRUNNER_UTIL_REGEX_HPP_*/

View file

@ -191,6 +191,24 @@ backwards (ITA&& iterable)
}
/**
* Shortcut for casting away `const`.
* @warning Use with care. Can be very handy to simplify defining
* const and non-const variants of member functions though.
*/
template<class OBJ>
inline OBJ* unConst (const OBJ* o)
{
return const_cast<OBJ*> (o);
}
template<class OBJ>
inline OBJ& unConst (OBJ const& ro)
{
return const_cast<OBJ&> (ro);
}
/** @return content without leading or trailing whitespace */
string trimmed(string);