libdbg 1.2
|
00001 /* 00002 * File: dbg.h 00003 * Author: Pete Goodliffe 00004 * Version: 1.10 00005 * Created: 7 June 2001 00006 * 00007 * Purpose: C++ debugging support library 00008 * 00009 * Copyright (c) Pete Goodliffe 2001-2002 (pete@cthree.org) 00010 * 00011 * This file is modifiable/redistributable under the terms of the GNU 00012 * Lesser General Public License. 00013 * 00014 * You should have recieved a copy of the GNU General Public License along 00015 * with this program; see the file COPYING. If not, write to the Free Software 00016 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 0211-1307, USA. 00017 */ 00018 00019 #ifndef DBG_DBG_H 00020 #define DBG_DBG_H 00021 00022 #include <iosfwd> 00023 #include <exception> 00024 00025 #ifndef _MSC_VER 00026 #include <ctime> 00027 #else 00028 // The start of a MSVC compatibility disaster area. 00029 // See the documentation for the dbgclock_t type. 00030 #include <time.h> 00031 #endif 00032 00033 #if defined(DBG_ENABLED) && defined(NDEBUG) 00034 //#warning DBG_ENABLED defined with NDEBUG which do you want? 00035 #endif 00036 00292 namespace dbg 00293 { 00300 const int version = 110; 00301 00302 /************************************************************************** 00303 * Debugging declarations 00304 *************************************************************************/ 00305 00325 enum level 00326 { 00327 info, 00328 warning, 00329 error, 00330 fatal, 00331 tracing, 00332 debug, 00333 none, 00334 all 00335 }; 00336 00353 enum assertion_behaviour 00354 { 00355 assertions_abort, 00356 assertions_throw, 00357 assertions_continue 00358 }; 00359 00379 typedef const char * dbg_source; 00380 00381 /************************************************************************** 00382 * source_pos 00383 *************************************************************************/ 00384 00392 typedef const unsigned int line_no_t; 00393 00402 typedef const char * func_name_t; 00403 00411 typedef const char * file_name_t; 00412 00431 struct source_pos 00432 { 00433 line_no_t line; 00434 func_name_t func; 00435 file_name_t file; 00436 dbg_source src; 00437 00442 source_pos(line_no_t ln, func_name_t fn, file_name_t fl, dbg_source s) 00443 : line(ln), func(fn), file(fl), src(s) {} 00444 00448 source_pos() 00449 : line(0), func(0), file(0), src(0) {} 00450 }; 00451 00452 #ifndef _MSC_VER 00453 00466 typedef std::clock_t dbgclock_t; 00467 #else 00468 00472 typedef clock_t dbgclock_t; 00473 #endif 00474 00475 /************************************************************************** 00476 * Exceptions 00477 *************************************************************************/ 00478 00487 struct dbg_exception : public std::exception 00488 { 00489 dbg_exception(const source_pos &p) : pos(p) {} 00490 const source_pos pos; 00491 }; 00492 00498 struct assertion_exception : public dbg_exception 00499 { 00500 assertion_exception(const source_pos &p) : dbg_exception(p) {} 00501 }; 00502 00508 struct sentinel_exception : public dbg_exception 00509 { 00510 sentinel_exception(const source_pos &p) : dbg_exception(p) {} 00511 }; 00512 00518 struct unimplemented_exception : public dbg_exception 00519 { 00520 unimplemented_exception(const source_pos &p) : dbg_exception(p) {} 00521 }; 00522 00528 struct check_ptr_exception : public dbg_exception 00529 { 00530 check_ptr_exception(const source_pos &p) : dbg_exception(p) {} 00531 }; 00532 00533 #ifdef DBG_ENABLED 00534 00535 /************************************************************************** 00536 * default_source 00537 *************************************************************************/ 00538 00554 extern dbg_source default_source; 00555 00556 /************************************************************************** 00557 * Debug version of the DBG_HERE macro 00558 *************************************************************************/ 00559 00560 /* 00561 * DBG_FUNCTION is defined to be a macro that expands to the name of 00562 * the current function, or zero if the compiler is unable to supply that 00563 * information. It's sad that this wasn't included in the C++ standard 00564 * from the very beginning. 00565 */ 00566 #if defined(__GNUC__) 00567 #define DBG_FUNCTION __FUNCTION__ 00568 #else 00569 #define DBG_FUNCTION 0 00570 #endif 00571 00572 #if !defined(DBG_SOURCE) 00573 #define DBG_SOURCE 0 00574 #endif 00575 00576 /* 00577 * Handy macro to generate a @ref source_pos object containing the 00578 * information of the current source line. 00579 * 00580 * @see dbg::source_pos 00581 */ 00582 #define DBG_HERE \ 00583 (::dbg::source_pos(__LINE__, DBG_FUNCTION, __FILE__, DBG_SOURCE)) 00584 00585 /************************************************************************** 00586 * Enable/disable dbg facilities 00587 *************************************************************************/ 00588 00616 void enable(level lvl, bool enabled); 00617 00638 void enable(level lvl, dbg_source src, bool enabled); 00639 00651 void enable_all(level lvl, bool enabled); 00652 00653 /************************************************************************** 00654 * Logging 00655 *************************************************************************/ 00656 00678 std::ostream &out(level lvl, dbg_source src); 00679 00703 inline std::ostream &out(level lvl) 00704 { 00705 return out(lvl, 0); 00706 } 00707 00729 void attach_ostream(level lvl, std::ostream &o); 00730 00742 void attach_ostream(level lvl, dbg_source src, std::ostream &o); 00743 00757 void detach_ostream(level lvl, std::ostream &o); 00758 00770 void detach_ostream(level lvl, dbg_source src, std::ostream &o); 00771 00780 void detach_all_ostreams(level lvl); 00781 00791 void detach_all_ostreams(level lvl, dbg_source src); 00792 00799 inline std::ostream &info_out() 00800 { 00801 return out(dbg::info); 00802 } 00803 00810 inline std::ostream &warning_out() 00811 { 00812 return out(dbg::warning); 00813 } 00814 00821 inline std::ostream &error_out() 00822 { 00823 return out(dbg::error); 00824 } 00825 00832 inline std::ostream &fatal_out() 00833 { 00834 return out(dbg::fatal); 00835 } 00836 00843 inline std::ostream &trace_out() 00844 { 00845 return out(dbg::tracing); 00846 } 00847 00848 /************************************************************************** 00849 * Output formatting 00850 *************************************************************************/ 00851 00861 void set_prefix(const char *prefix); 00862 00874 void enable_level_prefix(bool enabled); 00875 00891 void enable_time_prefix(bool enabled); 00892 00917 struct prefix 00918 { 00923 prefix() : l(none) {} 00924 00928 prefix(level lvl) : l(lvl) {} 00929 00930 level l; 00931 }; 00932 00939 std::ostream &operator<<(std::ostream &s, const prefix &p); 00940 00960 struct indent 00961 { 00966 indent() : l(none) {} 00967 00971 indent(level lvl) : l(lvl) {} 00972 00973 level l; 00974 }; 00975 00982 std::ostream &operator<<(std::ostream &s, const indent &i); 00983 01004 std::ostream &operator<<(std::ostream &s, const source_pos &pos); 01005 01006 /************************************************************************** 01007 * Behaviour 01008 *************************************************************************/ 01009 01030 void set_assertion_behaviour(level lvl, assertion_behaviour behaviour); 01031 01080 void set_assertion_period(dbgclock_t period); 01081 01082 /************************************************************************** 01083 * Assertion 01084 *************************************************************************/ 01085 01095 struct assert_info : public source_pos 01096 { 01097 bool asserted; 01098 const char *text; 01099 01105 assert_info(bool a, const char *t, 01106 line_no_t line, func_name_t func, 01107 file_name_t file, dbg_source spos) 01108 : source_pos(line, func, file, spos), asserted(a), text(t) {} 01109 01115 assert_info(bool a, const char *b, const source_pos &sp) 01116 : source_pos(sp), asserted(a), text(b) {} 01117 }; 01118 01119 /* 01120 * Utility macro used by the DBG_ASSERTION macro - it converts a 01121 * macro parameter into a character string. 01122 */ 01123 #define DBG_STRING(a) #a 01124 01125 /* 01126 * Handy macro used by clients of the @ref dbg::assertion function. 01127 * It use is described in the @ref assertion documentation. 01128 * 01129 * @see dbg::assertion 01130 */ 01131 #define DBG_ASSERTION(a) \ 01132 ::dbg::assert_info(a, DBG_STRING(a), DBG_HERE) 01133 01164 void assertion(level lvl, dbg_source src, const assert_info &ai); 01165 01173 inline void assertion(level lvl, const assert_info &ai) 01174 { 01175 assertion(lvl, 0, ai); 01176 } 01177 01185 inline void assertion(dbg_source src, const assert_info &ai) 01186 { 01187 assertion(warning, src, ai); 01188 } 01189 01196 inline void assertion(const assert_info &ai) 01197 { 01198 assertion(warning, 0, ai); 01199 } 01200 01201 /************************************************************************** 01202 * Sentinel 01203 *************************************************************************/ 01204 01224 void sentinel(level lvl, dbg_source src, const source_pos &here); 01225 01233 inline void sentinel(level lvl, const source_pos &here) 01234 { 01235 sentinel(lvl, 0, here); 01236 } 01237 01245 inline void sentinel(dbg_source src, const source_pos &here) 01246 { 01247 sentinel(warning, src, here); 01248 } 01249 01256 inline void sentinel(const source_pos &here) 01257 { 01258 sentinel(warning, 0, here); 01259 } 01260 01261 /************************************************************************** 01262 * Unimplemented 01263 *************************************************************************/ 01264 01291 void unimplemented(level lvl, dbg_source src, const source_pos &here); 01292 01300 inline void unimplemented(level lvl, const source_pos &here) 01301 { 01302 unimplemented(lvl, 0, here); 01303 } 01304 01312 inline void unimplemented(dbg_source src, const source_pos &here) 01313 { 01314 unimplemented(warning, src, here); 01315 } 01316 01323 inline void unimplemented(const source_pos &here) 01324 { 01325 unimplemented(warning, 0, here); 01326 } 01327 01328 /************************************************************************** 01329 * Pointer checking 01330 *************************************************************************/ 01331 01349 void check_ptr(level lvl, dbg_source src, const void *p, const source_pos &here); 01350 01359 inline void check_ptr(level lvl, const void *p, const source_pos &here) 01360 { 01361 check_ptr(lvl, 0, p, here); 01362 } 01363 01372 inline void check_ptr(dbg_source src, const void *p, const source_pos &here) 01373 { 01374 check_ptr(warning, src, p, here); 01375 } 01376 01384 inline void check_ptr(const void *p, const source_pos &here) 01385 { 01386 check_ptr(warning, 0, p, here); 01387 } 01388 01389 /************************************************************************** 01390 * Bounds checking 01391 *************************************************************************/ 01392 01404 template <class T> 01405 inline unsigned int array_size(T &array) 01406 { 01407 return sizeof(array)/sizeof(array[0]); 01408 } 01409 01424 void check_bounds(level lvl, dbg_source src, 01425 int index, int bound, const source_pos &here); 01442 inline void check_bounds(level lvl, dbg_source src, 01443 int index, int minbound, int maxbound, 01444 const source_pos &here) 01445 { 01446 check_bounds(lvl, src, index-minbound, maxbound, here); 01447 } 01448 01467 template <class T> 01468 void check_bounds(level lvl, dbg_source src, 01469 int index, T &array, const source_pos &here) 01470 { 01471 check_bounds(lvl, src, index, array_size(array), here); 01472 } 01473 01483 template <class T> 01484 void check_bounds(level lvl, int index, T &array, const source_pos &here) 01485 { 01486 check_bounds(lvl, 0, index, array_size(array), here); 01487 } 01488 01498 template <class T> 01499 void check_bounds(dbg_source src, int index, T &array, 01500 const source_pos &here) 01501 { 01502 check_bounds(warning, src, index, array_size(array), here); 01503 } 01504 01513 template <class T> 01514 void check_bounds(int index, T &array, const source_pos &here) 01515 { 01516 check_bounds(warning, 0, index, array_size(array), here); 01517 } 01518 01519 /************************************************************************** 01520 * Tracing 01521 *************************************************************************/ 01522 01581 class trace 01582 { 01583 public: 01584 01593 trace(func_name_t name); 01594 01599 trace(dbg_source src, func_name_t name); 01600 01607 trace(const source_pos &here); 01608 01613 trace(dbg_source src, const source_pos &here); 01614 01615 ~trace(); 01616 01617 private: 01618 01619 trace(const trace &); 01620 trace &operator=(const trace &); 01621 01622 void trace_begin(); 01623 void trace_end(); 01624 01625 dbg_source m_src; 01626 const char *m_name; 01627 const source_pos m_pos; 01628 bool m_triggered; 01629 }; 01630 01631 /************************************************************************** 01632 * Post conditions 01633 *************************************************************************/ 01634 01690 template <class obj_t> 01691 class post_mem_fun 01692 { 01693 public: 01694 01699 typedef bool (obj_t::*fn_t)(); 01700 01707 post_mem_fun(level lvl, obj_t *obj, fn_t fn, const source_pos &pos) 01708 : m_lvl(lvl), m_src(0), m_obj(obj), m_fn(fn), m_pos(pos) {} 01709 01717 post_mem_fun(level lvl, dbg_source src, 01718 obj_t *obj, fn_t fn, const source_pos &pos) 01719 : m_lvl(lvl), m_src(src), m_obj(obj), m_fn(fn), m_pos(pos) {} 01720 01729 post_mem_fun(obj_t *obj, fn_t fn, const source_pos &pos) 01730 : m_lvl(dbg::warning), m_src(0), 01731 m_obj(obj), m_fn(fn), m_pos(pos) {} 01732 01742 post_mem_fun(dbg_source src, obj_t *obj, fn_t fn, 01743 const source_pos &pos) 01744 : m_lvl(dbg::warning), m_src(src), 01745 m_obj(obj), m_fn(fn), m_pos(pos) {} 01746 01750 ~post_mem_fun() 01751 { 01752 assertion(m_lvl, m_src, 01753 assert_info((m_obj->*m_fn)(), "post condition", 01754 m_pos.line, m_pos.func, m_pos.file, m_pos.src)); 01755 } 01756 01757 private: 01758 01759 const level m_lvl; 01760 const dbg_source m_src; 01761 obj_t *m_obj; 01762 fn_t m_fn; 01763 const source_pos m_pos; 01764 }; 01765 01777 class post 01778 { 01779 public: 01780 01785 typedef bool (*fn_t)(); 01786 01792 post(level lvl, fn_t fn, const source_pos &pos) 01793 : m_lvl(lvl), m_src(0), m_fn(fn), m_pos(pos) {} 01794 01801 post(level lvl, dbg_source src, fn_t fn, const source_pos &pos) 01802 : m_lvl(lvl), m_src(src), m_fn(fn), m_pos(pos) {} 01803 01811 post(fn_t fn, const source_pos &pos) 01812 : m_lvl(dbg::warning), m_src(0), m_fn(fn), m_pos(pos) {} 01813 01822 post(dbg_source src, fn_t fn, const source_pos &pos) 01823 : m_lvl(dbg::warning), m_src(src), m_fn(fn), m_pos(pos) {} 01824 01828 ~post() 01829 { 01830 assertion(m_lvl, m_src, 01831 assert_info(m_fn(), "post condition", 01832 m_pos.line, m_pos.func, m_pos.file, m_pos.src)); 01833 } 01834 01835 private: 01836 01837 level m_lvl; 01838 const dbg_source m_src; 01839 fn_t m_fn; 01840 const source_pos m_pos; 01841 }; 01842 01843 /************************************************************************** 01844 * Compile time assertions 01845 *************************************************************************/ 01846 01866 template <bool expression> 01867 class compile_assertion; 01868 template <> 01869 class compile_assertion<true> {}; 01870 01871 #else 01872 01873 /************************************************************************** 01874 * Non-debug stub versions 01875 *************************************************************************/ 01876 01877 /* 01878 * With debugging switched off we generate null versions of the above 01879 * definitions. 01880 * 01881 * Given a good compiler and a strong prevailing headwind, these will 01882 * optimise away to nothing. 01883 */ 01884 01885 #define DBG_HERE ((void*)0) 01886 #define DBG_ASSERTION(a) ((void*)0) 01887 01888 //enum { default_source = 0xdead }; 01889 const dbg_source default_source = 0; 01890 01897 class null_stream 01898 { 01899 public: 01900 #ifdef _MSC_VER 01901 null_stream &operator<<(void *) { return *this; } 01902 null_stream &operator<<(const void *) { return *this; } 01903 null_stream &operator<<(long) { return *this; } 01904 #else 01905 template <class otype> 01906 null_stream &operator<<(const otype &) { return *this; } 01907 #endif 01908 01909 template <class otype> 01910 null_stream &operator<<(otype &) { return *this; } 01911 null_stream &operator<<(std::ostream& (*)(std::ostream&)) 01912 { 01913 return *this; 01914 } 01915 }; 01916 01917 struct prefix { prefix() {} prefix(level) {} }; 01918 struct indent { indent() {} indent(level) {} }; 01919 01920 inline void enable(level, bool) {} 01921 inline void enable(level, dbg_source, bool) {} 01922 inline void enable_all(level, bool) {} 01923 inline null_stream out(level, dbg_source) {return null_stream();} 01924 inline null_stream out(level) {return null_stream();} 01925 inline void attach_ostream(level, std::ostream &) {} 01926 inline void attach_ostream(level, dbg_source, std::ostream &) {} 01927 inline void detach_ostream(level, std::ostream &) {} 01928 inline void detach_ostream(level, dbg_source, std::ostream &) {} 01929 inline void detach_all_ostreams(level) {} 01930 inline void detach_all_ostreams(level, dbg_source) {} 01931 inline null_stream info_out() {return null_stream();} 01932 inline null_stream warning_out() {return null_stream();} 01933 inline null_stream error_out() {return null_stream();} 01934 inline null_stream fatal_out() {return null_stream();} 01935 inline null_stream trace_out() {return null_stream();} 01936 inline void set_prefix(const char *) {} 01937 inline void enable_level_prefix(bool) {} 01938 inline void enable_time_prefix(bool) {} 01939 01940 inline void set_assertion_behaviour(level, assertion_behaviour) {} 01941 inline void set_assertion_period(dbgclock_t) {} 01942 inline void assertion(level, dbg_source, void *) {} 01943 inline void assertion(level, void *) {} 01944 inline void assertion(dbg_source, void *) {} 01945 inline void assertion(void *) {} 01946 inline void sentinel(level, dbg_source, void *) {} 01947 inline void sentinel(level, void *) {} 01948 inline void sentinel(dbg_source, void *) {} 01949 inline void sentinel(void *) {} 01950 inline void unimplemented(level, dbg_source, void *) {} 01951 inline void unimplemented(level, void *) {} 01952 inline void unimplemented(dbg_source, void *) {} 01953 inline void unimplemented(void *) {} 01954 inline void check_ptr(level, dbg_source, const void *, void *) {} 01955 inline void check_ptr(level, const void *, void *) {} 01956 inline void check_ptr(dbg_source, const void *, void *) {} 01957 inline void check_ptr(const void *, void *) {} 01958 inline void check_bounds(level, void *, int, int, void *) {} 01959 inline void check_bounds(level, dbg_source, int, void*, void*) {} 01960 inline void check_bounds(level, dbg_source, int, int, 01961 void *, void *) {} 01962 inline void check_bounds(level, int, void *, void*) {} 01963 inline void check_bounds(void *, int, void *, void *) {} 01964 inline void check_bounds(int, void *, void *) {} 01965 01966 class trace 01967 { 01968 public: 01969 trace(const char *fn_name) {} 01970 trace(dbg_source, const char *fn_name) {} 01971 trace(void *here) {} 01972 trace(dbg_source, void *here) {} 01973 ~trace() {} 01974 }; 01975 01976 template <class obj_t> 01977 class post_mem_fun 01978 { 01979 public: 01980 typedef bool (obj_t::*fn_t)(); 01981 post_mem_fun(level, void *, fn_t, void *) {} 01982 post_mem_fun(level, dbg_source, void *, fn_t, void *) {} 01983 post_mem_fun(void *, fn_t, void *) {} 01984 post_mem_fun(dbg_source, void *, fn_t, void *) {} 01985 ~post_mem_fun() {} 01986 }; 01987 class post 01988 { 01989 public: 01990 typedef bool(*fn_t)(); 01991 post(level, fn_t, void *) {} 01992 post(level, dbg_source, fn_t, void *) {} 01993 post(fn_t, void *) {} 01994 post(dbg_source, fn_t, void *) {} 01995 ~post() {} 01996 }; 01997 01998 template <bool expression> 01999 class compile_assertion {}; 02000 02001 #endif 02002 } 02003 02004 #endif