-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtablePrinter.hh
136 lines (119 loc) · 4.38 KB
/
tablePrinter.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#pragma once
#include <iostream>
#include <numeric>
#include <sstream>
#include <string>
#include <vector>
class tablePrinter {
public:
tablePrinter(const std::string title, const std::vector<std::string>& headers,
const std::vector<std::vector<std::string>>& data)
: title_(title), columnHeaders_(headers), rowData_(data) {
// Check that all rows of data contain correct number of elements
for (size_t i = 0; i < rowData_.size(); i++) {
if (rowData_[i].size() != columnHeaders_.size()) {
std::cerr << "ERROR - Number of elements in table row " << i
<< " does not match the number of column headers."
<< std::endl;
exit(1);
}
}
// Initialise member variables
calcColumnWidths();
formatHeader();
formatRows();
initCommonStrings();
}
/** Print the table to stdout - `padding` refers to the number of tabs each
* line will be prefixed with. */
void print(int padding) {
// Print table title
std::string prefix(padding, '\t');
std::cout << prefix << title_ << std::endl;
// Print headers
std::cout << prefix << hLine_ << std::endl;
std::cout << prefix << headerLine_ << std::endl;
std::cout << prefix << hLineD_ << std::endl;
// Print all rows
for (size_t i = 0; i < rows_.size(); i++) {
std::cout << prefix << rows_[i] << std::endl;
std::cout << prefix << hLine_ << std::endl;
}
std::cout << std::endl;
}
private:
/** Calculates width of each column. */
void calcColumnWidths() {
for (size_t i = 0; i < columnHeaders_.size(); i++) {
// Find max width of each column using columnHeaders_ and rowData_
size_t maxWidth = columnHeaders_[i].size();
for (size_t j = 0; j < rowData_.size(); j++) {
if (rowData_[j][i].size() > maxWidth) maxWidth = rowData_[j][i].size();
}
// Once found max width, add 1 padding to either side
colWidths_.push_back(static_cast<int>(maxWidth + 2));
}
}
/** Format the table's header. */
void formatHeader() {
// Initialise stream
std::stringstream headerStream;
// Print left hand table boarder
headerStream << "|";
for (size_t i = 0; i < columnHeaders_.size(); i++) {
// Calculate how much padding to add after column header
int suffixPadding = colWidths_[i] - columnHeaders_[i].size() - 1;
// Add next column header with padding and right hand column divider to
// output stream
headerStream << " " << columnHeaders_[i]
<< std::string(suffixPadding, ' ') << "|";
}
// Save formatted column headers
headerLine_ = headerStream.str();
}
/** Format the table's rows. */
void formatRows() {
for (size_t i = 0; i < rowData_.size(); i++) {
std::stringstream rowStream;
// Print left hand table boarder
rowStream << "|";
for (size_t j = 0; j < rowData_[i].size(); j++) {
// Calculate how much padding to add after the printed data to fill
// column width
int suffixPadding = colWidths_[j] - rowData_[i][j].size() - 1;
// Add next piece of data to output stream with right hand column
// divider and padding
rowStream << " " << rowData_[i][j] << std::string(suffixPadding, ' ')
<< "|";
}
// Save formatted row
rows_.push_back(rowStream.str());
}
}
/** Initialises common strings. */
void initCommonStrings() {
int totalWidth = 1 + 1 +
std::accumulate(colWidths_.begin(), colWidths_.end(), 0) +
(columnHeaders_.size() - 1);
hLine_ = std::string(totalWidth, '-');
hLineD_ = std::string(totalWidth, '=');
}
/** The table's title. */
const std::string title_;
/** The header names for each column. */
const std::vector<std::string> columnHeaders_;
/** The rows of data - items of data per row must match number of columns
* defined in `columnHeaders_`. */
const std::vector<std::vector<std::string>> rowData_;
/** The correctly formatted table header. */
std::string headerLine_;
/** The correctly formatted table rows. */
std::vector<std::string> rows_;
/** The width of each column - each index corresponds to an index in
* `columnHeaders_`. */
std::vector<int> colWidths_;
/** A horizontal line of single width. */
std::string hLine_;
/** A horizontal line of double width. */
std::string hLineD_;
};