diff --git a/yoshimi-testrunner/src/util/csv.hpp b/yoshimi-testrunner/src/util/csv.hpp index 50ecf1cdc..b0da3cca6 100644 --- a/yoshimi-testrunner/src/util/csv.hpp +++ b/yoshimi-testrunner/src/util/csv.hpp @@ -151,6 +151,12 @@ public: and not curr_->empty(); } + bool isParseFail() + { + return curr_ == end() + and not isValid(); + } + void fail() { if (curr_ == end()) diff --git a/yoshimi-testrunner/src/util/data.hpp b/yoshimi-testrunner/src/util/data.hpp index 426d07e95..d6264ccb5 100644 --- a/yoshimi-testrunner/src/util/data.hpp +++ b/yoshimi-testrunner/src/util/data.hpp @@ -54,8 +54,10 @@ //#include //#include +#include #include #include +#include #include @@ -92,6 +94,8 @@ struct Column : util::NonCopyable string header; vector 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().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::type::ValueType; + col.get() = parseAs(*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::max(); + forEach(unConst(this)->allColumns(), + [&](auto& col) + { + rowCnt = std::min(rowCnt, col.data.size()); + }); + return rowCnt; + } + + bool empty() const + { + return 0 == this->size(); + } + template decltype(auto) getCol() { diff --git a/yoshimi-testrunner/src/util/format.hpp b/yoshimi-testrunner/src/util/format.hpp index 5ecfe20d9..44915ff5e 100644 --- a/yoshimi-testrunner/src/util/format.hpp +++ b/yoshimi-testrunner/src/util/format.hpp @@ -30,7 +30,8 @@ #define TESTRUNNER_UTIL_FORMAT_HPP_ -//#include +#include "util/utils.hpp" + #include #include @@ -77,5 +78,23 @@ inline string formatVal(float f) return oss.str(); } + +/** parse string representation into typed value */ +template +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_*/ diff --git a/yoshimi-testrunner/src/util/regex.hpp b/yoshimi-testrunner/src/util/regex.hpp index f12ce28d9..1aae85bc0 100644 --- a/yoshimi-testrunner/src/util/regex.hpp +++ b/yoshimi-testrunner/src/util/regex.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 @@ -54,4 +54,4 @@ struct MatchSeq }//(End)namespace util -#endif /*TESTRUNNER_UTIL_PARSE_HPP_*/ +#endif /*TESTRUNNER_UTIL_REGEX_HPP_*/ diff --git a/yoshimi-testrunner/src/util/utils.hpp b/yoshimi-testrunner/src/util/utils.hpp index 5b0d44fed..3952e06fe 100644 --- a/yoshimi-testrunner/src/util/utils.hpp +++ b/yoshimi-testrunner/src/util/utils.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 +inline OBJ* unConst (const OBJ* o) +{ +return const_cast (o); +} + +template +inline OBJ& unConst (OBJ const& ro) +{ +return const_cast (ro); +} + + /** @return content without leading or trailing whitespace */ string trimmed(string);