87 #ifndef LIB_STAT_DATA_H 88 #define LIB_STAT_DATA_H 98 #include <type_traits> 129 template<
typename VAL>
136 using ValueType = VAL;
158 operator VAL
const&()
const 160 return unConst(
this)->get();
164 VAL& operator= (X&& newVal)
166 return get() = std::forward<X> (newVal);
202 : filename_{fs::consolidated (csvFile)}
216 static constexpr
size_t columnCnt = std::tuple_size_v<decltype(std::declval<TAB>().allColumns())>;
221 return 0 == this->size();
227 if (0 == columnCnt)
return 0;
228 size_t rowCnt = std::numeric_limits<size_t>::max();
232 rowCnt = min (rowCnt, col.data.size());
241 csv.reserve (size()+1);
242 auto header = generateHeaderSpec();
243 std::swap (csv[0], header);
244 for (uint i=0; i < size(); ++i)
245 csv.emplace_back (formatCSVRow(i));
260 col.data.resize (siz);
273 col.data.emplace_back (col.data.back());
284 size_t siz = col.data.size();
285 col.data.resize (siz>0? siz-1 : 0);
290 reserve (
size_t expectedCapacity)
295 col.data.reserve(expectedCapacity);
310 appendFrom (
CSVData const& csv)
312 if (isnil (csv))
return;
313 verifyHeaderSpec (csv[0]);
314 for (
size_t row=1; row<csv.size(); ++row)
315 if (not isnil (csv[row]))
316 appendRowFromCSV (csv[row]);
323 save (
size_t lineLimit =std::numeric_limits<size_t>::max()
324 ,
bool backupOld =
false)
326 if (filename_.empty())
327 throw error::Logic{
"Unable to save DataFile without filename given."};
329 fs::path newFilename{filename_};
330 newFilename +=
".tmp";
332 std::ofstream csvFile{newFilename, std::ios_base::out | std::ios_base::trunc};
333 if (not csvFile.good())
336 saveData (csvFile, lineLimit);
340 fs::path oldFile{filename_};
342 if (fs::exists (filename_))
343 fs::rename (filename_, oldFile);
345 fs::rename (newFilename, filename_);
346 filename_ = fs::consolidated(filename_);
351 saveAs (fs::path newStorage
352 ,
size_t lineLimit =std::numeric_limits<size_t>::max())
354 newStorage = fs::consolidated (newStorage);
355 if (fs::exists(newStorage))
358 if (not (newStorage.parent_path().empty()
359 or fs::exists(newStorage.parent_path())))
361 % newStorage.filename() % newStorage.parent_path()};
362 filename_ = newStorage;
374 lib::meta::forEach (unConst(
this)->allColumns()
375 ,std::forward<OP> (doIt));
381 if (not (filename_.parent_path().empty()
382 or fs::exists(filename_.parent_path())))
384 % filename_.filename() % filename_.parent_path()};
385 if (not fs::exists(filename_))
388 std::ifstream csvFile{filename_};
389 if (not csvFile.good())
392 std::deque<string> rawLines;
393 for (
string line; std::getline(csvFile, line); )
394 rawLines.emplace_back (move(line));
396 if (rawLines.size() < 1)
return;
397 verifyHeaderSpec (rawLines[0]);
400 reserve (rawLines.size() - 1);
403 for (
size_t row = rawLines.size()-1; 0<row; --row)
404 if (not isnil(rawLines[row]))
405 appendRowFromCSV (rawLines[row]);
410 saveData (std::ofstream& csvFile,
size_t lineLimit)
412 csvFile << generateHeaderSpec() <<
"\n";
415 lineLimit = size() > lineLimit? size()-lineLimit : 0;
417 for (
size_t row = size(); lineLimit < row; --row)
418 csvFile << formatCSVRow(row-1) <<
"\n";
423 verifyHeaderSpec (
string headerLine)
429 if (*header != col.header)
431 "Expecting column(%s) but found \"%s\""}
432 % filename_ % col.header % *header};
438 generateHeaderSpec()
const 451 appendRowFromCSV (
string line)
460 if (csv.isParseFail())
464 % csv.getParsedFieldCnt() % columnCnt % line};
467 using Value =
typename std::remove_reference<decltype(col)>::type::ValueType;
468 col.get() = parseAs<Value>(*csv);
478 formatCSVRow (
size_t rownum)
const 481 throw error::Logic{
"Attempt to access data from empty DataTable."};
482 if (rownum >= this->size())
484 % rownum % (size()-1)};
490 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