UTL

Collection of self-contained header-only libraries for C++17

View on GitHub

utl::table

<- to README.md

<- to implementation.hpp

utl::table is a small header for exporting data to various tabular formats, it supports:

Useful numerical work with visualization and reports. Main design goals:

Below is a quick usage showcase:

Code Formats to
Image Image
Image Image
Image Image
Image Image
Image Image

Definitions

// Table formats
struct ASCII {
    explicit ASCII(std::size_t cols);
    
    template <class... T>
    void cell(T&&... args);
    
    void hline();
    
    std::string format() const;
};

struct Markdown {
    explicit Markdown(std::vector<std::string> title);
    
    template <class... T>
    void cell(T&&... args);
    
    std::string format();
};

struct LaTeX {
    explicit LaTeX(std::size_t cols);
    
    template <class... T>
    void cell(T&&... args);
    
    void hline();
    
    std::string format();
};

struct Mathematica {
    explicit Mathematica(std::size_t cols);
    
    template <class... T>
    void cell(T&&... args);
    
    void hline();
    
    std::string format();
};

struct CSV {
    explicit CSV(std::size_t cols) : matrix(cols);
    
    template <class... T>
    void cell(T&&... args);
    
    std::string format();
};

// Number formatting
template <class T>
struct Number {
    constexpr explicit Number(
        T                 value,
        std::chars_format format    = std::chars_format::general,
        int               precision = 3
    ) noexcept;
};

Methods

Table formats: ASCII

explicit ASCII(std::size_t cols);

Constructs ASCII table with cols columns.

template <class... T>
void cell(T&&... args);

Adds one or several cells to the table with args as their contents.

T can be an instance of any numeric, boolean, or string-convertible type.

Note: The table will automatically escape any control chars in the string (such as \r, \n and etc.) so it can be properly rendered in the terminal.

void hline();

Adds horizontal line to the table.

std::string format();

Formats table into a string.

Note: In case last row of the table “wasn’t finished”, it automatically gets completed with empty cells. This behavior holds true for every format.

Table formats: Markdown

explicit Markdown(std::vector<std::string> title);

Constructs Markdown table with given title. This results in title.size() columns.

template <class... T>
void cell(T&&... args);

Adds one or several cells to the table with args as their contents.

T can be an instance of any numeric, boolean, or string-convertible type.

Note: Since Markdown is implementation-defined, there are no specific restrictions imposed on the strings in the table. For example, some markdown flavors might want to export HTML cells, while other would consider such syntax to be invalid.

std::string format();

Formats table into a string.

Table formats: LaTeX

explicit LaTeX(std::size_t cols);

Constructs LaTeX table with cols columns.

template <class... T>
void cell(T&&... args);

Adds one or several cells to the table with args as their contents.

T can be an instance of any numeric, boolean, or string-convertible type.

Note 1: To allow export of hand-written LaTeX expressions, there are no specific restrictions on imposed strings in the table.

Note 2: Integer and floating point numbers will be formated as proper LaTeX formulas. This includes numbers in scientific and hex notation.

void hline();

Adds horizontal line to the table.

std::string format();

Formats table into a string.

Table formats: Mathematica

explicit Mathematica(std::size_t cols);

Constructs Mathematica table with cols columns.

template <class... T>
void cell(T&&... args);

Adds one or several cells to the table with args as their contents.

T can be an instance of any numeric, boolean, or string-convertible type.

Note 1: Mathematica strings can include almost any Unicode character. Double-quotes in the string are automatically escaped.

Note 2: Floating point numbers in scientific notation are formatted according to the Mathematica specification.

void hline();

Adds horizontal line to the table.

std::string format();

Formats table into a string.

Table formats: CSV

explicit CSV(std::size_t cols);

Constructs CSV table with cols columns.

template <class... T>
void cell(T&&... args);

Adds one or several cells to the table with args as their contents.

T can be an instance of any numeric, boolean, or string-convertible type.

Note: CSV is a format without standardized specification. This library refers to commonly supported RFC-4180 guidelines for format and special character handling.

void hline();

Adds horizontal line to the table.

std::string format();

Formats table into a string.

Number formatting

