integrate CSV handling into the new data table type
This commit is contained in:
parent
b6a2eec94c
commit
a42de3ee1b
5 changed files with 108 additions and 4 deletions
|
|
@ -151,6 +151,12 @@ public:
|
|||
and not curr_->empty();
|
||||
}
|
||||
|
||||
bool isParseFail()
|
||||
{
|
||||
return curr_ == end()
|
||||
and not isValid();
|
||||
}
|
||||
|
||||
void fail()
|
||||
{
|
||||
if (curr_ == end())
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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_*/
|
||||
|
|
|
|||
|
|
@ -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_*/
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue