25 #ifndef INCLUDED_CSV_h_GUID_30FA2504_8CCF_4B87_71C7_5974F968BC19
26 #define INCLUDED_CSV_h_GUID_30FA2504_8CCF_4B87_71C7_5974F968BC19
40 #include <type_traits>
41 #include <unordered_map>
46 template <
typename Derived>
class CSVBase;
48 template <
typename T>
class CellBase {
50 explicit CellBase(T
const &data) : data_(data) {}
53 T
const &getData()
const {
return data_; }
62 template <
typename T,
typename HeaderType = std::
string>
class Cell;
63 template <
typename T>
class Cell<T,
std::string> :
public CellBase<T> {
65 using Base = CellBase<T>;
66 Cell(std::string
const &header, T
const &data)
67 : Base(data), header_(header) {}
69 Cell(
const char *header, T
const &data)
70 : Base(data), header_(header) {}
71 Cell(std::string &&header, T
const &data)
72 : Base(data), header_(
std::move(header)) {}
74 std::string
const &getHeader()
const {
return header_; }
80 template <
typename T,
typename Dummy =
void>
struct CellStreamPrep {
81 static void prepareStream(std::ostream &) {
87 struct CellStreamPrep<T, typename
std::enable_if<
88 std::is_floating_point<T>::value>::type> {
89 static void prepareStream(std::ostream &os) {
91 os << std::setprecision(std::numeric_limits<T>::digits10 + 1);
97 inline void prepareStream(std::ostream &os, T
const &
cell) {
98 using DataValueConstType =
99 typename std::remove_reference<decltype(cell.getData())>::type;
100 using DataValueType =
101 typename std::remove_const<DataValueConstType>::type;
102 using PrepType = CellStreamPrep<DataValueType>;
103 PrepType::prepareStream(os);
130 : csv_(other.csv_), preparedRow_(other.preparedRow_),
131 active_(other.active_) {
134 other.active_ =
false;
142 if (active_ && preparedRow_) {
151 template <
typename... CellArgs>
154 std::ostringstream os;
155 prepareStream(os, c);
157 commonPostAdd(c.getHeader(), os.str());
163 void commonPreAdd() {
171 void commonPostAdd(std::string
const &header,
172 std::string
const &value) {
177 bool preparedRow_ =
false;
182 static const char COMMA[] =
",";
183 static const char DOUBLEQUOTE[] =
"\"";
184 static const char DOUBLEQUOTE_COMMA[] =
"\",";
185 static const char NEWLINE[] =
"\n";
191 using DataRow = std::vector<std::string>;
192 using column_id = std::size_t;
193 column_id getColumn(std::string
const &heading) {
194 auto it = columnsMap_.find(heading);
196 column_id ret = columns_.size();
197 if (end(columnsMap_) != it) {
203 columns_.push_back(heading);
204 columnsMap_.insert(std::make_pair(heading, ret));
207 column_id numColumns()
const {
return columns_.size(); }
210 void outputHeaders(std::ostream &os)
const {
211 for (
auto &colName : columns_) {
212 os << csv::DOUBLEQUOTE << colName << csv::DOUBLEQUOTE_COMMA;
218 std::vector<std::string> columns_;
219 std::unordered_map<std::string, column_id> columnsMap_;
223 template <
typename Derived,
typename... CellArgs>
225 operator<<(CSVRowProxy<Derived> &&row,
Cell<CellArgs...>
const &
cell) {
227 return std::move(row);
231 template <
typename Derived,
typename... CellArgs>
232 inline CSVRowProxy<Derived> &operator<<(CSVRowProxy<Derived> &row,
233 Cell<CellArgs...>
const &
cell) {
247 template <
typename Derived>
class CSVBase :
public detail::CSVCommonBase {
249 friend class detail::CSVRowProxy<Derived>;
250 using RowProxy = detail::CSVRowProxy<Derived>;
255 RowProxy
row() {
return RowProxy(*
this); }
273 std::string
const &data) {
274 auto col = getColumn(heading);
275 ensureLatestRowCanHoldColId(col);
283 derived().finalizeLatestRow();
292 void outputRow(std::ostream &os, DataRow
const &row)
const {
293 for (
auto &cell : row) {
294 os << cell << detail::csv::COMMA;
296 os << detail::csv::NEWLINE;
301 for (
auto &row : data_) {
308 data_.emplace_back(std::move(
latestRow()));
313 void ensureLatestRowCanHoldColId(column_id
id) {
320 Derived
const &derived()
const {
321 return *
static_cast<Derived
const *
>(
this);
324 Derived &derived() {
return *
static_cast<Derived *
>(
this); }
325 std::size_t rows_ = 0;
326 std::vector<DataRow> data_;
341 Base::outputHeaders(os);
360 friend class CSVBase<StreamCSV>;
372 Base::outputHeaders(m_stream);
380 std::ostream &m_stream;
385 bool m_streaming =
false;
389 void finalizeLatestRow() {
400 template <
typename T>
406 template <
typename T>
414 #endif // INCLUDED_CSV_h_GUID_30FA2504_8CCF_4B87_71C7_5974F968BC19
CSVRowProxy & operator=(CSVRowProxy const &)=delete
non-assignable
void moveLatestRowToData()
utility function for use in derived finalizeLatestRow()
CSVRowProxy(CSVRowProxy &&other)
move constructible
The main namespace for all C++ elements of the framework, internal and external.
void output(std::ostream &os) const
detail::size< coerce_list< Ts...>> size
Get the size of a list (number of elements.)
StreamCSV(std::ostream &os)
void outputData(std::ostream &os) const
Called by derived classes to output stored data rows.
void outputRow(std::ostream &os, DataRow const &row) const
void prepareForRow()
Called by CSVRowProxy life cycle, on row creation.
void dataForLatestRow(std::string const &heading, std::string const &data)
Called by CSVRowProxy life cycle, on cell addition.
std::size_t numRows() const
std::size_t numDataRows() const
void add(Cell< CellArgs...> const &c)
Truly shared base class for all CSV implementations.
detail::Cell< T > cell(const char *header, T const &data)
Helper free function to make a CSV cell.