88 #pragma warning(disable:4786)
114 const char *LEVEL_NAMES[] =
125 const char *BEHAVIOUR_NAMES[] =
129 "assertions_continue"
139 const char *TRACE_IN =
"->";
140 const char *TRACE_OUT =
"<-";
141 const char *INDENT =
" ";
142 const char *PREFIX =
"*** ";
143 const char *TRUE_STRING =
"true";
144 const char *FALSE_STRING =
"false";
145 const unsigned int ALL_SOURCES_MASK = 0xff;
146 const unsigned int NUM_DBG_LEVELS = dbg::all-1;
161 STDCLK::clock_t triggered_at;
176 if (a.file == b.file)
178 if (a.func == b.func)
180 return a.line < b.line;
184 return a.func < b.func;
189 return a.file < b.file;
205 class dbg_streambuf :
public std::streambuf
209 dbg_streambuf(std::vector<std::ostream*> &ostreams,
int bsize = 0);
212 int pubsync() {
return sync(); }
221 void put_buffer(
void);
224 std::vector<std::ostream *> &ostreams;
237 class null_streambuf :
public std::streambuf
246 int overflow(
int) {
return 0; }
247 int sync() {
return 0; }
259 class dbg_ostream :
public std::ostream
264 dbg_ostream() : std::ostream(&dbg_buf), dbg_buf(streams) {}
265 dbg_ostream(
const dbg_ostream &rhs)
266 : std::ostream(&dbg_buf), streams(rhs.streams),
274 : std::basic_ostream<char>(&dbg_buf), dbg_buf(streams) {}
275 dbg_ostream(
const dbg_ostream &rhs)
276 : std::basic_ostream<char>(&dbg_buf), streams(rhs.streams),
279 ~dbg_ostream() { dbg_buf.pubsync(); }
281 void add(std::ostream &o);
282 void remove(std::ostream &o);
287 dbg_ostream &operator=(
const dbg_ostream&);
289 typedef std::vector<std::ostream*> stream_vec_type;
291 stream_vec_type streams;
292 dbg_streambuf dbg_buf;
316 enum ConstructionStyle
318 ConstructTheDefaultSource = 0,
319 ConstructCopyOfDefaultSource = 1
322 source_info(ConstructionStyle cs = ConstructCopyOfDefaultSource);
323 source_info(
const source_info &rhs);
337 return (levels & dbg_source_mask(lvl)) != 0;
343 void add_ostream(
dbg::level lvl, std::ostream &o);
348 void remove_ostream(
dbg::level lvl, std::ostream &o);
367 static unsigned int dbg_source_mask(
dbg::level lvl)
369 return (lvl != dbg::all) ? 1 << lvl : ALL_SOURCES_MASK;
395 dbg_ostream dbg_streams[NUM_DBG_LEVELS];
397 dbg_ostream *dbg_streams;
398 unsigned char raw_dbg_streams[
sizeof(array_type)];
400 array_type &raw_cast()
402 return *
reinterpret_cast<array_type*
>(raw_dbg_streams);
404 const array_type &raw_cast()
const
406 return *
reinterpret_cast<const array_type*
>(raw_dbg_streams);
420 class source_map_type
424 typedef std::map<std::string, source_info> map_type;
425 typedef map_type::iterator iterator;
426 typedef map_type::key_type key_type;
430 typedef map_type::mapped_type data_type;
433 typedef source_info data_type;
439 std::make_pair(dbg::default_source,
440 source_info(source_info::ConstructTheDefaultSource)));
444 source_info(source_info::ConstructTheDefaultSource)));
446 iterator begin() {
return _map.begin(); }
447 iterator end() {
return _map.end(); }
448 data_type &operator[](key_type key) {
return _map[key]; }
455 typedef std::map<dbg::source_pos, period_data, lt_sp> period_map_type;
462 std::ostream null_ostream(
new null_streambuf());
466 dbg::assertions_abort,
467 dbg::assertions_abort,
468 dbg::assertions_abort,
469 dbg::assertions_abort,
470 dbg::assertions_abort,
471 dbg::assertions_abort,
472 dbg::assertions_abort,
473 dbg::assertions_abort
476 unsigned int indent_depth = 0;
477 std::string indent_prefix = PREFIX;
478 bool level_prefix =
false;
479 bool time_prefix =
false;
480 STDCLK::clock_t period = 0;
481 source_map_type source_map;
482 period_map_type period_map;
503 void print_period_info(std::ostream &out,
const dbg::source_pos &where);
509 void do_assertion_behaviour(
dbg::level lvl, constraint_type why,
516 void do_prefix(
dbg::level lvl, std::ostream &s);
533 return !period || period_allows_impl(where);
556 void dbg::enable(
dbg::level lvl,
bool enabled)
558 out(debug) << prefix(debug) <<
"dbg::enable(" << LEVEL_NAMES[lvl]
559 <<
"," << (enabled ? TRUE_STRING : FALSE_STRING) <<
")\n";
561 source_map[
""].enable(lvl, enabled);
567 out(debug) << prefix(debug) <<
"dbg::enable(" << LEVEL_NAMES[lvl]
568 <<
",\"" << src <<
"\","
569 << (enabled ? TRUE_STRING : FALSE_STRING) <<
")\n";
571 source_map[src].enable(lvl, enabled);
575 void dbg::enable_all(
dbg::level lvl,
bool enabled)
577 out(debug) << prefix(debug) <<
"dbg::enable_all("
578 << LEVEL_NAMES[lvl] <<
","
579 << (enabled ? TRUE_STRING : FALSE_STRING) <<
")\n";
581 source_map_type::iterator i = source_map.begin();
582 for ( ; i != source_map.end(); ++i)
584 (i->second).enable(lvl, enabled);
595 return source_map[src ? src :
""].out(lvl);
599 void dbg::attach_ostream(
dbg::level lvl, std::ostream &o)
601 out(debug) << prefix(debug) <<
"dbg::attach_ostream("
602 << LEVEL_NAMES[lvl] <<
",ostream)\n";
604 source_map[
""].add_ostream(lvl, o);
610 out(debug) << prefix(debug) <<
"dbg::attach_ostream("
615 source_map[src].add_ostream(lvl, o);
619 void dbg::detach_ostream(
dbg::level lvl, std::ostream &o)
621 out(debug) << prefix(debug) <<
"dbg::detach_ostream("
622 << LEVEL_NAMES[lvl] <<
")\n";
624 source_map[
""].remove_ostream(lvl, o);
630 out(debug) << prefix(debug) <<
"dbg::detach_ostream("
635 source_map[src].remove_ostream(lvl, o);
641 out(debug) << prefix(debug) <<
"dbg::detach_all_ostreams("
645 source_map[
""].clear_ostream(lvl);
651 out(debug) << prefix(debug) <<
"dbg::detach_all_ostreams("
653 <<
", \"" << src <<
"\")\n";
655 source_map[src].clear_ostream(lvl);
663 void dbg::set_prefix(
const char *pfx)
665 out(debug) << prefix(debug) <<
"dbg::set_prefix(" << pfx <<
")\n";
671 void dbg::enable_level_prefix(
bool enabled)
673 out(debug) << prefix(debug) <<
"dbg::enable_level_prefix("
674 << (enabled ? TRUE_STRING : FALSE_STRING) <<
")\n";
676 level_prefix = enabled;
680 void dbg::enable_time_prefix(
bool enabled)
682 out(debug) << prefix(debug) <<
"dbg::enable_time_prefix("
683 << (enabled ? TRUE_STRING : FALSE_STRING) <<
")\n";
685 time_prefix = enabled;
689 std::ostream &dbg::operator<<(std::ostream &s,
const prefix &p)
691 s << indent_prefix.c_str();
697 std::ostream &dbg::operator<<(std::ostream &s,
const indent &i)
699 s << indent_prefix.c_str();
701 for (
unsigned int n = 0; n < indent_depth; n++) s << INDENT;
706 std::ostream &dbg::operator<<(std::ostream &s,
const source_pos &pos)
719 out(debug) << prefix(debug) <<
"dbg::set_assertion_behaviour("
720 << LEVEL_NAMES[lvl] <<
"," << BEHAVIOUR_NAMES[b] <<
")\n";
728 for (
int n = 0; n < dbg::all; n++)
736 void dbg::set_assertion_period(dbgclock_t p)
738 out(debug) << prefix(debug) <<
"dbg::set_assertion_period("
748 if (p && STDCLK::clock() == -1)
751 out(debug) << prefix(debug)
752 <<
"*** WARNING ***\n"
753 <<
"Platform does not support std::clock, and so\n"
754 <<
"dbg::set_assertion_period is not supported.\n";
764 const assert_info &info)
766 determine_source(src, info);
768 if (source_map[src].enabled(lvl) && !info.asserted && period_allows(info))
770 std::ostream &o = out(lvl, src);
772 o << indent(lvl) <<
"assertion \"" << info.text <<
"\" failed ";
775 o <<
"for \"" << src <<
"\" ";
779 print_period_info(o, info);
782 do_assertion_behaviour(lvl, why_assertion, info);
793 determine_source(src, here);
795 if (source_map[src].enabled(lvl) && period_allows(here))
797 std::ostream &o = out(lvl, src);
798 o << indent(lvl) <<
"sentinel reached at ";
800 print_period_info(o, here);
803 do_assertion_behaviour(lvl, why_sentinel, here);
813 const source_pos &here)
815 determine_source(src, here);
817 if (source_map[src].enabled(lvl) && period_allows(here))
819 std::ostream &o = out(lvl, src);
820 o << indent(lvl) <<
"behaviour not yet implemented at ";
822 print_period_info(o, here);
825 do_assertion_behaviour(lvl, why_unimplemented, here);
835 const void *p,
const source_pos &here)
837 determine_source(src, here);
839 if (source_map[src].enabled(lvl) && p == 0 && period_allows(here))
841 std::ostream &o = out(lvl, src);
842 o << indent(lvl) <<
"pointer is zero at ";
844 print_period_info(o, here);
847 do_assertion_behaviour(lvl, why_check_ptr, here);
857 int index,
int bound,
const source_pos &here)
859 determine_source(src, here);
861 if (source_map[src].enabled(lvl)
862 && index >= 0 && index >= bound
863 && period_allows(here))
865 std::ostream &o = out(lvl, src);
866 o << indent(lvl) <<
"index " << index <<
" is out of bounds ("
869 print_period_info(o, here);
872 do_assertion_behaviour(lvl, why_check_ptr, here);
881 dbg::trace::trace(func_name_t name)
882 : m_src(0), m_name(name), m_pos(DBG_HERE), m_triggered(false)
884 determine_source(m_src, m_pos);
886 if (source_map[m_src].enabled(dbg::tracing))
893 dbg::trace::trace(dbg_source src, func_name_t name)
894 : m_src(src), m_name(name), m_pos(DBG_HERE), m_triggered(false)
896 determine_source(m_src, m_pos);
898 if (source_map[m_src].enabled(dbg::tracing))
905 dbg::trace::trace(
const source_pos &where)
906 : m_src(0), m_name(0), m_pos(where), m_triggered(false)
908 determine_source(m_src, m_pos);
910 if (source_map[m_src].enabled(dbg::tracing))
917 dbg::trace::trace(dbg_source src,
const source_pos &where)
918 : m_src(src), m_name(0), m_pos(where), m_triggered(false)
920 determine_source(m_src, m_pos);
922 if (source_map[src].enabled(dbg::tracing))
938 void dbg::trace::trace_begin()
940 std::ostream &o = out(dbg::tracing, m_src);
941 o << indent(tracing);
950 print_pos_short(o, m_pos);
952 if (m_src && strcmp(m_src,
""))
954 o <<
" (for \"" << m_src <<
"\")";
962 void dbg::trace::trace_end()
964 std::ostream &o = out(dbg::tracing, m_src);
966 o << indent(tracing);
974 print_pos_short(o, m_pos);
976 if (m_src && strcmp(m_src,
""))
978 o <<
" (for \"" << m_src <<
"\")";
994 dbg_streambuf::dbg_streambuf(std::vector<std::ostream*> &o,
int bsize)
999 char *ptr =
new char[bsize];
1000 setp(ptr, ptr + bsize);
1009 dbg_streambuf::~dbg_streambuf()
1015 int dbg_streambuf::overflow(
int c)
1020 if (pbase() == epptr())
1032 int dbg_streambuf::sync()
1038 void dbg_streambuf::put_buffer(
void)
1040 if (pbase() != pptr())
1042 std::vector<std::ostream *>::iterator i = ostreams.begin();
1043 while (i != ostreams.end())
1045 (*i)->write(pbase(), pptr() - pbase());
1048 setp(pbase(), epptr());
1052 void dbg_streambuf::put_char(
int c)
1054 std::vector<std::ostream *>::iterator i = ostreams.begin();
1055 while (i != ostreams.end())
1057 (**i) <<
static_cast<char>(c);
1067 void dbg_ostream::add(std::ostream &o)
1069 if (std::find(streams.begin(), streams.end(), &o) == streams.end())
1071 streams.push_back(&o);
1075 void dbg_ostream::remove(std::ostream &o)
1077 stream_vec_type::iterator i
1078 = std::find(streams.begin(), streams.end(), &o);
1079 if (i != streams.end())
1085 void dbg_ostream::clear()
1095 source_info::source_info(ConstructionStyle cs)
1096 : levels(cs ? source_map[dbg::default_source].levels : 0),
1097 dbg_streams(raw_cast().dbg_streams)
1101 new (raw_dbg_streams)
1102 array_type(source_map[dbg::default_source].raw_cast());
1106 new (raw_dbg_streams) array_type;
1108 add_ostream(dbg::error, std::cerr);
1109 add_ostream(dbg::fatal, std::cerr);
1113 source_info::source_info(
const source_info &rhs)
1114 : levels(rhs.levels), dbg_streams(raw_cast().dbg_streams)
1116 new (raw_dbg_streams) array_type(rhs.raw_cast());
1119 source_info::~source_info()
1121 raw_cast().~array_type();
1124 void source_info::enable(
dbg::level lvl,
bool status)
1126 levels &= ~dbg_source_mask(lvl);
1129 levels |= dbg_source_mask(lvl);
1133 void source_info::add_ostream(
dbg::level lvl, std::ostream &o)
1135 if (lvl == dbg::all)
1137 for (
unsigned int n = 0; n < NUM_DBG_LEVELS; ++n)
1139 dbg_streams[n].add(o);
1144 dbg_streams[lvl].add(o);
1148 void source_info::remove_ostream(
dbg::level lvl, std::ostream &o)
1150 if (lvl == dbg::all)
1152 for (
unsigned int n = 0; n < NUM_DBG_LEVELS; ++n)
1154 dbg_streams[n].remove(o);
1159 dbg_streams[lvl].remove(o);
1163 void source_info::clear_ostream(
dbg::level lvl)
1165 if (lvl == dbg::all)
1167 for (
unsigned int n = 0; n < NUM_DBG_LEVELS; ++n)
1169 dbg_streams[n].clear();
1174 dbg_streams[lvl].clear();
1178 std::ostream &source_info::out(
dbg::level lvl)
1180 if (lvl == dbg::none || !enabled(lvl))
1182 return null_ostream;
1186 return dbg_streams[lvl];
1195 period_data::period_data()
1196 : no_triggers(0), triggered_at(STDCLK::clock() - period*2)
1211 out <<
"function: " << where.func <<
", ";
1213 out <<
"line: " << where.line <<
", file: " << where.file;
1223 out << where.func <<
" (" << where.line
1224 <<
" in " << where.file <<
")";
1228 out <<
"function at (" << where.line
1229 <<
" in " << where.file <<
")";
1234 void print_period_info(std::ostream &out,
const dbg::source_pos &where)
1238 size_t no_triggers = period_map[where].no_triggers;
1239 out <<
" (triggered " << no_triggers <<
" time";
1240 if (no_triggers > 1)
1251 void do_assertion_behaviour(
dbg::level lvl, constraint_type why,
1254 switch (lvl != dbg::fatal ? behaviour[lvl] : dbg::assertions_abort)
1256 case dbg::assertions_abort:
1261 case dbg::assertions_throw:
1276 case why_unimplemented:
1289 case dbg::assertions_continue:
1297 void do_prefix(
dbg::level lvl, std::ostream &s)
1301 STDCLK::time_t t = STDCLK::time(0);
1304 s << std::string(STDCLK::ctime(&t), 24) <<
": ";
1311 case dbg::info: { s <<
" info: ";
break; }
1312 case dbg::warning: { s <<
"warning: ";
break; }
1313 case dbg::error: { s <<
" error: ";
break; }
1314 case dbg::fatal: { s <<
" fatal: ";
break; }
1315 case dbg::tracing: { s <<
" trace: ";
break; }
1316 case dbg::debug: { s <<
" debug: ";
break; }
1317 case dbg::none: {
break; }
1318 case dbg::all: { s <<
" all: ";
break; }
1325 period_data &data = period_map[where];
1327 if (data.triggered_at < STDCLK::clock() - period)
1329 data.triggered_at = STDCLK::clock();
1341 if (src ==
"" && here.src)
assertion_behaviour
This enum type describes what happens when a debugging assertion fails.
The type of exception thrown by unimplemented.
const char * dbg_source
typedef for a string that describes the "source" of a diagnostic.
The type of exception thrown by check_ptr.
Data structure describing a position in the source file.
The type of exception thrown by sentinel.
level
The various predefined debugging levels.
The type of exception thrown by assertion.