Library: add some mutual integration between DataFile and CSVData
...both are related to CSV, and it is conceivable to create inline CSVData in a test case to populate a DataFile
This commit is contained in:
parent
03c2191649
commit
f37e651b61
5 changed files with 94 additions and 30 deletions
|
|
@ -51,7 +51,6 @@
|
|||
#include "lib/null-value.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/format-string.hpp"
|
||||
#include "lib/format-util.hpp"
|
||||
#include "lib/regex.hpp"
|
||||
|
||||
#include <limits>
|
||||
|
|
@ -170,7 +169,10 @@ namespace stat {
|
|||
|
||||
operator string() const
|
||||
{
|
||||
return util::join (*this, "\n");
|
||||
std::ostringstream buffer;
|
||||
for (string const& line : *this)
|
||||
buffer << line << '\n';
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,13 @@
|
|||
**
|
||||
** std::vector<int>& counters = daz.n.data;
|
||||
** \endcode
|
||||
**
|
||||
** \par Variations
|
||||
** The standard case is to have a table backed by persistent file storage,
|
||||
** which can be initially empty. Under some conditions, especially for tests
|
||||
** - the DataFile can be created without filename
|
||||
** - it can be created from a CSVData, which is a `std::vector` of CSV-strings
|
||||
** - it can be [rendered into CSV strings](\ref #renderCSV)
|
||||
** - a (new) storage file name can be [given later](\ref saveAs)
|
||||
** @see DataCSV_test
|
||||
**
|
||||
*/
|
||||
|
|
@ -198,6 +204,12 @@ namespace stat{
|
|||
loadData();
|
||||
}
|
||||
|
||||
DataFile (CSVData const& csv)
|
||||
: filename_{}
|
||||
{
|
||||
appendFrom (csv);
|
||||
}
|
||||
|
||||
|
||||
/* === Data Access === */
|
||||
|
||||
|
|
@ -222,12 +234,15 @@ namespace stat{
|
|||
return rowCnt;
|
||||
}
|
||||
|
||||
string
|
||||
dumpCSV() const
|
||||
CSVData
|
||||
renderCSV() const
|
||||
{
|
||||
string csv;
|
||||
CSVData csv{{}};
|
||||
csv.reserve (size()+1);
|
||||
auto header = generateHeaderSpec();
|
||||
std::swap (csv[0], header);
|
||||
for (uint i=0; i < size(); ++i)
|
||||
csv += formatCSVRow(i) + '\n';
|
||||
csv.emplace_back (formatCSVRow(i));
|
||||
return csv;
|
||||
}
|
||||
|
||||
|
|
@ -291,6 +306,17 @@ namespace stat{
|
|||
});
|
||||
}
|
||||
|
||||
void
|
||||
appendFrom (CSVData const& csv)
|
||||
{
|
||||
if (isnil (csv)) return;
|
||||
verifyHeaderSpec (csv[0]);
|
||||
for (size_t row=1; row<csv.size(); ++row)
|
||||
if (not isnil (csv[row]))
|
||||
appendRowFromCSV (csv[row]);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @param lineLimit number of rows to retain, back from the newest */
|
||||
void
|
||||
|
|
@ -408,14 +434,14 @@ namespace stat{
|
|||
});
|
||||
}
|
||||
|
||||
string
|
||||
generateHeaderSpec()
|
||||
CSVLine
|
||||
generateHeaderSpec() const
|
||||
{
|
||||
string csv;
|
||||
CSVLine csv;
|
||||
forAllColumns(
|
||||
[&](auto& col)
|
||||
{
|
||||
appendCsvField (csv, col.header);
|
||||
csv += col.header;
|
||||
});
|
||||
return csv;
|
||||
}
|
||||
|
|
@ -448,7 +474,7 @@ namespace stat{
|
|||
}
|
||||
|
||||
|
||||
string
|
||||
CSVLine
|
||||
formatCSVRow (size_t rownum) const
|
||||
{
|
||||
if (this->empty())
|
||||
|
|
@ -457,11 +483,11 @@ namespace stat{
|
|||
throw error::Logic{_Fmt{"Attempt to access row #%d beyond range [0..%d]."}
|
||||
% rownum % (size()-1)};
|
||||
|
||||
string csvLine;
|
||||
CSVLine csvLine;
|
||||
forAllColumns(
|
||||
[&](auto& col)
|
||||
{
|
||||
appendCsvField (csvLine, col.data.at(rownum));
|
||||
csvLine += col.data.at(rownum);
|
||||
});
|
||||
return csvLine;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@ namespace test{
|
|||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 4/24 🔁 define ⟶ implement
|
||||
* @todo WIP 4/24 🔁 define ⟶ ✔ implement
|
||||
*/
|
||||
void
|
||||
simpeUsage()
|
||||
|
|
@ -78,12 +78,13 @@ namespace test{
|
|||
,{4,5}
|
||||
,{5,8}
|
||||
,{6,13}
|
||||
,{7,21}
|
||||
,{7,21.55}
|
||||
}});
|
||||
cout << gnuplot <<endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** @test TODO
|
||||
* @todo WIP 4/24 🔁 define ⟶ implement
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -327,9 +327,10 @@ namespace test{
|
|||
dat.dupRow();
|
||||
dat.id = "last";
|
||||
dat.off *= -1;
|
||||
// can dump the contents as CSV
|
||||
CHECK (dat.dumpCSV() ==
|
||||
R"("",0,0
|
||||
// can render the contents as CSV
|
||||
CHECK (dat.renderCSV() ==
|
||||
R"("ID","Value","Offset"
|
||||
"",0,0
|
||||
"mid",5.5,1
|
||||
"last",5.5,-1
|
||||
)"_expect);
|
||||
|
|
@ -364,8 +365,8 @@ R"("ID","Value","Offset"
|
|||
auto appended = (CSVLine{} += 5.5) += Symbol();
|
||||
CHECK (appended == "5.5,\"⟂\""_expect);
|
||||
|
||||
CHECK (CSVData({"eeny","meeny","miny","moe"}) == "\"eeny\",\"meeny\",\"miny\",\"moe\""_expect);
|
||||
CHECK (CSVData({"eeny , meeny","miny","moe"}) == "\"eeny , meeny\"\n\"miny\"\n\"moe\""_expect); // you dirty dirty dishrag you
|
||||
CHECK (CSVData({"eeny","meeny","miny","moe"}) == "\"eeny\",\"meeny\",\"miny\",\"moe\"\n"_expect);
|
||||
CHECK (CSVData({"eeny , meeny","miny","moe"}) == "\"eeny , meeny\"\n\"miny\"\n\"moe\"\n"_expect); // you dirty dirty dishrag you
|
||||
|
||||
auto csv = CSVData{{"la","la","schland"}
|
||||
,{{3.2,1l,88}
|
||||
|
|
@ -381,7 +382,23 @@ R"("la","la","schland"
|
|||
"mit","mia","ned"
|
||||
";"
|
||||
false
|
||||
|
||||
)"_expect);
|
||||
|
||||
VERIFY_FAIL ("Header mismatch in CSV file", TestTab{csv} );
|
||||
|
||||
csv = CSVData{{"ID","Value","Offset"}
|
||||
,{{"Baby","toe"}
|
||||
}};
|
||||
VERIFY_FAIL ("unable to parse \"toe\"", TestTab{csv} );
|
||||
|
||||
csv = CSVData{{"ID","Value","Offset"}
|
||||
,{{"Baby",1.6180,23}
|
||||
,{"Tiger",10101,-5}
|
||||
}};
|
||||
TestTab dat{csv};
|
||||
CHECK (dat.val == 1.0101e4);
|
||||
CHECK (dat.renderCSV() == string(csv));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -112157,14 +112157,20 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eef0c5" COLOR="#990000" CREATED="1710516999984" ID="ID_476868581" MODIFIED="1710517031610" TEXT="stat::DataSpan mit Lumiera-Iterator-Framework kompatibel machen">
|
||||
<icon BUILTIN="pencil"/>
|
||||
<node COLOR="#338800" CREATED="1710516999984" ID="ID_476868581" MODIFIED="1712095672484" TEXT="stat::DataSpan mit Lumiera-Iterator-Framework kompatibel machen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1710517020971" ID="ID_1049280485" MODIFIED="1710517029789" TEXT="das ist ein Vorgriff auf C++20">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1711836137562" ID="ID_108223729" MODIFIED="1711836155134" TEXT="schon mal free-functions begin() | end() hinzugefügt">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1712095673899" ID="ID_179465663" MODIFIED="1712095687761" TEXT="incl. Erzeugen von Teil-Bereichen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1712095688617" ID="ID_503885767" MODIFIED="1712095695468" TEXT="Test: mit lib::explore()">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1710351128227" ID="ID_1587957134" MODIFIED="1710351136356" TEXT="Ergänzungen">
|
||||
<icon BUILTIN="idea"/>
|
||||
|
|
@ -112186,8 +112192,8 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<node COLOR="#435e98" CREATED="1710351185059" ID="ID_431256200" MODIFIED="1710352477645" STYLE="fork" TEXT="saveAs()-Funktion bereistellen"/>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1711983612740" ID="ID_902546947" MODIFIED="1712089787472" TEXT="vereinfachte / erweiterte CSV-Notation für Tests">
|
||||
<linktarget COLOR="#2a9fe5" DESTINATION="ID_902546947" ENDARROW="Default" ENDINCLINATION="-1334;77;" ID="Arrow_ID_47054806" SOURCE="ID_1350863024" STARTARROW="None" STARTINCLINATION="-1467;-42;"/>
|
||||
<linktarget COLOR="#3483c8" DESTINATION="ID_902546947" ENDARROW="Default" ENDINCLINATION="-1334;77;" ID="Arrow_ID_606537608" SOURCE="ID_1834207024" STARTARROW="None" STARTINCLINATION="1430;149;"/>
|
||||
<linktarget COLOR="#2a9fe5" DESTINATION="ID_902546947" ENDARROW="Default" ENDINCLINATION="-1334;77;" ID="Arrow_ID_47054806" SOURCE="ID_1350863024" STARTARROW="None" STARTINCLINATION="-1467;-42;"/>
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#338800" CREATED="1711983784796" ID="ID_1350290271" MODIFIED="1712081833591" TEXT="CSVLine : string der Felder anhängen kann">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -112203,8 +112209,17 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1712081944646" ID="ID_685990414" MODIFIED="1712081986841" TEXT="kann aus DataTable gewonnen werden">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#338800" CREATED="1712081944646" ID="ID_685990414" MODIFIED="1712095588465" TEXT="kann aus DataFile gewonnen werden">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1712095483749" ID="ID_448300363" MODIFIED="1712095501564" TEXT="erscheint nur mäßig sinnvoll...">
|
||||
<icon BUILTIN="smiley-neutral"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1712095518601" ID="ID_1818911968" MODIFIED="1712095586479" TEXT="Umgekehrt: die dump-Funktion von DataFile durch CSVData ersetzen">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
<node COLOR="#435e98" CREATED="1712095554779" ID="ID_1265654486" MODIFIED="1712095586479" TEXT="...und damit ist es auch ein neuer ctor sinnvoll: DataFile{CSVData}">
|
||||
<font ITALIC="true" NAME="SansSerif" SIZE="12"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
|
|
@ -112260,10 +112275,6 @@ Date:   Thu Apr 20 18:53:17 2023 +0200<br/>
|
|||
</node>
|
||||
<node COLOR="#338800" CREATED="1711983648446" ID="ID_1858721218" MODIFIED="1712089737113" TEXT="demonnstrate_CSV_Notation">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#228091" CREATED="1711983651689" ID="ID_1350863024" MODIFIED="1712089777858" TEXT="sollte doch noch etwas die Notation von Testdaten vereinfachen">
|
||||
<arrowlink COLOR="#2a9fe5" DESTINATION="ID_902546947" ENDARROW="Default" ENDINCLINATION="-1334;77;" ID="Arrow_ID_47054806" STARTARROW="None" STARTINCLINATION="-1467;-42;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#338800" CREATED="1710460938455" ID="ID_757574171" MODIFIED="1710466412661" TEXT="verify_persistentDataFile">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
|
|
@ -114421,9 +114432,16 @@ std::cout << tmpl.render({"what", "World"}) << s
|
|||
</node>
|
||||
<node COLOR="#338800" CREATED="1711820811033" ID="ID_1587185713" MODIFIED="1711904722630" TEXT="Header + Datentupel<double>">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node COLOR="#435e98" CREATED="1712095887150" HGAP="33" ID="ID_675366089" LINK="#ID_1395935730" MODIFIED="1712095932364" TEXT="Umweg über CSVData" VSHIFT="8">
|
||||
<icon BUILTIN="idea"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node COLOR="#228091" CREATED="1711983651689" ID="ID_1350863024" MODIFIED="1712089777858" TEXT="sollte doch noch etwas die Notation von Testdaten vereinfachen">
|
||||
<arrowlink COLOR="#2a9fe5" DESTINATION="ID_902546947" ENDARROW="Default" ENDINCLINATION="-1334;77;" ID="Arrow_ID_47054806" STARTARROW="None" STARTINCLINATION="-1467;-42;"/>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1711900330296" ID="ID_1080765414" MODIFIED="1711900374682" TEXT="typischerweise: Familie von Aufruf-Front-ends">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node CREATED="1711900349274" ID="ID_1386251374" MODIFIED="1711900360595" TEXT="der eigentliche Aufruf kann mit einem Rec::Mutator erfolgen"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue