/* This file is part of Jellyfish.
Jellyfish is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Jellyfish is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Jellyfish. If not, see .
*/
#ifndef __DBG_HPP__
#define __DBG_HPP__
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
namespace dbg {
pid_t gettid();
class stringbuf : public std::stringbuf {
public:
stringbuf() : std::stringbuf(std::ios_base::out) { }
explicit stringbuf(const std::string &str) :
std::stringbuf(str, std::ios_base::out) { }
bool end_is_space() {
if(pptr() == pbase())
return true;
return isspace(*(pptr() - 1));
}
friend class print_t;
};
class str {
const char *_s;
const size_t _l;
public:
str(const char *s, size_t len) : _s(s), _l(len) {}
friend class print_t;
};
class xspace { };
class no_flush { };
class print_t {
static pthread_mutex_t _lock;
static volatile pid_t _print_tid;
stringbuf _strbuf;
std::ostream _buf;
bool _flush;
public:
print_t(const char *file, const char *function, int line) :
_buf(&_strbuf), _flush(true)
{
const char *file_basename = strrchr(file, '/');
if(!file_basename)
file_basename = file;
_buf << pthread_self() << "/" << gettid() << ":"
<< file_basename << ":" << function << ":" << line << ": ";
}
~print_t() {
if(_print_tid == 0 || gettid() == _print_tid) {
pthread_mutex_lock(&_lock);
std::cerr.write(_strbuf.pbase(), _strbuf.pptr() - _strbuf.pbase());
if(_flush)
std::cerr << std::endl;
else
std::cerr << "\n";
pthread_mutex_unlock(&_lock);
}
}
static int set_signal(int signum = SIGUSR1);
static void signal_handler(int signum, siginfo_t *info, void *context);
static pid_t print_tid() { return _print_tid; }
static void print_tid(pid_t new_tid) { _print_tid = new_tid; }
print_t & operator<<(const char *a[]) {
for(int i = 0; a[i]; i++)
_buf << (i ? "\n" : "") << a[i];
return *this;
}
print_t & operator<<(const std::exception &e) {
_buf << e.what();
return *this;
}
print_t & operator<<(const str &ss) {
_buf.write(ss._s, ss._l);
return *this;
}
print_t & operator<<(const xspace &xs) {
if(!_strbuf.end_is_space())
_buf << " ";
return *this;
}
print_t &operator<<(const no_flush &nf) {
_flush = false;
return *this;
}
print_t & operator<<(const Time &t) {
_buf << t.str();
return *this;
}
template
print_t & operator<<(const T &x) {
_buf << x;
return *this;
}
};
class no_print_t {
public:
no_print_t() {}
template
no_print_t & operator<<(const T &x) { return *this; }
};
void tic();
Time toc();
}
#ifdef DEBUG
#define DBG if(1) dbg::print_t(__FILE__, __FUNCTION__, __LINE__)
#define NFDBG if(1) dbg::print_t(__FILE__, __FUNCTION__, __LINE__) << dbg::no_flush()
#define V(v) dbg::xspace() << #v ":" << v
#else
#define DBG if(1) dbg::no_print_t()
#define NFDBG if(1) dbg::no_print_t()
#define V(v) v
#endif
#endif /* __DBG_HPP__ */