42

pprint: Pretty Printer for Modern C++

 4 years ago
source link: https://www.tuicool.com/articles/hit/YRV3m2I
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

YJFnAvY.png!web

Highlights

  • Single header file
  • Requires C++17
  • MIT License

Quick Start

Simply include pprint.hpp and you're good to go.

#include <pprint.hpp>

To start printing, create a PrettyPrinter

pprint::PrettyPrinter printer;

You can construct a PrettyPrinter with any stream that inherits from std::ostream , e.g, std::stringstream

std::stringstream stream;
pprint::PrettyPrinter printer(stream);

Fundamental Types

printer.print(5);
printer.print(3.14f);
printer.print(2.718);
printer.print(true);
printer.print('x');
printer.print("Hello, 世界");
printer.print(nullptr);
5
3.14f
2.718
true
'x'
"Hello, 世界"
nullptr

Strings

Maybe you don't want your strings to be quoted? Simply set printer.quotes(false)

printer.quotes(false);
printer.print('A', 'B', 'C');   // parameter packing
printer.print("1 2 3");
A B C
1 2 3

Complex Numbers

using namespace std::complex_literals;
std::complex<double> cfoo = 1. + 2.5i;
std::complex<double> cbar = 9. + 4i;
printer.print(cfoo, "*", cbar, "=", (cfoo * cbar));   // parameter packing
(1 + 2.5i) * (9 + 4i) = (-1 + 26.5i)

Enumeration Types

enum Color { RED = 2, BLUE = 4, GREEN = 8 };
Color color = BLUE;
printer.print(color);

If you compile with

  • Clang/LLVM >= 5
  • Visual C++ >= 15.3 / Visual Studio >= 2017
  • Xcode >= 10.2
  • GCC >= 9

then pprint will print the name of the enum for you (thanks to magic_enum )

enum Level { LOW, MEDIUM, HIGH };
Level current_level = MEDIUM;
std::cout << "Current level: ";
printer.print(current_level);
Current level: MEDIUM

STL Sequence Containers

pprint supports a variety of STL sequence containers including std::vector , std::list , std::deque , and std::array .

Here's an exmaple pretty print of a simple 3x3 matrix:

typedef std::array<std::array<int, 3>, 3> Mat3x3;
Mat3x3 matrix;
matrix[0] = {1, 2, 3};
matrix[1] = {4, 5, 6};
matrix[2] = {7, 8, 9};
printer.print(matrix);
[
  [1, 2, 3], 
  [4, 5, 6], 
  [7, 8, 9]
]

Compact Printing

pprint also supports compact printing of containers. Simply call printer.compact(true) to enable this:

std::vector<std::map<std::string, int>> foo {{{"a", 1}, {"b", 2}}, {{"c", 3}, {"d", 4}}};
printer.compact(true);
std::cout << "Foo = ";
printer.print(foo);
Foo = [{"a" : 1, "b" : 2}, {"c" : 3, "d" : 4}]

STL Associative Containers

Support for associative containers includes pretty printing of std::map , std::multimap , std::unordered_map , std::unordered_multimap , std::set , std::multiset , std::unordered_set and , std::unordered_multiset

printer.print(std::map<std::string, std::set<int>>{ 
    {"foo", {1, 2, 3, 3, 2, 1}}, {"bar", {7, 6, 5, 4}}});
{
  "bar" : {4, 5, 6, 7}, 
  "foo" : {1, 2, 3}
}

STL Container Adaptors

pprint can print container adaptors including std::queue , std::priority_queue and std::stack . Here's an example print of a priority queue:

std::priority_queue<int> queue;
for(int n : {1,8,5,6,3,4,0,9,7,2})
  queue.push(n);
printer.print(queue);
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

Fixed-size Heterogeneous Tuples

auto get_student = [](int id) {
  if (id == 0) return std::make_tuple(3.8, 'A', "Lisa Simpson");
  if (id == 1) return std::make_tuple(2.9, 'C', "Milhouse Van Houten");
  if (id == 2) return std::make_tuple(1.7, 'D', "Ralph Wiggum");
  throw std::invalid_argument("id");
};
printer.print({ get_student(0), get_student(1), get_student(2) });
{(1.7, 'D', "Ralph Wiggum"), (2.9, 'C', "Milhouse Van Houten"), (3.8, 'A', "Lisa Simpson")}

Type-safe Unions

// Construct a vector of values
std::vector<std::variant<bool, int, int *, float, std::string, std::vector<int>,		      
       std::map<std::string, std::map<std::string, int>>, 
       std::pair<double, double>>> var;
var.push_back(5);
var.push_back(nullptr);
var.push_back(3.14f);
var.push_back(std::string{"Hello World"});
var.push_back(std::vector<int>{1, 2, 3, 4});
var.push_back(std::map<std::string, std::map<std::string, int>>{{"a",{{"b",1}}}, {"c",{{"d",2}, {"e",3}}}});
var.push_back(true);
var.push_back(std::pair<double, double>{1.1, 2.2});

// Print the vector
pprint::PrettyPrinter printer;
printer.indent(2);
printer.print(var);
[
  5, 
  nullptr,
  3.14f, 
  "Hello World", 
  [1, 2, 3, 4], 
  {"a" : {"b" : 1}, "c" : {"d" : 2, "e" : 3}}, 
  true, 
  (1.1, 2.2)
]

Optional Values

std::optional<int> opt = 5;
std::optional<int> opt2;

printer.print(opt);
printer.print(opt2);
5
nullopt

Class Objects

pprint print class objects with or without an overloaded << operator

class Foo {};
Foo foo;
printer.print(foo);
<Object main::Foo at 0x7ffc8c820890>

If an << operator is available, pprint will use it to print your object:

class Date {
  unsigned int month, day, year;
public:
  Date(unsigned int m, unsigned int d, unsigned int y) : month(m), day(d), year(y) {}
  friend std::ostream& operator<<(std::ostream& os, const Date& dt);
};

    
std::ostream& operator<<(std::ostream& os, const Date& dt) {
  os << dt.month << '/' << dt.day << '/' << dt.year;
  return os;
}
Date date(04, 07, 2019);
std::cout << "Today's date is ";
printer.print(date);
Today's date is 4/7/2019

License

The project is available under the MIT license.


Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK