Core Library  1.7.0.0
Library containing core utilities and tools for threading, networking, logging, INI and CSV file management etc.
CsvGridMain.h
Go to the documentation of this file.
1 // This file is part of CoreLibrary containing useful reusable utility
2 // classes.
3 //
4 // Copyright (C) 2014 to present, Duncan Crutchley
5 // Contact <dac1976github@outlook.com>
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Lesser General Public License as published
9 // by the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License and GNU Lesser General Public License
16 // for more details.
17 //
18 // You should have received a copy of the GNU General Public License
19 // and GNU Lesser General Public License along with this program. If
20 // not, see <http://www.gnu.org/licenses/>.
21 
27 #ifndef CSVGRIDMAIN
28 #define CSVGRIDMAIN
29 
30 #include <fstream>
31 #include <limits>
32 #include <cmath>
33 #include "CsvGridRow.h"
34 
36 namespace core_lib
37 {
39 namespace csv_grid
40 {
41 
44 {
46  truncate,
48  append
49 };
50 
81 template <template <class, class> class C, class T = Cell> class TCsvGrid final
82 {
83 public:
87  using container_type = C<row_type, std::allocator<row_type>>;
89  TCsvGrid() = default;
91  TCsvGrid(const TCsvGrid&) = default;
92 #ifdef USE_EXPLICIT_MOVE_
93 
94  TCsvGrid(TCsvGrid&& csvGrid)
95  {
96  *this = std::move(csvGrid);
97  }
98 #else
99 
100  TCsvGrid(TCsvGrid&&) = default;
101 #endif
102 
111  TCsvGrid(size_t rows, size_t cols)
112  {
113  if ((rows == 0) || (cols == 0))
114  {
115  BOOST_THROW_EXCEPTION(std::out_of_range("rows or cols is 0"));
116  }
117 
118  m_grid.resize(rows, row_type(cols));
119  }
130  TCsvGrid(const std::string& filename, eCellFormatOptions options)
131  {
132  LoadFromCSVFile(filename, options);
133  }
140  // cppcheck-suppress noExplicitConstructor
141  TCsvGrid(std::initializer_list<row_type> rows)
142  : m_grid(rows)
143  {
144  }
146  ~TCsvGrid() = default;
148  TCsvGrid& operator=(const TCsvGrid&) = default;
149 #ifdef USE_EXPLICIT_MOVE_
150 
151  TCsvGrid& operator=(TCsvGrid&& csvGrid)
152  {
153  std::swap(m_grid, csvGrid.m_grid);
154  return *this;
155  }
156 #else
157 
158  TCsvGrid& operator=(TCsvGrid&&) = default;
159 #endif
160 
169  row_type& operator[](size_t row)
170  {
171  if (row >= GetRowCount())
172  {
173  BOOST_THROW_EXCEPTION(std::out_of_range("row out of range"));
174  }
175 
176  return *std::next(m_grid.begin(), row);
177  }
187  const row_type& operator[](size_t row) const
188  {
189  if (row >= GetRowCount())
190  {
191  BOOST_THROW_EXCEPTION(std::out_of_range("row out of range"));
192  }
193 
194  return *std::next(m_grid.begin(), row);
195  }
200  bool Empty() const
201  {
202  return m_grid.empty();
203  }
208  size_t GetRowCount() const
209  {
210  return std::distance(m_grid.begin(), m_grid.end());
211  }
221  size_t GetColCount(size_t row) const
222  {
223  if (row >= GetRowCount())
224  {
225  BOOST_THROW_EXCEPTION(std::out_of_range("row out of range"));
226  }
227 
228  auto n = std::next(m_grid.begin(), row);
229  return n->GetSize();
230  }
238  void SetRowCount(size_t rows, size_t defaultCols = 0)
239  {
240  m_grid.resize(rows, row_type(defaultCols));
241  }
248  void AddRow(size_t cols = 0)
249  {
250  m_grid.emplace_back(cols);
251  }
257  // cppcheck-suppress functionConst
259  {
260  for (auto& row : m_grid)
261  {
262  row.AddColumn();
263  }
264  }
273  void InsertRow(size_t row, size_t defaultCols = 0)
274  {
275  if (row >= GetRowCount())
276  {
277  BOOST_THROW_EXCEPTION(std::out_of_range("row out of range"));
278  }
279 
280  m_grid.emplace(std::next(m_grid.begin(), row), defaultCols);
281  }
289  // cppcheck-suppress functionConst
290  void InsertColumnInAllRows(size_t col)
291  {
292  for (auto& row : m_grid)
293  {
294  if (col < row.GetSize())
295  {
296  row.InsertColumn(col);
297  }
298  }
299  }
306  // cppcheck-suppress functionConst
307  void ClearCells()
308  {
309  for (auto& row : m_grid)
310  {
311  row.ClearCells();
312  }
313  }
319  void ResetGrid()
320  {
321  m_grid.clear();
322  }
335  void LoadFromCSVFile(const std::string& filename, eCellFormatOptions options,
336  size_t firstRowToLoad = 0,
337  size_t maxNumRowsToLoad = std::numeric_limits<size_t>::max())
338  {
339  std::ifstream csvfile{filename.c_str()};
340 
341  if (!csvfile.is_open())
342  {
343  std::string err("failed to create file stream for loading: ");
344  err.append(filename);
345 
346  BOOST_THROW_EXCEPTION(std::runtime_error(err));
347  }
348 
349  m_grid.clear();
350  size_t rowCount = 0;
351  std::string row;
352  bool rowComplete = false;
353 
354  while (csvfile.good() && (m_grid.size() < maxNumRowsToLoad))
355  {
356  std::string line;
357  std::getline(csvfile, line);
359 
360  if ((csvfile.tellg() == csvfile.gcount()) || csvfile.eof())
361  {
362  if (line.compare("") == 0)
363  {
364  break;
365  }
366  }
367 
368  // Because a cell may have line breaks within it we have to
369  // accumulate lines from the file until we have a complete row.
370  // But as we join the lines back to gether to form a complete
371  // row we must add back in the new-line char for each line end.
372  if (!row.empty())
373  {
374  row.append("\n");
375  }
376 
377  row.append(line);
378 
379  if (ContainsEndOfRow(row))
380  {
381  rowComplete = true;
382  }
383 
384  if ((rowCount >= firstRowToLoad) && rowComplete)
385  {
386  m_grid.emplace_back(row, options);
387  }
388 
389  if (rowComplete)
390  {
391  ++rowCount;
392  rowComplete = false;
393  row.clear();
394  }
395  }
396 
397  csvfile.close();
398  }
408  void SaveToCsvFile(const std::string& filename,
410  {
411  std::ofstream csvfile;
412 
413  if (option == eSaveToFileOptions::append)
414  {
415  csvfile.open(filename.c_str(), std::ofstream::app);
416  }
417  else
418  {
419  csvfile.open(filename.c_str(), std::ofstream::trunc);
420  }
421 
422  if (!csvfile.is_open())
423  {
424  std::string err("failed to create file stream for saving: ");
425  err.append(filename);
426 
427  BOOST_THROW_EXCEPTION(std::runtime_error(err));
428  }
429 
430  OutputCsvGridToStream(csvfile);
431  csvfile.close();
432  }
433 
434 private:
441  void OutputCsvGridToStream(std::ostream& os) const
442  {
443  size_t row = 0;
444 
445  for (const auto& rowItem : m_grid)
446  {
447  rowItem.OutputRowToStream(os);
448 
449  if (row++ < GetRowCount() - 1)
450  {
451  os << std::endl;
452  }
453  }
454  }
465  static bool ContainsEndOfRow(const std::string& row)
466  {
467  std::string::difference_type numQuotes = std::count(row.begin(), row.end(), '"');
468  return (numQuotes % 2) == 0;
469  }
470 
471 private:
473  container_type m_grid{};
474 };
475 
476 } // namespace csv_grid
477 } // namespace core_lib
478 
479 #endif // CSVGRIDMAIN
Append the contents of the grid to the end of the file if it already exists.
void AddRow(size_t cols=0)
Add a new row.
Definition: CsvGridMain.h:248
Grid class with CSV file capabilities.
Definition: CsvGridMain.h:81
void InsertRow(size_t row, size_t defaultCols=0)
Insert a new row.
Definition: CsvGridMain.h:273
Class defining a row of the grid.
Definition: CsvGridRow.h:136
void ResetGrid()
Clear the entire grid.
Definition: CsvGridMain.h:319
size_t GetRowCount() const
Get the number of rows.
Definition: CsvGridMain.h:208
TCsvGrid(const std::string &filename, eCellFormatOptions options)
Initializing constructor.
Definition: CsvGridMain.h:130
void SetRowCount(size_t rows, size_t defaultCols=0)
Resize the grid.
Definition: CsvGridMain.h:238
const row_type & operator[](size_t row) const
Const subscript operator.
Definition: CsvGridMain.h:187
bool Empty() const
Get empty state of grid.
Definition: CsvGridMain.h:200
File containing declarations relating the CSVGridRow class.
void SaveToCsvFile(const std::string &filename, eSaveToFileOptions option=eSaveToFileOptions::truncate) const
Save the grid to a CSV file.
Definition: CsvGridMain.h:408
The core_lib namespace.
Definition: AsioDefines.h:59
Class defining a single cell within a row of the grid.
Definition: CsvGridCell.h:49
Truncate existing file replacing it with the contents of the grid.
void InsertColumnInAllRows(size_t col)
Insert a new column in all rows.
Definition: CsvGridMain.h:290
void LoadFromCSVFile(const std::string &filename, eCellFormatOptions options, size_t firstRowToLoad=0, size_t maxNumRowsToLoad=std::numeric_limits< size_t >::max())
Load a csv file into the grid.
Definition: CsvGridMain.h:335
size_t GetColCount(size_t row) const
Get the number of columns for a given row.
Definition: CsvGridMain.h:221
void AddColumnToAllRows()
Add a column to each row.
Definition: CsvGridMain.h:258
eSaveToFileOptions
Enumeration controlling how file is saved.
Definition: CsvGridMain.h:43
TCsvGrid(size_t rows, size_t cols)
Initializing constructor.
Definition: CsvGridMain.h:111
void OutputCsvGridToStream(std::ostream &os) const
Output the grid to a stream object.
Definition: CsvGridMain.h:441
C< row_type, std::allocator< row_type > > container_type
typedef for container type
Definition: CsvGridMain.h:87
void CORE_LIBRARY_DLL_SHARED_API PackStdString(std::string &line)
Tidy a string obtained from getline function.
Definition: StringUtils.cpp:47
void ClearCells()
Clear the contents of all cells.
Definition: CsvGridMain.h:307
static bool ContainsEndOfRow(const std::string &row)
Check if row string contains the actual end of the CSV row.
Definition: CsvGridMain.h:465
eCellFormatOptions
Cell format options enumeration.
Definition: CsvGridRow.h:61
row_type & operator[](size_t row)
Subscript operator.
Definition: CsvGridMain.h:169
TCsvGrid(std::initializer_list< row_type > rows)
Initializer list constructor.
Definition: CsvGridMain.h:141