Debugging the traditional way
Virtually every competitive programmer sometimes needs to print the values from some container, or array, or just a variable during debugging. This is where appear those ugly nested loops which take several minutes to write:
vector<int> a[4][6] = {{{2,3}, {4}}, {{6,2}, {4,5}}};
for(int i = 0; i < size(a); ++i, cout << endl){
for(int j = 0; j < size(a[i]); ++j, cout << endl){
for(int k : a[i][j]){
cout << k << ' ';
}
}
}
OMG, and bound checking for simple output of an array of vectors? 2D, 3D, it doesn't matter anymore if we can't write it concisely. And those stupid endls for empty cells...
Debugging with f_dbg()
I was fed up with traditional this and wrote a simple several-liner for printing almost everything one might want. The output is in python style. It has some limitations, but generally I like it.
You can find it here. My code exploits C++17 features, so choose the appropriate compiler.
The compact version is created from extended by means of http://removelinebreaks.net/
How formatted debug works
Let me call c-array, vector, deque, array just arr. Then, basically, f_dbg()
can output sub-arr. You just need to pass the name of arr and [two closed bounds] for each dimension, or omit several last bounds. If they are too large, f_dbg()
reduces them so that they are inside the arr. By default the bounds are set on start and end of each dimension.
If type of element of arr is some other arr-type, f_dbg()
is recursively called with this element as argument until the simplest types are reached. You know them: int, char, double, and so on. They are then neatly printed, and that's all.
Other data structures like maps, sets don't have any indices, that's why they are printed from begin to end. In maps, f_dbg()
is called both from the key and the value.
Pairs are printed the same way — recursive f_dbg()
from the first element and from the second.
/*-----------------------------------------------*/
Compare:
// traditional way(modified for similarity with f_dbg())
int x1 = 0;
int x2 = size(a)-1;
for(int i = x1; i <= x2; ++i, cout << endl){
int y1 = 0;
int y2 = size(a[i])-1;
for(int j = y1; j <= y2; ++j, cout << endl){
for(int k : a[i][j]){
cout << k << ' ';
}
}
}
// f_dbg()
f_dbg(a,0,1);
traditional version outputs:
2 3
4
6 2
4 5
/*...endls...*/
f_dbg()
outputs:
[[[2,3],[4],[]]
[[6,2],[4,5],[]]]
/*-----------------------------------------------*/
Debugging with n_dbg()
Ever dreamt of printing names of variables and their values the readable way without << "my_var" << my_var
?
Look at named debug
We can make use of macro functions. Let's do this:
#define _(x) string(#x), string(": "), x, string(", ")
It just substitutes the bare variable with its name, colon, value, and comma. We can now have a function that takes arbitrary number of arguments and calls f_dbg()
with each. Let's call this function n_dbg()
. We only have to write _()
around each argument we pass to it.
Compare:
string a = "dfs"; pair<int, string> b = {123, "ksdf"}; int c = 51;
cout << "a " << a << " | " << "b " << b.first << " " << b.second << " | " << "c " << c << endl;
n_dbg(_(a), _(b), _(c));
traditional version outputs:
a dfs | b 123 ksdf | c 51
n_dbg()
outputs:
[a: dfs, b: [123,ksdf], c: 51, ]
/*-----------------------------------------------*/
Hope this code saves your precious minutes during contests. Enjoy.
P.S. If you want to adapt this code to c++11 or 14, I don't mind if you clone this blog for (c++11/14 edition). Alternatively, you can suggest me your code to add to this post, so that all versions are together.
UPD1: output of unsigned int, long long, unsigned long long, long double, double added
UPD2: output for bitset added
UPD3: interface and interface description changed a bit
UPD4: n_dbg()
added