HOG2
Table.h
Go to the documentation of this file.
1 #include <iostream>
2 #include <iomanip>
3 #include <ios>
4 #include <vector>
5 #include <tuple>
6 #include <type_traits>
7 #include <cassert>
8 #include <cmath>
9 
11 {
12  kAUTO,
14  kFIXED,
15  kPERCENT
16 };
17 
18 
19 template <class... Ts>
20 class Table
21 {
22 public:
23  typedef std::tuple<Ts...> DataTuple;
24 
31  Table(std::vector<std::string> headers,
32  unsigned int static_column_size = 0,
33  unsigned int cell_padding = 1)
34  : _headers(headers),
35  _num_columns(std::tuple_size<DataTuple>::value),
36  _static_column_size(static_column_size),
37  _cell_padding(cell_padding)
38  {
39  assert(headers.size() == _num_columns);
40  }
41 
50  void addRow(Ts... entries) { _data.emplace_back(std::make_tuple(entries...)); }
51 
55  template <typename StreamType>
56  void print(StreamType & stream)
57  {
58  size_columns();
59 
60  // Start computing the total width
61  // _num_columns + 1 "|" characters
62  unsigned int total_width = _num_columns + 1;
63 
64  // Now add in the size of each colum
65  for (auto & col_size : _column_sizes)
66  total_width += col_size + (2 * _cell_padding);
67 
68  // Print out the top line
69  stream << std::string(total_width, '-') << "\n";
70 
71  // Print out the headers
72  stream << "|";
73  for (unsigned int i = 0; i < _num_columns; i++)
74  {
75  // Must find the center of the column
76  auto half = _column_sizes[i] / 2;
77  half -= _headers[i].size() / 2;
78 
79  stream << std::string(_cell_padding, ' ') << std::setw(_column_sizes[i]) << std::left
80  << std::string(half, ' ') + _headers[i] << std::string(_cell_padding, ' ') << "|";
81  }
82 
83  stream << "\n";
84 
85  // Print out the line below the header
86  stream << std::string(total_width, '-') << "\n";
87 
88  // Now print the rows of the table
89  for (auto & row : _data)
90  {
91  stream << "|";
92  print_each(row, stream);
93  stream << "\n";
94  }
95 
96  // Print out the line below the header
97  stream << std::string(total_width, '-') << "\n";
98  }
99 
107  void setColumnFormat(const std::vector<TableColumnFormat> & column_format)
108  {
109  assert(column_format.size() == std::tuple_size<DataTuple>::value);
110 
111  _column_format = column_format;
112  }
113 
121  void setColumnPrecision(const std::vector<int> & precision)
122  {
123  assert(precision.size() == std::tuple_size<DataTuple>::value);
124  _precision = precision;
125  }
126 
127 protected:
128  // Just some handy typedefs for the following two functions
129  typedef decltype(&std::right) right_type;
130  typedef decltype(&std::left) left_type;
131 
132  // Attempts to figure out the correct justification for the data
133  // If it's a floating point value
134  template <typename T,
135  typename = typename std::enable_if<
136  std::is_arithmetic<typename std::remove_reference<T>::type>::value>::type>
137  static right_type justify(int /*firstchoice*/)
138  {
139  return std::right;
140  }
141 
142  // Otherwise
143  template <typename T>
144  static left_type justify(long /*secondchoice*/)
145  {
146  return std::left;
147  }
148 
162  template <typename TupleType, typename StreamType>
163  void print_each(TupleType &&,
164  StreamType & /*stream*/,
165  std::integral_constant<
166  size_t,
167  std::tuple_size<typename std::remove_reference<TupleType>::type>::value>)
168  {
169  }
170 
174  template <std::size_t I,
175  typename TupleType,
176  typename StreamType,
177  typename = typename std::enable_if<
178  I != std::tuple_size<typename std::remove_reference<TupleType>::type>::value>::type>
179  void print_each(TupleType && t, StreamType & stream, std::integral_constant<size_t, I>)
180  {
181  auto & val = std::get<I>(t);
182 
183  // Set the precision
184  if (!_precision.empty())
185  {
186  assert(_precision.size() ==
187  std::tuple_size<typename std::remove_reference<TupleType>::type>::value);
188 
189  stream << std::setprecision(_precision[I]);
190  }
191 
192  // Set the format
193  if (!_column_format.empty())
194  {
195  assert(_column_format.size() ==
196  std::tuple_size<typename std::remove_reference<TupleType>::type>::value);
197 
199  stream << std::scientific;
200 
202  stream << std::fixed;
203 
205  stream << std::fixed << std::setprecision(2);
206  }
207 
208  stream << std::string(_cell_padding, ' ') << std::setw(_column_sizes[I])
209  << justify<decltype(val)>(0) << val << std::string(_cell_padding, ' ') << "|";
210 
211  // Unset the format
212  if (!_column_format.empty())
213  {
214  // Because "stream << std::defaultfloat;" won't compile with old GCC or Clang
215  stream.unsetf(std::ios_base::floatfield);
216  }
217 
218  // Recursive call to print the next item
219  print_each(std::forward<TupleType>(t), stream, std::integral_constant<size_t, I + 1>());
220  }
221 
225  template <typename TupleType, typename StreamType>
226  void print_each(TupleType && t, StreamType & stream)
227  {
228  print_each(std::forward<TupleType>(t), stream, std::integral_constant<size_t, 0>());
229  }
230 
236  template <class T>
237  size_t sizeOfData(const T & data, decltype(((T *)nullptr)->size()) * /*dummy*/ = nullptr)
238  {
239  return data.size();
240  }
241 
247  template <class T>
248  size_t sizeOfData(const T & data,
249  typename std::enable_if<std::is_integral<T>::value>::type * /*dummy*/ = nullptr)
250  {
251  if (data == 0)
252  return 1;
253 
254  return std::log10(data) + 1;
255  }
256 
260  size_t sizeOfData(...) { return _static_column_size; }
261 
270  template <typename TupleType>
271  void size_each(TupleType &&,
272  std::vector<unsigned int> & /*sizes*/,
273  std::integral_constant<
274  size_t,
275  std::tuple_size<typename std::remove_reference<TupleType>::type>::value>)
276  {
277  }
278 
282  template <std::size_t I,
283  typename TupleType,
284  typename = typename std::enable_if<
285  I != std::tuple_size<typename std::remove_reference<TupleType>::type>::value>::type>
286  void
287  size_each(TupleType && t, std::vector<unsigned int> & sizes, std::integral_constant<size_t, I>)
288  {
289  sizes[I] = sizeOfData(std::get<I>(t));
290 
291  // Override for Percent
292  if (!_column_format.empty())
294  sizes[I] = 6; // 100.00
295 
296  // Continue the recursion
297  size_each(std::forward<TupleType>(t), sizes, std::integral_constant<size_t, I + 1>());
298  }
299 
303  template <typename TupleType>
304  void size_each(TupleType && t, std::vector<unsigned int> & sizes)
305  {
306  size_each(std::forward<TupleType>(t), sizes, std::integral_constant<size_t, 0>());
307  }
308 
313  {
314  _column_sizes.resize(_num_columns);
315 
316  // Temporary for querying each row
317  std::vector<unsigned int> column_sizes(_num_columns);
318 
319  // Start with the size of the headers
320  for (unsigned int i = 0; i < _num_columns; i++)
321  _column_sizes[i] = _headers[i].size();
322 
323  // Grab the size of each entry of each row and see if it's bigger
324  for (auto & row : _data)
325  {
326  size_each(row, column_sizes);
327 
328  for (unsigned int i = 0; i < _num_columns; i++)
329  _column_sizes[i] = std::max(_column_sizes[i], column_sizes[i]);
330  }
331  }
332 
334  std::vector<std::string> _headers;
335 
337  unsigned int _num_columns;
338 
340  unsigned int _static_column_size;
341 
343  unsigned int _cell_padding;
344 
346  std::vector<DataTuple> _data;
347 
349  std::vector<unsigned int> _column_sizes;
350 
352  std::vector<TableColumnFormat> _column_format;
353 
355  std::vector<int> _precision;
356 };
Table::addRow
void addRow(Ts... entries)
Add a row of data.
Definition: Table.h:50
TableColumnFormat::kSCIENTIFIC
@ kSCIENTIFIC
Table::_column_sizes
std::vector< unsigned int > _column_sizes
Holds the printable width of each column.
Definition: Table.h:349
Table::print_each
void print_each(TupleType &&t, StreamType &stream, std::integral_constant< size_t, I >)
This gets called on each item.
Definition: Table.h:179
Table::print_each
void print_each(TupleType &&, StreamType &, std::integral_constant< size_t, std::tuple_size< typename std::remove_reference< TupleType >::type >::value >)
These three functions print out each item in a Tuple into the table.
Definition: Table.h:163
Table::print_each
void print_each(TupleType &&t, StreamType &stream)
This is what gets called first.
Definition: Table.h:226
TableColumnFormat::kPERCENT
@ kPERCENT
Table::_static_column_size
unsigned int _static_column_size
Size of columns that we can't get the size of.
Definition: Table.h:340
Table::Table
Table(std::vector< std::string > headers, unsigned int static_column_size=0, unsigned int cell_padding=1)
Construct the table with headers.
Definition: Table.h:31
Table::size_each
void size_each(TupleType &&t, std::vector< unsigned int > &sizes, std::integral_constant< size_t, I >)
Recursively called for each element.
Definition: Table.h:287
Table::_headers
std::vector< std::string > _headers
The column headers.
Definition: Table.h:334
Table::print
void print(StreamType &stream)
Print the table of data.
Definition: Table.h:56
Table::DataTuple
std::tuple< Ts... > DataTuple
Definition: Table.h:23
Table::size_each
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...
Definition: Table.h:271
TableColumnFormat
TableColumnFormat
Definition: Table.h:10
Table::size_columns
void size_columns()
Finds the size each column should be and set it in _column_sizes.
Definition: Table.h:312
TableColumnFormat::kFIXED
@ kFIXED
Table::_precision
std::vector< int > _precision
Precision For each column.
Definition: Table.h:355
Table::setColumnPrecision
void setColumnPrecision(const std::vector< int > &precision)
Set how many digits of precision to show for floating point numbers.
Definition: Table.h:121
Table::_num_columns
unsigned int _num_columns
Number of columns in the table.
Definition: Table.h:337
Table::setColumnFormat
void setColumnFormat(const std::vector< TableColumnFormat > &column_format)
Set how to format numbers for each column.
Definition: Table.h:107
Table::_cell_padding
unsigned int _cell_padding
Size of the cell padding.
Definition: Table.h:343
Table::sizeOfData
size_t sizeOfData(...)
If it doesn't...
Definition: Table.h:260
TableColumnFormat::kAUTO
@ kAUTO
max
#define max(a, b)
Definition: MinimalSectorAbstraction.cpp:40
Table::justify
static left_type justify(long)
Definition: Table.h:144
Table::size_each
void size_each(TupleType &&t, std::vector< unsigned int > &sizes)
The function that is actually called that starts the recursion.
Definition: Table.h:304
std
Definition: CanonicalGraphEnvironment.h:26
Table::right_type
decltype(&std::right) typedef right_type
Definition: Table.h:129
Table
Definition: Table.h:20
Table::justify
static right_type justify(int)
Definition: Table.h:137
Table::sizeOfData
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.
Definition: Table.h:248
Table::sizeOfData
size_t sizeOfData(const T &data, decltype(((T *) nullptr) ->size()) *=nullptr)
Try to find the size the column will take up.
Definition: Table.h:237
Table::_data
std::vector< DataTuple > _data
The actual data.
Definition: Table.h:346
Table::left_type
decltype(&std::left) typedef left_type
Definition: Table.h:130
Table::_column_format
std::vector< TableColumnFormat > _column_format
Column Format.
Definition: Table.h:352