template <class T>
struct Number {
    constexpr explicit Number(
        T                 value,
        std::chars_format format    = std::chars_format::general,
        int               precision = 3
    ) noexcept;
};

A thin wrapper around the floating-point value used to specify its format. See corresponding example.

Examples

ASCII table

[ Run this code ]

utl::table::ASCII tb(4);

tb.hline();
tb.cell("Task", "Time", "Error", "Done");
tb.hline();
tb.cell("Work 1", 1.35, 3.7e-5, true );
tb.cell("Work 2", 1.35, 2.5e-8, false);
tb.hline();

std::cout << tb.format();

Output:

|--------|------|---------|-------|
| Task   | Time | Error   | Done  |
|--------|------|---------|-------|
| Work 1 | 1.35 | 3.7e-05 | true  |
| Work 2 | 1.35 | 2.5e-08 | false |
|--------|------|---------|-------|

Markdown table

[ Run this code ]

utl::table::Markdown tb({"Task", "Time", "Error", "Done"});

tb.cell("Work 1", 1.35, 3.7e-5, true );
tb.cell("Work 2", 1.35, 2.5e-8, false);

std::cout << tb.format();

Output:

| Task   | Time | Error   | Done    |
| ------ | ---- | ------- | ------- |
| Work 1 | 1.35 | 3.7e-05 | `true`  |
| Work 2 | 1.35 | 2.5e-08 | `false` |

LaTeX table

[ Run this code ]

utl::table::LaTeX tb(4);

tb.hline();
tb.cell("Task", "Time", "Error", "Done");
tb.hline();
tb.cell("Work 1", 1.35, 3.7e-5, true );
tb.cell("Work 2", 1.35, 2.5e-8, false);
tb.hline();

std::cout << tb.format();

Output:

\begin{tabular}{|c|c|c|c|}
\hline
    Task   & Time   & Error               & Done  \\
\hline
    Work 1 & $1.35$ & $3.7 \cdot 10^{-5}$ & true  \\
    Work 2 & $1.35$ & $2.5 \cdot 10^{-8}$ & false \\
\hline
\end{tabular}

Mathematica table

[ Run this code ]

utl::table::Mathematica tb(4);

tb.hline();
tb.cell("Task", "Time", "Error", "Done");
tb.hline();
tb.cell("Work 1", 1.35, 3.7e-5, true );
tb.cell("Work 2", 1.35, 2.5e-8, false);
tb.hline();

std::cout << tb.format();

Output:

Grid[{
    { "Task"  , "Time", "Error" , "Done" },
    { "Work 1", 1.35  , 3.7*^-05, True   },
    { "Work 2", 1.35  , 2.5*^-08, False  }
}, Dividers -> {All, {True, True, False, True}}]

CSV table

[ Run this code ]

utl::table::CSV tb(4);

tb.cell("Task", "Time", "Error", "Done");
tb.cell("Work 1", 1.35, 3.7e-5, true );
tb.cell("Work 2", 1.35, 2.5e-8, false);

std::cout << tb.format();

Output:

"Task","Time","Error","Done"
"Work 1",1.35,3.7e-05,true
"Work 2",1.35,2.5e-08,false

Floating-point formatting

[ Run this code ]

using namespace utl;

const auto format_number = [](double x) { return table::Number{x, std::chars_format::scientific, 1}; };

table::Markdown tb({"Method", "Error"});

tb.cell("Jacobi", format_number(3.475e-4));
tb.cell("Seidel", format_number(6.732e-6));

std::cout << tb.format();

Output:

| Method | Error   |
| ------ | ------- |
| Jacobi | 3.5e-04 |
| Seidel | 6.7e-06 |

Building tables cell-by-cell

[ Run this code ]

utl::table::Markdown tb({"Method", "Error", "Converged"});

// 1 call to 'cell()' doesn't necessarily have to fill the entire row at once
tb.cell("Jacobi");
tb.cell(3.475e-4);
tb.cell(false);

tb.cell("Seidel");
tb.cell(6.732e-6, true);

std::cout << tb.format();

Output:

| Method | Error     | Converged |
| ------ | --------- | --------- |
| Jacobi | 0.0003475 | `false`   |
| Seidel | 6.732e-06 | `true`    |