File print_table.hpp

Enums

enum class VariadicTableColumnFormat

Used to specify the column format

Values:

enumerator AUTO
enumerator SCIENTIFIC
enumerator FIXED
enumerator PERCENT
template<class ...Ts>
class VariadicTable
#include <print_table.hpp>

A class for “pretty printing” a table of data.

Requries C++11 (and nothing more)

It’s templated on the types that will be in each column (all values in a column must have the same type)

For instance, to use it with data that looks like: “Fred”, 193.4, 35, “Sam” with header names: “Name”, “Weight”, “Age”, “Brother”

You would invoke the table like so: VariadicTable<std::string, double, int, std::string> vt(“Name”, “Weight”, “Age”, “Brother”);

Then add the data to the table: vt.addRow(“Fred”, 193.4, 35, “Sam”);

And finally print it: vt.print();

Public Types

typedef std::tuple<Ts...> DataTuple

The type stored for each row.

Public Functions

inline VariadicTable(std::vector<std::string> headers, unsigned int static_column_size = 0, unsigned int cell_padding = 1)

Construct the table with headers

Parameters:
  • headers – The names of the columns

  • static_column_size – The size of columns that can’t be found automatically

inline void addRow(Ts... entries)

Add a row of data

Easiest to use like: table.addRow({data1, data2, data3});

Parameters:

data – A Tuple of data to add

template<typename StreamType>
inline void print(StreamType &stream)

Pretty print the table of data

inline void setColumnFormat(const std::vector<VariadicTableColumnFormat> &column_format)

Set how to format numbers for each column

Note: this is ignored for std::string columns

@column_format The format for each column: MUST be the same length as the number of columns.

inline void setColumnPrecision(const std::vector<int> &precision)

Set how many digits of precision to show for floating point numbers

Note: this is ignored for std::string columns

@column_format The precision for each column: MUST be the same length as the number of columns.

Protected Types

typedef decltype(&std::right) right_type
typedef decltype(&std::left) left_type

Protected Functions

template<typename TupleType, typename StreamType>
inline 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

Original Idea From From https://stackoverflow.com/a/26908596

BTW: This would all be a lot easier with generic lambdas there would only need to be one of this sequence and then you could pass in a generic lambda. Unfortunately, that’s C++14 This ends the recursion

template<std::size_t I, typename TupleType, typename StreamType, typename = typename std::enable_if<I != std::tuple_size<typename std::remove_reference<TupleType>::type>::value>::type>
inline void print_each(TupleType &&t, StreamType &stream, std::integral_constant<size_t, I>)

This gets called on each item

template<typename TupleType, typename StreamType>
inline void print_each(TupleType &&t, StreamType &stream)

his is what gets called first

template<class T>
inline size_t sizeOfData(const T &data, decltype(((T*)nullptr)->size())* = nullptr)

Try to find the size the column will take up

If the datatype has a size() member… let’s call it

template<class T>
inline 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

If the datatype is an integer - let’s get it’s length

inline size_t sizeOfData(...)

If it doesn’t… let’s just use a statically set size

template<typename TupleType>
inline 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 vector End the recursion

template<std::size_t I, typename TupleType, typename = typename std::enable_if<I != std::tuple_size<typename std::remove_reference<TupleType>::type>::value>::type>
inline void size_each(TupleType &&t, std::vector<unsigned int> &sizes, std::integral_constant<size_t, I>)

Recursively called for each element

template<typename TupleType>
inline void size_each(TupleType &&t, std::vector<unsigned int> &sizes)

The function that is actually called that starts the recursion

inline void size_columns()

Finds the size each column should be and set it in _column_sizes

Protected Attributes

std::vector<std::string> _headers

The column headers.

unsigned int _num_columns

Number of columns in the table.

unsigned int _static_column_size

Size of columns that we can’t get the size of.

unsigned int _cell_padding

Size of the cell padding.

std::vector<DataTuple> _data

The actual data.

std::vector<unsigned int> _column_sizes

Holds the printable width of each column.

std::vector<VariadicTableColumnFormat> _column_format

Column Format.

std::vector<int> _precision

Precision For each column.

Protected Static Functions

template<typename T, typename = typename std::enable_if<std::is_arithmetic<typename std::remove_reference<T>::type>::value>::type>
static inline right_type justify(int)
template<typename T>
static inline left_type justify(long)