#include "TablePrinter.h" #include #include #include #include "stringTools.h" using std::ostream; using std::initializer_list; using std::invalid_argument; using std::vector; using std::string; TablePrinter::TablePrinter(ostream *stream, initializer_list columnWidths, int columnSpacing) : stream(stream), columnWidths(columnWidths.begin(), columnWidths.end()), columnSpacing(columnSpacing) { if (stream == nullptr) throw invalid_argument("stream is null."); if (columnWidths.size() < 1) throw invalid_argument("No columns defined."); if (std::any_of(columnWidths.begin(), columnWidths.end(), [](int width){ return width <= 1; })) { throw invalid_argument("All columns must have a width of at least 1."); } if (columnSpacing < 0) throw invalid_argument("columnSpacing must not be negative."); } void TablePrinter::printRow(initializer_list columns) const { if (columns.size() != columnWidths.size()) throw invalid_argument("Number of specified strings does not match number of defined columns."); // Some cells may span multiple lines. // Create matrix of text lines in columns. vector> strings(columns.size()); size_t lineCount = 0; { int columnIndex = 0; for (const string& column : columns) { vector lines = wrapString(column, columnWidths[columnIndex]); if (lines.size() > lineCount) lineCount = lines.size(); strings[columnIndex] = move(lines); columnIndex++; } // Make sure the matrix is uniform for (vector& columnRows : strings) { columnRows.resize(lineCount); } } // Save stream flags, restore them at end of scope boost::io::ios_flags_saver ifs(*stream); // Print lines *stream << std::left; string spacer(columnSpacing, ' '); for (size_t rowIndex = 0; rowIndex < lineCount; rowIndex++) { for (size_t columnIndex = 0; columnIndex < columns.size(); columnIndex++) { if (columnIndex != 0) { *stream << spacer; } *stream << std::setw(columnWidths[columnIndex]) << strings[columnIndex][rowIndex]; } *stream << std::endl; } }