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
43 enum class eSaveToFileOptions
44 {
46 truncate,
48 append
49 };
50
81 template <template <class, class> class C, class T = Cell> class TCsvGrid final
82 {
83 public:
85 using row_type = TRow<C, T>;
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
258 void AddColumnToAllRows()
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);
358 string_utils::PackStdString(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,
409 eSaveToFileOptions option = eSaveToFileOptions::truncate) const
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
core_lib::csv_grid::eSaveToFileOptions::append
Append the contents of the grid to the end of the file if it already exists.
core_lib::csv_grid::TCsvGrid::AddRow
void AddRow(size_t cols=0)
Add a new row.
Definition: CsvGridMain.h:248
core_lib::csv_grid::TCsvGrid
Grid class with CSV file capabilities.
Definition: CsvGridMain.h:81
core_lib::csv_grid::TCsvGrid::InsertRow
void InsertRow(size_t row, size_t defaultCols=0)
Insert a new row.
Definition: CsvGridMain.h:273
core_lib::csv_grid::TRow
Class defining a row of the grid.
Definition: CsvGridRow.h:136
core_lib::csv_grid::TCsvGrid::ResetGrid
void ResetGrid()
Clear the entire grid.
Definition: CsvGridMain.h:319
core_lib::csv_grid::TCsvGrid::GetRowCount
size_t GetRowCount() const
Get the number of rows.
Definition: CsvGridMain.h:208
core_lib::csv_grid::TCsvGrid::TCsvGrid
TCsvGrid(const std::string &filename, eCellFormatOptions options)
Initializing constructor.
Definition: CsvGridMain.h:130
core_lib::csv_grid::TCsvGrid::SetRowCount
void SetRowCount(size_t rows, size_t defaultCols=0)
Resize the grid.
Definition: CsvGridMain.h:238
core_lib::csv_grid::TCsvGrid::operator[]
const row_type & operator[](size_t row) const
Const subscript operator.
Definition: CsvGridMain.h:187
core_lib::csv_grid::TCsvGrid::Empty
bool Empty() const
Get empty state of grid.
Definition: CsvGridMain.h:200
CsvGridRow.h
File containing declarations relating the CSVGridRow class.
core_lib::csv_grid::TCsvGrid::SaveToCsvFile
void SaveToCsvFile(const std::string &filename, eSaveToFileOptions option=eSaveToFileOptions::truncate) const
Save the grid to a CSV file.
Definition: CsvGridMain.h:408
core_lib
The core_lib namespace.
Definition: AsioDefines.h:59
core_lib::csv_grid::Cell
Class defining a single cell within a row of the grid.
Definition: CsvGridCell.h:49
core_lib::csv_grid::eSaveToFileOptions::truncate
Truncate existing file replacing it with the contents of the grid.
core_lib::csv_grid::TCsvGrid::InsertColumnInAllRows
void InsertColumnInAllRows(size_t col)
Insert a new column in all rows.
Definition: CsvGridMain.h:290
core_lib::csv_grid::TCsvGrid::LoadFromCSVFile
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
core_lib::csv_grid::TCsvGrid::GetColCount
size_t GetColCount(size_t row) const
Get the number of columns for a given row.
Definition: CsvGridMain.h:221
core_lib::csv_grid::TCsvGrid::AddColumnToAllRows
void AddColumnToAllRows()
Add a column to each row.
Definition: CsvGridMain.h:258
core_lib::csv_grid::eSaveToFileOptions
eSaveToFileOptions
Enumeration controlling how file is saved.
Definition: CsvGridMain.h:43
core_lib::csv_grid::TCsvGrid::TCsvGrid
TCsvGrid(size_t rows, size_t cols)
Initializing constructor.
Definition: CsvGridMain.h:111
core_lib::csv_grid::TCsvGrid::OutputCsvGridToStream
void OutputCsvGridToStream(std::ostream &os) const
Output the grid to a stream object.
Definition: CsvGridMain.h:441
core_lib::csv_grid::TCsvGrid::container_type
C< row_type, std::allocator< row_type > > container_type
typedef for container type
Definition: CsvGridMain.h:87
core_lib::string_utils::PackStdString
void CORE_LIBRARY_DLL_SHARED_API PackStdString(std::string &line)
Tidy a string obtained from getline function.
Definition: StringUtils.cpp:47
core_lib::csv_grid::TCsvGrid::ClearCells
void ClearCells()
Clear the contents of all cells.
Definition: CsvGridMain.h:307
core_lib::csv_grid::TCsvGrid::ContainsEndOfRow
static bool ContainsEndOfRow(const std::string &row)
Check if row string contains the actual end of the CSV row.
Definition: CsvGridMain.h:465
core_lib::csv_grid::eCellFormatOptions
eCellFormatOptions
Cell format options enumeration.
Definition: CsvGridRow.h:61
core_lib::csv_grid::TCsvGrid::operator[]
row_type & operator[](size_t row)
Subscript operator.
Definition: CsvGridMain.h:169
core_lib::csv_grid::TCsvGrid::TCsvGrid
TCsvGrid(std::initializer_list< row_type > rows)
Initializer list constructor.
Definition: CsvGridMain.h:141