https://mooseframework.inl.gov
Loading...
Searching...
No Matches
VariadicTable.h
Go to the documentation of this file.
1//* This file is part of the MOOSE framework
2//* https://mooseframework.inl.gov
3//*
4//* All rights reserved, see COPYRIGHT for full restrictions
5//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
6//*
7//* Licensed under LGPL 2.1, please see LICENSE for details
8//* https://www.gnu.org/licenses/lgpl-2.1.html
9
10#pragma once
11
20#include <iostream>
21#include <iomanip>
22#include <ios>
23#include <vector>
24#include <tuple>
25#include <type_traits>
26#include <cassert>
27#include <cmath>
28
33{
34 AUTO,
36 FIXED,
38};
39
60template <class... Ts>
62{
63public:
65 typedef std::tuple<Ts...> DataTuple;
66
73 VariadicTable(std::vector<std::string> headers,
74 unsigned int static_column_size = 0,
75 unsigned int cell_padding = 1)
76 : _headers(headers),
77 _num_columns(std::tuple_size<DataTuple>::value),
78 _static_column_size(static_column_size),
79 _cell_padding(cell_padding)
80 {
81 assert(headers.size() == _num_columns);
82 }
83
92 void addRow(Ts... entries) { _data.emplace_back(std::make_tuple(entries...)); }
93
97 template <typename StreamType>
98 void print(StreamType & stream)
99 {
100 size_columns();
101
102 // Start computing the total width
103 // First - we will have _num_columns + 1 "|" characters
104 unsigned int total_width = _num_columns + 1;
105
106 // Now add in the size of each colum
107 for (auto & col_size : _column_sizes)
108 total_width += col_size + (2 * _cell_padding);
109
110 // Print out the top line
111 stream << std::string(total_width, '-') << "\n";
112
113 // Print out the headers
114 stream << "|";
115 for (unsigned int i = 0; i < _num_columns; i++)
116 {
117 // Must find the center of the column
118 auto half = _column_sizes[i] / 2;
119 half -= _headers[i].size() / 2;
120
121 stream << std::string(_cell_padding, ' ') << std::setw(_column_sizes[i]) << std::left
122 << std::string(half, ' ') + _headers[i] << std::string(_cell_padding, ' ') << "|";
123 }
124
125 stream << "\n";
126
127 // Print out the line below the header
128 stream << std::string(total_width, '-') << "\n";
129
130 // Now print the rows of the table
131 for (auto & row : _data)
132 {
133 stream << "|";
134 print_each(row, stream);
135 stream << "\n";
136 }
137
138 // Print out the line below the header
139 stream << std::string(total_width, '-') << std::endl;
140 }
141
149 void setColumnFormat(const std::vector<VariadicTableColumnFormat> & column_format)
150 {
151 assert(column_format.size() == std::tuple_size<DataTuple>::value);
152
153 _column_format = column_format;
154 }
155
163 void setColumnPrecision(const std::vector<int> & precision)
164 {
165 assert(precision.size() == std::tuple_size<DataTuple>::value);
166 _precision = precision;
167 }
168
169protected:
170 // Attempts to figure out the correct justification for the data
171 template <typename T>
172 static auto justify(int /*firstchoice*/)
173 {
174 if constexpr (std::is_arithmetic<typename std::remove_reference<T>::type>::value)
175 // If it's a floating point value
176 return std::right;
177 else
178 // Otherwise
179 return std::left;
180 }
181
195 template <std::size_t I, typename TupleType, typename StreamType>
196 void print_each(TupleType && t, StreamType & stream, std::integral_constant<size_t, I>)
197 {
198 auto & val = std::get<I>(t);
199
200 auto original_precision = stream.precision();
201 auto original_flags = stream.flags();
202
203 // Set the precision
204 if (!_precision.empty())
205 {
206 assert(_precision.size() ==
207 std::tuple_size<typename std::remove_reference<TupleType>::type>::value);
208
209 stream << std::setprecision(_precision[I]);
210 }
211
212 // Set the format
213 if (!_column_format.empty())
214 {
215 assert(_column_format.size() ==
216 std::tuple_size<typename std::remove_reference<TupleType>::type>::value);
217
219 stream << std::scientific;
220
222 stream << std::fixed;
223
225 stream << std::fixed << std::setprecision(2);
226 }
227
228 stream << std::string(_cell_padding, ' ') << std::setw(_column_sizes[I])
229 << justify<decltype(val)>(0) << val << std::string(_cell_padding, ' ') << "|";
230
231 // Restore the format
232 if (!_column_format.empty())
233 stream.flags(original_flags);
234
235 // Restore the precision
236 if (!_precision.empty())
237 stream.precision(original_precision);
238
239 // Recursive call to print the next item (if there are any left)
240 if constexpr (I + 1 != std::tuple_size<typename std::remove_reference<TupleType>::type>::value)
241 print_each(std::forward<TupleType>(t), stream, std::integral_constant<size_t, I + 1>());
242 }
243
247 template <typename TupleType, typename StreamType>
248 void print_each(TupleType && t, StreamType & stream)
249 {
250 print_each(std::forward<TupleType>(t), stream, std::integral_constant<size_t, 0>());
251 }
252
258 template <class T>
259 size_t sizeOfData(const T & data, decltype(((T *)nullptr)->size()) * /*dummy*/ = nullptr)
260 {
261 return data.size();
262 }
263
269 template <class T>
270 size_t sizeOfData(const T & data,
271 typename std::enable_if<std::is_integral<T>::value>::type * /*dummy*/ = nullptr)
272 {
273 if (data == 0)
274 return 1;
275
276 return std::log10(data) + 1;
277 }
278
282 size_t sizeOfData(...) { return _static_column_size; }
283
292 template <typename TupleType>
293 void size_each(TupleType &&,
294 std::vector<unsigned int> & /*sizes*/,
295 std::integral_constant<
296 size_t,
297 std::tuple_size<typename std::remove_reference<TupleType>::type>::value>)
298 {
299 }
300
304 template <std::size_t I,
305 typename TupleType,
306 typename = typename std::enable_if<
307 I != std::tuple_size<typename std::remove_reference<TupleType>::type>::value>::type>
308 void
309 size_each(TupleType && t, std::vector<unsigned int> & sizes, std::integral_constant<size_t, I>)
310 {
311 sizes[I] = sizeOfData(std::get<I>(t));
312
313 // Override for Percent
314 if (!_column_format.empty())
316 sizes[I] = 6; // 100.00
317
318 // Continue the recursion
319 size_each(std::forward<TupleType>(t), sizes, std::integral_constant<size_t, I + 1>());
320 }
321
325 template <typename TupleType>
326 void size_each(TupleType && t, std::vector<unsigned int> & sizes)
327 {
328 size_each(std::forward<TupleType>(t), sizes, std::integral_constant<size_t, 0>());
329 }
330
335 {
337
338 // Temporary for querying each row
339 std::vector<unsigned int> column_sizes(_num_columns);
340
341 // Start with the size of the headers
342 for (unsigned int i = 0; i < _num_columns; i++)
343 _column_sizes[i] = _headers[i].size();
344
345 // Grab the size of each entry of each row and see if it's bigger
346 for (auto & row : _data)
347 {
348 size_each(row, column_sizes);
349
350 for (unsigned int i = 0; i < _num_columns; i++)
351 _column_sizes[i] = std::max(_column_sizes[i], column_sizes[i]);
352 }
353 }
354
356 std::vector<std::string> _headers;
357
359 unsigned int _num_columns;
360
363
365 unsigned int _cell_padding;
366
368 std::vector<DataTuple> _data;
369
371 std::vector<unsigned int> _column_sizes;
372
374 std::vector<VariadicTableColumnFormat> _column_format;
375
377 std::vector<int> _precision;
378};
VariadicTableColumnFormat
Note! This class comes from https://github.com/friedmud/variadic_table.
A class for "pretty printing" a table of data.
std::vector< std::string > _headers
The column headers.
unsigned int _static_column_size
Size of columns that we can't get the size of.
static auto justify(int)
void print(StreamType &stream)
Pretty print the table of data.
void print_each(TupleType &&t, StreamType &stream)
This is what gets called first.
unsigned int _cell_padding
Size of the cell padding.
std::vector< int > _precision
Precision For each column.
VariadicTable(std::vector< std::string > headers, unsigned int static_column_size=0, unsigned int cell_padding=1)
Construct the table with headers.
std::tuple< Ts... > DataTuple
The type stored for each row.
void size_each(TupleType &&, std::vector< unsigned int > &, std::integral_constant< size_t, std::tuple_size< typename std::remove_reference< TupleType >::type >::value >)
These three functions iterate over the Tuple, find the printed size of each element and set it in a v...
size_t sizeOfData(const T &data, typename std::enable_if< std::is_integral< T >::value >::type *=nullptr)
Try to find the size the column will take up.
std::vector< VariadicTableColumnFormat > _column_format
Column Format.
void addRow(Ts... entries)
Add a row of data.
void print_each(TupleType &&t, StreamType &stream, std::integral_constant< size_t, I >)
These three functions print out each item in a Tuple into the table.
void size_each(TupleType &&t, std::vector< unsigned int > &sizes)
The function that is actually called that starts the recursion.
unsigned int _num_columns
Number of columns in the table.
std::vector< DataTuple > _data
The actual data.
void setColumnFormat(const std::vector< VariadicTableColumnFormat > &column_format)
Set how to format numbers for each column.
void size_each(TupleType &&t, std::vector< unsigned int > &sizes, std::integral_constant< size_t, I >)
Recursively called for each element.
void setColumnPrecision(const std::vector< int > &precision)
Set how many digits of precision to show for floating point numbers.
size_t sizeOfData(...)
If it doesn't... let's just use a statically set size.
void size_columns()
Finds the size each column should be and set it in _column_sizes.
std::vector< unsigned int > _column_sizes
Holds the printable width of each column.
size_t sizeOfData(const T &data, decltype(((T *) nullptr) ->size()) *=nullptr)
Try to find the size the column will take up.