dbg.h
/*
* File: dbg.h
* Author: Pete Goodliffe
* Version: 1.10
* Created: 7 June 2001
*
* Purpose: C++ debugging support library
*
* Copyright (c) Pete Goodliffe 2001-2002 (pete@cthree.org)
*
* This file is modifiable/redistributable under the terms of the GNU
* Lesser General Public License.
*
* You should have recieved a copy of the GNU General Public License along
* with this program; see the file COPYING. If not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 0211-1307, USA.
*/
#ifndef DBG_DBG_H
#define DBG_DBG_H
#include <iosfwd>
#include <exception>
#ifndef _MSC_VER
#include <ctime>
#else
// The start of a MSVC compatibility disaster area.
// See the documentation for the dbgclock_t type.
#include <time.h>
#endif
#if defined(DBG_ENABLED) && defined(NDEBUG)
//#warning DBG_ENABLED defined with NDEBUG which do you want?
#endif
namespace dbg
{
const int version = 110;
/**************************************************************************
* Debugging declarations
*************************************************************************/
enum level
{
info,
warning,
error,
fatal,
tracing,
debug,
none,
all
};
enum assertion_behaviour
{
assertions_abort,
assertions_throw,
assertions_continue
};
typedef const char * dbg_source;
/**************************************************************************
* source_pos
*************************************************************************/
typedef const unsigned int line_no_t;
typedef const char * func_name_t;
typedef const char * file_name_t;
struct source_pos
{
line_no_t line;
func_name_t func;
file_name_t file;
dbg_source src;
source_pos(line_no_t ln, func_name_t fn, file_name_t fl, dbg_source s)
: line(ln), func(fn), file(fl), src(s) {}
source_pos()
: line(0), func(0), file(0), src(0) {}
};
#ifndef _MSC_VER
typedef std::clock_t dbgclock_t;
#else
typedef clock_t dbgclock_t;
#endif
/**************************************************************************
* Exceptions
*************************************************************************/
struct dbg_exception : public std::exception
{
dbg_exception(const source_pos &p) : pos(p) {}
const source_pos pos;
};
struct assertion_exception : public dbg_exception
{
assertion_exception(const source_pos &p) : dbg_exception(p) {}
};
struct sentinel_exception : public dbg_exception
{
sentinel_exception(const source_pos &p) : dbg_exception(p) {}
};
struct unimplemented_exception : public dbg_exception
{
unimplemented_exception(const source_pos &p) : dbg_exception(p) {}
};
struct check_ptr_exception : public dbg_exception
{
check_ptr_exception(const source_pos &p) : dbg_exception(p) {}
};
#ifdef DBG_ENABLED
/**************************************************************************
* default_source
*************************************************************************/
extern dbg_source default_source;
/**************************************************************************
* Debug version of the DBG_HERE macro
*************************************************************************/
/*
* DBG_FUNCTION is defined to be a macro that expands to the name of
* the current function, or zero if the compiler is unable to supply that
* information. It's sad that this wasn't included in the C++ standard
* from the very beginning.
*/
#if defined(__GNUC__)
#define DBG_FUNCTION __FUNCTION__
#else
#define DBG_FUNCTION 0
#endif
#if !defined(DBG_SOURCE)
#define DBG_SOURCE 0
#endif
/*
* Handy macro to generate a @ref source_pos object containing the
* information of the current source line.
*
* @see dbg::source_pos
*/
#define DBG_HERE \
(::dbg::source_pos(__LINE__, DBG_FUNCTION, __FILE__, DBG_SOURCE))
/**************************************************************************
* Enable/disable dbg facilities
*************************************************************************/
void enable(level lvl, bool enabled);
void enable(level lvl, dbg_source src, bool enabled);
void enable_all(level lvl, bool enabled);
/**************************************************************************
* Logging
*************************************************************************/
std::ostream &out(level lvl, dbg_source src);
inline std::ostream &out(level lvl)
{
return out(lvl, 0);
}
void attach_ostream(level lvl, std::ostream &o);
void attach_ostream(level lvl, dbg_source src, std::ostream &o);
void detach_ostream(level lvl, std::ostream &o);
void detach_ostream(level lvl, dbg_source src, std::ostream &o);
void detach_all_ostreams(level lvl);
void detach_all_ostreams(level lvl, dbg_source src);
inline std::ostream &info_out()
{
return out(dbg::info);
}
inline std::ostream &warning_out()
{
return out(dbg::warning);
}
inline std::ostream &error_out()
{
return out(dbg::error);
}
inline std::ostream &fatal_out()
{
return out(dbg::fatal);
}
inline std::ostream &trace_out()
{
return out(dbg::tracing);
}
/**************************************************************************
* Output formatting
*************************************************************************/
void set_prefix(const char *prefix);
void enable_level_prefix(bool enabled);
void enable_time_prefix(bool enabled);
struct prefix
{
prefix() : l(none) {}
prefix(level lvl) : l(lvl) {}
level l;
};
std::ostream &operator<<(std::ostream &s, const prefix &p);
struct indent
{
indent() : l(none) {}
indent(level lvl) : l(lvl) {}
level l;
};
std::ostream &operator<<(std::ostream &s, const indent &i);
std::ostream &operator<<(std::ostream &s, const source_pos &pos);
/**************************************************************************
* Behaviour
*************************************************************************/
void set_assertion_behaviour(level lvl, assertion_behaviour behaviour);
void set_assertion_period(dbgclock_t period);
/**************************************************************************
* Assertion
*************************************************************************/
struct assert_info : public source_pos
{
bool asserted;
const char *text;
assert_info(bool a, const char *t,
line_no_t line, func_name_t func,
file_name_t file, dbg_source spos)
: source_pos(line, func, file, spos), asserted(a), text(t) {}
assert_info(bool a, const char *b, const source_pos &sp)
: source_pos(sp), asserted(a), text(b) {}
};
/*
* Utility macro used by the DBG_ASSERTION macro - it converts a
* macro parameter into a character string.
*/
#define DBG_STRING(a) #a
/*
* Handy macro used by clients of the @ref dbg::assertion function.
* It use is described in the @ref assertion documentation.
*
* @see dbg::assertion
*/
#define DBG_ASSERTION(a) \
::dbg::assert_info(a, DBG_STRING(a), DBG_HERE)
void assertion(level lvl, dbg_source src, const assert_info &ai);
inline void assertion(level lvl, const assert_info &ai)
{
assertion(lvl, 0, ai);
}
inline void assertion(dbg_source src, const assert_info &ai)
{
assertion(warning, src, ai);
}
inline void assertion(const assert_info &ai)
{
assertion(warning, 0, ai);
}
/**************************************************************************
* Sentinel
*************************************************************************/
void sentinel(level lvl, dbg_source src, const source_pos &here);
inline void sentinel(level lvl, const source_pos &here)
{
sentinel(lvl, 0, here);
}
inline void sentinel(dbg_source src, const source_pos &here)
{
sentinel(warning, src, here);
}
inline void sentinel(const source_pos &here)
{
sentinel(warning, 0, here);
}
/**************************************************************************
* Unimplemented
*************************************************************************/
void unimplemented(level lvl, dbg_source src, const source_pos &here);
inline void unimplemented(level lvl, const source_pos &here)
{
unimplemented(lvl, 0, here);
}
inline void unimplemented(dbg_source src, const source_pos &here)
{
unimplemented(warning, src, here);
}
inline void unimplemented(const source_pos &here)
{
unimplemented(warning, 0, here);
}
/**************************************************************************
* Pointer checking
*************************************************************************/
void check_ptr(level lvl, dbg_source src, const void *p, const source_pos &here);
inline void check_ptr(level lvl, const void *p, const source_pos &here)
{
check_ptr(lvl, 0, p, here);
}
inline void check_ptr(dbg_source src, const void *p, const source_pos &here)
{
check_ptr(warning, src, p, here);
}
inline void check_ptr(const void *p, const source_pos &here)
{
check_ptr(warning, 0, p, here);
}
/**************************************************************************
* Bounds checking
*************************************************************************/
template <class T>
inline unsigned int array_size(T &array)
{
return sizeof(array)/sizeof(array[0]);
}
void check_bounds(level lvl, dbg_source src,
int index, int bound, const source_pos &here);
inline void check_bounds(level lvl, dbg_source src,
int index, int minbound, int maxbound,
const source_pos &here)
{
check_bounds(lvl, src, index-minbound, maxbound, here);
}
template <class T>
void check_bounds(level lvl, dbg_source src,
int index, T &array, const source_pos &here)
{
check_bounds(lvl, src, index, array_size(array), here);
}
template <class T>
void check_bounds(level lvl, int index, T &array, const source_pos &here)
{
check_bounds(lvl, 0, index, array_size(array), here);
}
template <class T>
void check_bounds(dbg_source src, int index, T &array,
const source_pos &here)
{
check_bounds(warning, src, index, array_size(array), here);
}
template <class T>
void check_bounds(int index, T &array, const source_pos &here)
{
check_bounds(warning, 0, index, array_size(array), here);
}
/**************************************************************************
* Tracing
*************************************************************************/
class trace
{
public:
trace(func_name_t name);
trace(dbg_source src, func_name_t name);
trace(const source_pos &here);
trace(dbg_source src, const source_pos &here);
~trace();
private:
trace(const trace &);
trace &operator=(const trace &);
void trace_begin();
void trace_end();
dbg_source m_src;
const char *m_name;
const source_pos m_pos;
bool m_triggered;
};
/**************************************************************************
* Post conditions
*************************************************************************/
template <class obj_t>
class post_mem_fun
{
public:
typedef bool (obj_t::*fn_t)();
post_mem_fun(level lvl, obj_t *obj, fn_t fn, const source_pos &pos)
: m_lvl(lvl), m_src(0), m_obj(obj), m_fn(fn), m_pos(pos) {}
post_mem_fun(level lvl, dbg_source src,
obj_t *obj, fn_t fn, const source_pos &pos)
: m_lvl(lvl), m_src(src), m_obj(obj), m_fn(fn), m_pos(pos) {}
post_mem_fun(obj_t *obj, fn_t fn, const source_pos &pos)
: m_lvl(dbg::warning), m_src(0),
m_obj(obj), m_fn(fn), m_pos(pos) {}
post_mem_fun(dbg_source src, obj_t *obj, fn_t fn,
const source_pos &pos)
: m_lvl(dbg::warning), m_src(src),
m_obj(obj), m_fn(fn), m_pos(pos) {}
~post_mem_fun()
{
assertion(m_lvl, m_src,
assert_info((m_obj->*m_fn)(), "post condition",
m_pos.line, m_pos.func, m_pos.file, m_pos.src));
}
private:
const level m_lvl;
const dbg_source m_src;
obj_t *m_obj;
fn_t m_fn;
const source_pos m_pos;
};
class post
{
public:
typedef bool (*fn_t)();
post(level lvl, fn_t fn, const source_pos &pos)
: m_lvl(lvl), m_src(0), m_fn(fn), m_pos(pos) {}
post(level lvl, dbg_source src, fn_t fn, const source_pos &pos)
: m_lvl(lvl), m_src(src), m_fn(fn), m_pos(pos) {}
post(fn_t fn, const source_pos &pos)
: m_lvl(dbg::warning), m_src(0), m_fn(fn), m_pos(pos) {}
post(dbg_source src, fn_t fn, const source_pos &pos)
: m_lvl(dbg::warning), m_src(src), m_fn(fn), m_pos(pos) {}
~post()
{
assertion(m_lvl, m_src,
assert_info(m_fn(), "post condition",
m_pos.line, m_pos.func, m_pos.file, m_pos.src));
}
private:
level m_lvl;
const dbg_source m_src;
fn_t m_fn;
const source_pos m_pos;
};
/**************************************************************************
* Compile time assertions
*************************************************************************/
template <bool expression>
class compile_assertion;
template <>
class compile_assertion<true> {};
#else
/**************************************************************************
* Non-debug stub versions
*************************************************************************/
/*
* With debugging switched off we generate null versions of the above
* definitions.
*
* Given a good compiler and a strong prevailing headwind, these will
* optimise away to nothing.
*/
#define DBG_HERE ((void*)0)
#define DBG_ASSERTION(a) ((void*)0)
//enum { default_source = 0xdead };
const dbg_source default_source = 0;
class null_stream
{
public:
#ifdef _MSC_VER
null_stream &operator<<(void *) { return *this; }
null_stream &operator<<(const void *) { return *this; }
null_stream &operator<<(long) { return *this; }
#else
template <class otype>
null_stream &operator<<(const otype &) { return *this; }
#endif
template <class otype>
null_stream &operator<<(otype &) { return *this; }
null_stream &operator<<(std::ostream& (*)(std::ostream&))
{
return *this;
}
};
struct prefix { prefix() {} prefix(level) {} };
struct indent { indent() {} indent(level) {} };
inline void enable(level, bool) {}
inline void enable(level, dbg_source, bool) {}
inline void enable_all(level, bool) {}
inline null_stream out(level, dbg_source) {return null_stream();}
inline null_stream out(level) {return null_stream();}
inline void attach_ostream(level, std::ostream &) {}
inline void attach_ostream(level, dbg_source, std::ostream &) {}
inline void detach_ostream(level, std::ostream &) {}
inline void detach_ostream(level, dbg_source, std::ostream &) {}
inline void detach_all_ostreams(level) {}
inline void detach_all_ostreams(level, dbg_source) {}
inline null_stream info_out() {return null_stream();}
inline null_stream warning_out() {return null_stream();}
inline null_stream error_out() {return null_stream();}
inline null_stream fatal_out() {return null_stream();}
inline null_stream trace_out() {return null_stream();}
inline void set_prefix(const char *) {}
inline void enable_level_prefix(bool) {}
inline void enable_time_prefix(bool) {}
inline void set_assertion_behaviour(level, assertion_behaviour) {}
inline void set_assertion_period(dbgclock_t) {}
inline void assertion(level, dbg_source, void *) {}
inline void assertion(level, void *) {}
inline void assertion(dbg_source, void *) {}
inline void assertion(void *) {}
inline void sentinel(level, dbg_source, void *) {}
inline void sentinel(level, void *) {}
inline void sentinel(dbg_source, void *) {}
inline void sentinel(void *) {}
inline void unimplemented(level, dbg_source, void *) {}
inline void unimplemented(level, void *) {}
inline void unimplemented(dbg_source, void *) {}
inline void unimplemented(void *) {}
inline void check_ptr(level, dbg_source, const void *, void *) {}
inline void check_ptr(level, const void *, void *) {}
inline void check_ptr(dbg_source, const void *, void *) {}
inline void check_ptr(const void *, void *) {}
inline void check_bounds(level, void *, int, int, void *) {}
inline void check_bounds(level, dbg_source, int, void*, void*) {}
inline void check_bounds(level, dbg_source, int, int,
void *, void *) {}
inline void check_bounds(level, int, void *, void*) {}
inline void check_bounds(void *, int, void *, void *) {}
inline void check_bounds(int, void *, void *) {}
class trace
{
public:
trace(const char *fn_name) {}
trace(dbg_source, const char *fn_name) {}
trace(void *here) {}
trace(dbg_source, void *here) {}
~trace() {}
};
template <class obj_t>
class post_mem_fun
{
public:
typedef bool (obj_t::*fn_t)();
post_mem_fun(level, void *, fn_t, void *) {}
post_mem_fun(level, dbg_source, void *, fn_t, void *) {}
post_mem_fun(void *, fn_t, void *) {}
post_mem_fun(dbg_source, void *, fn_t, void *) {}
~post_mem_fun() {}
};
class post
{
public:
typedef bool(*fn_t)();
post(level, fn_t, void *) {}
post(level, dbg_source, fn_t, void *) {}
post(fn_t, void *) {}
post(dbg_source, fn_t, void *) {}
~post() {}
};
template <bool expression>
class compile_assertion {};
#endif
}
#endif