MaCh3  2.8.0
Reference Guide
TablePrinter.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <algorithm>
4 #include <cstddef>
5 #include <iomanip>
6 #include <sstream>
7 #include <string>
8 #include <string_view>
9 #include <utility>
10 #include <vector>
11 
12 #include "Manager/MaCh3Logger.h"
13 
14 namespace M3::Utils {
16 enum class Alignment {
17  Left,
18  Right,
19  Center
20 };
21 
23 struct ColumnSpec {
25  std::string name;
27  std::size_t minWidth = 0;
29  std::size_t maxWidth = 0;
32 };
33 
35 template <typename Container>
36 std::string join(const Container& values, std::string_view separator = " ") {
37  return fmt::format("{}", fmt::join(values, separator));
38 }
39 
43 template <typename T>
44 static std::string Cell(T&& value, std::string_view format) {
45  return fmt::format(fmt::runtime(format), std::forward<T>(value));
46 }
47 
50 class TablePrinter {
51  public:
53  explicit TablePrinter(std::vector<ColumnSpec> columns) : _columns(std::move(columns)) {}
54 
56  template <typename... Args>
57  void AddRow(Args&&... args) {
58  _rows.push_back({toString(std::forward<Args>(args))...});
59  }
60 
62  [[nodiscard]]
63  std::vector<std::string> Render() const
64  {
65  if (_columns.empty()) return {};
66 
67  const auto widths = CalculateWidths();
68 
69  std::vector<std::string> result;
70  result.reserve(_rows.size() + 4);
71 
72  // ┌──────┬────────┐
73  result.push_back(MakeBorder(widths, "┌", "┬", "┐", "─"));
74 
75  // │ Name │ Value │
76  result.push_back(MakeRow(widths, MakeHeader()));
77 
78  // ├──────┼────────┤
79  result.push_back(MakeBorder(widths, "├", "┼", "┤", "─"));
80 
81  // data rows
82  for (const auto& row : _rows)
83  result.push_back(MakeRow(widths, row));
84 
85  // └──────┴────────┘
86  result.push_back(MakeBorder(widths, "└", "┴", "┘", "─"));
87 
88  return result;
89  }
90 
91  private:
92  std::vector<ColumnSpec> _columns;
93  std::vector<std::vector<std::string>> _rows;
95  template <typename T>
96  static std::string toString(T&& value)
97  {
98  std::ostringstream os;
99  os << std::forward<T>(value);
100  return os.str();
101  }
103  static std::string Truncate(const std::string_view value, const std::size_t width)
104  {
105  if (value.size() <= width) return std::string(value);
106 
107  if (width == 0) return {};
108 
109  if (width == 1) return "…";
110 
111  return std::string(value.substr(0, width - 1)) + "…";
112  }
114  static std::string Align(
115  const std::string_view value,
116  const std::size_t width,
117  const Alignment alignment)
118  {
119  if (value.size() >= width){
120  return std::string(value);
121  }
122  const std::size_t padding = width - value.size();
123 
124  switch (alignment) {
125  case Alignment::Left:
126  return std::string(value) + std::string(padding, ' ');
127 
128  case Alignment::Right:
129  return std::string(padding, ' ') + std::string(value);
130 
131  case Alignment::Center: {
132  const std::size_t left = padding / 2;
133  const std::size_t right = padding - left;
134 
135  return std::string(left, ' ') + std::string(value) + std::string(right, ' ');
136  }
137  }
138  return std::string(value);
139  }
140 
141  std::vector<std::size_t> CalculateWidths() const
142  {
143  std::vector<std::size_t> widths;
144  widths.reserve(_columns.size());
145 
146  for (std::size_t col = 0; col < _columns.size(); ++col) {
147  auto width = _columns[col].name.size();
148 
149  for (const auto& row : _rows) {
150  if (col < row.size()) {
151  width = std::max(width, row[col].size());
152  }
153  }
154 
155  width = std::max(width, _columns[col].minWidth);
156 
157  if (_columns[col].maxWidth != 0){
158  width = std::min(width, _columns[col].maxWidth);
159  }
160  widths.push_back(width);
161  }
162 
163  return widths;
164  }
165 
166  std::vector<std::string> MakeHeader() const
167  {
168  std::vector<std::string> header(_columns.size());
169  for (std::size_t i = 0; i < _columns.size(); i++) {
170  header[i] = _columns[i].name;
171  }
172  return header;
173  }
174 
175  std::string MakeBorder(const std::vector<std::size_t>& widths,
176  const std::string_view left, const std::string_view middle,
177  const std::string_view right, const std::string_view horizontal) const {
178  std::string result;
179  result += left;
180 
181  for (std::size_t i = 0; i < widths.size(); ++i) {
182  for (std::size_t j = 0; j < widths[i] + 2; ++j) {
183  result += horizontal;
184  }
185  if (i + 1 < widths.size()) result += middle;
186  }
187 
188  result += right;
189  return result;
190  }
191 
192  std::string MakeRow(const std::vector<std::size_t>& widths,
193  const std::vector<std::string>& row) const {
194  std::string result = "│";
195 
196  for (std::size_t col = 0; col < widths.size(); ++col) {
197  std::string value;
198 
199  if (col < row.size()){
200  value = Truncate(row[col], widths[col]);
201  }
202  value = Align(value, widths[col], _columns[col].alignment);
203 
204  result += " ";
205  result += value;
206  result += " │";
207  }
208  return result;
209  }
210 };
211 } // namespace M3::Utils
MaCh3 Logging utilities built on top of SPDLOG.
Creates fancy formatted text tables for terminal output.
Definition: TablePrinter.h:50
static std::string Align(const std::string_view value, const std::size_t width, const Alignment alignment)
Alling to values to table deepening on values.
Definition: TablePrinter.h:114
TablePrinter(std::vector< ColumnSpec > columns)
Construct a table printer with the specified columns.
Definition: TablePrinter.h:53
std::vector< ColumnSpec > _columns
Definition: TablePrinter.h:92
static std::string toString(T &&value)
Convert a value to a string using stream formatting.
Definition: TablePrinter.h:96
std::vector< std::size_t > CalculateWidths() const
Definition: TablePrinter.h:141
std::string MakeBorder(const std::vector< std::size_t > &widths, const std::string_view left, const std::string_view middle, const std::string_view right, const std::string_view horizontal) const
Definition: TablePrinter.h:175
void AddRow(Args &&... args)
Add a row to the table.
Definition: TablePrinter.h:57
static std::string Truncate(const std::string_view value, const std::size_t width)
If name is longer than desired name we truncate for example instead of SuperLongBlarb we have SuperLo...
Definition: TablePrinter.h:103
std::vector< std::vector< std::string > > _rows
Definition: TablePrinter.h:93
std::string MakeRow(const std::vector< std::size_t > &widths, const std::vector< std::string > &row) const
Definition: TablePrinter.h:192
std::vector< std::string > Render() const
Render the complete table, with widths etc. defined by constructor.
Definition: TablePrinter.h:63
std::vector< std::string > MakeHeader() const
Definition: TablePrinter.h:166
Utility helpers used across MaCh3.
static std::string Cell(T &&value, std::string_view format)
Format a value using a runtime fmt format string.
Definition: TablePrinter.h:44
std::string join(const Container &values, std::string_view separator=" ")
Join all values in a container into a single string.
Definition: TablePrinter.h:36
Alignment
Column alignment.
Definition: TablePrinter.h:16
@ Center
Center text within the column.
@ Right
Align text to the right.
@ Left
Align text to the left.
Column specification used by TablePrinter.
Definition: TablePrinter.h:23
std::size_t maxWidth
Maximum column width. Use 0 for no maximum.
Definition: TablePrinter.h:29
std::string name
Column header displayed in the table.
Definition: TablePrinter.h:25
std::size_t minWidth
Minimum column width.
Definition: TablePrinter.h:27
Alignment alignment
Alignment of values within the column.
Definition: TablePrinter.h:31