78 #ifndef LIB_STAT_DATA_H 79 #define LIB_STAT_DATA_H 89 #include <type_traits> 120 template<
typename VAL>
127 using ValueType = VAL;
149 operator VAL
const&()
const 151 return unConst(
this)->get();
155 VAL& operator= (X&& newVal)
157 return get() = std::forward<X> (newVal);
193 : filename_{fs::consolidated (csvFile)}
207 static constexpr
size_t columnCnt = std::tuple_size_v<decltype(std::declval<TAB>().allColumns())>;
212 return 0 == this->size();
218 if (0 == columnCnt)
return 0;
219 size_t rowCnt = std::numeric_limits<size_t>::max();
223 rowCnt = min (rowCnt, col.data.size());
232 csv.reserve (size()+1);
233 auto header = generateHeaderSpec();
235 swap (csv[0], header);
236 for (uint i=0; i < size(); ++i)
237 csv.emplace_back (formatCSVRow(i));
252 col.data.resize (siz);
265 col.data.emplace_back (col.data.back());
276 size_t siz = col.data.size();
277 col.data.resize (siz>0? siz-1 : 0);
282 reserve (
size_t expectedCapacity)
287 col.data.reserve(expectedCapacity);
302 appendFrom (
CSVData const& csv)
304 if (isnil (csv))
return;
305 verifyHeaderSpec (csv[0]);
306 for (
size_t row=1; row<csv.size(); ++row)
307 if (not isnil (csv[row]))
308 appendRowFromCSV (csv[row]);
315 save (
size_t lineLimit =std::numeric_limits<size_t>::max()
316 ,
bool backupOld =
false)
318 if (filename_.empty())
319 throw error::Logic{
"Unable to save DataFile without filename given."};
321 fs::path newFilename{filename_};
322 newFilename +=
".tmp";
324 std::ofstream csvFile{newFilename, std::ios_base::out | std::ios_base::trunc};
325 if (not csvFile.good())
328 saveData (csvFile, lineLimit);
332 fs::path oldFile{filename_};
334 if (fs::exists (filename_))
335 fs::rename (filename_, oldFile);
337 fs::rename (newFilename, filename_);
338 filename_ = fs::consolidated(filename_);
343 saveAs (fs::path newStorage
344 ,
size_t lineLimit =std::numeric_limits<size_t>::max())
346 newStorage = fs::consolidated (newStorage);
347 if (fs::exists(newStorage))
350 if (not (newStorage.parent_path().empty()
351 or fs::exists(newStorage.parent_path())))
353 % newStorage.filename() % newStorage.parent_path()};
354 filename_ = newStorage;
366 lib::meta::forEach (unConst(
this)->allColumns()
367 ,std::forward<OP> (doIt));
373 if (not (filename_.parent_path().empty()
374 or fs::exists(filename_.parent_path())))
376 % filename_.filename() % filename_.parent_path()};
377 if (not fs::exists(filename_))
380 std::ifstream csvFile{filename_};
381 if (not csvFile.good())
384 std::deque<string> rawLines;
385 for (
string line; std::getline(csvFile, line); )
386 rawLines.emplace_back (move(line));
388 if (rawLines.size() < 1)
return;
389 verifyHeaderSpec (rawLines[0]);
392 reserve (rawLines.size() - 1);
395 for (
size_t row = rawLines.size()-1; 0<row; --row)
396 if (not isnil(rawLines[row]))
397 appendRowFromCSV (rawLines[row]);
402 saveData (std::ofstream& csvFile,
size_t lineLimit)
404 csvFile << generateHeaderSpec() <<
"\n";
407 lineLimit = size() > lineLimit? size()-lineLimit : 0;
409 for (
size_t row = size(); lineLimit < row; --row)
410 csvFile << formatCSVRow(row-1) <<
"\n";
415 verifyHeaderSpec (
string headerLine)
421 if (*header != col.header)
423 "Expecting column(%s) but found \"%s\""}
424 % filename_ % col.header % *header};
430 generateHeaderSpec()
const 443 appendRowFromCSV (
string line)
452 if (csv.isParseFail())
456 % csv.getParsedFieldCnt() % columnCnt % line};
459 using Value =
typename std::remove_reference<decltype(col)>::type::ValueType;
460 col.get() = parseAs<Value>(*csv);
470 formatCSVRow (
size_t rownum)
const 473 throw error::Logic{
"Attempt to access data from empty DataTable."};
474 if (rownum >= this->size())
476 % rownum % (size()-1)};
482 csvLine += col.data.at(rownum);
Encoding and decoding of data into CSV format.
Wrapper to simplify notation in tests.
Includes the C++ Filesystem library and provides some convenience helpers.
A string with the ability to construct or append the CSV-rendering of data fields.
Types marked with this mix-in may be moved but not copied.
A front-end for using printf-style formatting.
Implementation namespace for support and library code.
Derived specific exceptions within Lumiera's exception hierarchy.
Mix-Ins to allow or prohibit various degrees of copying and cloning.
void save(size_t lineLimit=std::numeric_limits< size_t >::max(), bool backupOld=false)
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
Table with data values, stored persistently as CSV file.
Descriptor and Accessor for a data column within a DataTable table.
Lumiera error handling (C++ interface).
Parser to split one line of CSV data into fields.
void forAllColumns(OP &&doIt) const
apply a generic Lambda to all columns