C++ Debugging for Competitive Programming

Competitive Programming requires quick thinking and coding ability. And for writing correct code, we have to debug it. And I feel that it would be great if we can display values of different datatypes/containers without much effort. If you also feel the same way, then read on!

Introduction

I believe in test driven development, in which we define the final functionality and then develop code to achieve it. So, let us define the functionality for this post:

Code:

#include<bits/stdc++.h>
using namespace std;

/*
  Debug Code
*/

int main() {
  set<int> s;
  map<char, pair<int, int> > m;
  m.insert(make_pair('a', make_pair(1, 1)));
  m.insert(make_pair('b', make_pair(2, 1)));
  debug(m, s);   // line number: x
  s.insert(2);
  s.insert(3);
  debug(s);     // line number: y
  return 0;
}

On running the code, we expect the following debugging report:

#13: m:[(a, (1, 1)), (b, (2, 1))]; s:[];
#16: s:[2, 3];

where #13 and #16 are line numbers of debug statements in the above code.

Functionality Development

Define the macros for the debug:

#define debugUtil(args...)     (Debugger()) , args
#define debug(args...) {
  __line_number(__LINE__);
  __evars(split(#args, ',').begin(), args);
}

here, __line_number() will print the line number, and __evars() will display the variable names along with their content using debugUtil() function.

  • Function __line_number():
inline void __line_number(int line) {
  std::cerr << "#" << line <<": ";
}
  • Function __evars():
inline void __evars(vector<string>::iterator it) {
  cerr << endl;
}

template<typename T, typename... Args>
inline void __evars(vector<string>::iterator it, T a, Args... args) {
    cerr << it->substr((*it)[0] == ' ', it->length()) << ":";
    debugUtil(a);
    __evars(++it, args...);
}

in the above code, we have used function overloading, where the second function will print the variable name, then call debugUtil() function and then recursively call itselt to display the next variable. If all variables have been displayed, then first function is called and we print newline.

  • Function split()
vector<string> split(const string& s, char c) {
    vector<string> v; stringstream ss(s); string x;
    while (getline(ss, x, c)) v.emplace_back(x); return move(v);
}

to split the debug string.

Debugger

And finally the debugger class:

class Debugger {
    public:
    Debugger(const std::string& _separator = ", ") :
    first(true), separator(_separator){}
    template<typename ObjectType>
    Debugger& operator , (const ObjectType& v) {
        if(!first) std::cerr << separator;
        std::cerr << v;
        first = false;
        return *this;
    }
    ~Debugger() {  std::cerr << "; "; }
    private:
    bool first;
    std::string separator;
};

template <typename T1, typename T2>
inline std::ostream& operator << (std::ostream& os, const std::pair<T1, T2>& p) {
    return os << "(" << p.first << ", " << p.second << ")";
}

template<typename T>
inline std::ostream &operator << (std::ostream & os,const std::vector<T>& v) {
    bool first = true;
    os << "[";
    for(unsigned int i = 0; i < v.size(); i++) {
        if(!first) os << ", ";
        os << v[i];
        first = false;
    }
    return os << "]";
}

template<typename T>
inline std::ostream &operator << (std::ostream & os,const std::set<T>& v) {
    bool first = true;
    os << "[";
    for (typename std::set<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) {
        if(!first) os << ", ";
        os << *ii;
        first = false;
    }
    return os << "]";
}

template<typename T1, typename T2>
inline std::ostream &operator << (std::ostream & os,const std::map<T1, T2>& v) {
    bool first = true;
    os << "[";
    for (typename std::map<T1, T2>::const_iterator ii = v.begin(); ii != v.end(); ++ii) {
        if(!first) os << ", ";
        os << *ii ;
        first = false;
    }
    return os << "]";
}

Below, I try to explain the different components of the above class declaration.

Explanation

Class definition:

class Debugger {
    public:
    Debugger(const std::string& _separator = ", ") :
    first(true), separator(_separator){}
    template<typename ObjectType>
    Debugger& operator , (const ObjectType& v) {
        if(!first) std::cerr << separator;
        std::cerr << v;
        first = false;
        return *this;
    }
    ~Debugger() {  std::cerr << "; "; }
    private:
    bool first;
    std::string separator;
};

And finally the complete code. See, it was so simple :)

Final Code

The final code looks the following:

/////////////////////////////// DEBUG ////////////////////////////////

vector<string> split(const string& s, char c) {
    vector<string> v; stringstream ss(s); string x;
    while (getline(ss, x, c)) v.emplace_back(x); return move(v);
}

class Debugger {
    public:
    Debugger(const std::string& _separator = ", ") :
    first(true), separator(_separator){}
    template<typename ObjectType>
    Debugger& operator , (const ObjectType& v) {
        if(!first) std::cerr << separator;
        std::cerr << v;
        first = false;
        return *this;
    }
    ~Debugger() {  std::cerr << "; "; }
    private:
    bool first;
    std::string separator;
};

template <typename T1, typename T2>
inline std::ostream& operator << (std::ostream& os, const std::pair<T1, T2>& p) {
    return os << "(" << p.first << ", " << p.second << ")";
}

template<typename T>
inline std::ostream &operator << (std::ostream & os,const std::vector<T>& v) {
    bool first = true;
    os << "[";
    for(unsigned int i = 0; i < v.size(); i++) {
        if(!first) os << ", ";
        os << v[i];
        first = false;
    }
    return os << "]";
}

template<typename T>
inline std::ostream &operator << (std::ostream & os,const std::set<T>& v) {
    bool first = true;
    os << "[";
    for (typename std::set<T>::const_iterator ii = v.begin(); ii != v.end(); ++ii) {
        if(!first) os << ", ";
        os << *ii;
        first = false;
    }
    return os << "]";
}

template<typename T1, typename T2>
inline std::ostream &operator << (std::ostream & os,const std::map<T1, T2>& v) {
    bool first = true;
    os << "[";
    for (typename std::map<T1, T2>::const_iterator ii = v.begin(); ii != v.end(); ++ii) {
        if(!first) os << ", ";
        os << *ii ;
        first = false;
    }
    return os << "]";
}

#define debugUtil(args...)     (Debugger()) , args
#define debug(args...) { __line_number(__LINE__); __evars(split(#args, ',').begin(), args); }

inline void __line_number(int line) { std::cerr << "#" << line <<": "; }
inline void __evars(vector<string>::iterator it) { cerr << endl; }

template<typename T, typename... Args>
inline void __evars(vector<string>::iterator it, T a, Args... args) {
    cerr << it->substr((*it)[0] == ' ', it->length()) << ":";
    debugUtil(a);
    __evars(++it, args...);
}

//////////////////////////////////////////////////////////////////////

you can copy the above code at the beginning of the code file.

Credits: I have taken inspiration from this ideone archive. I have tried to enhance it, to make it more useable.

Happy Coding 🤓

© Ritesh Kumar, 2020