Inferno
0.2
|
00001 #ifndef TRACE_HPP 00002 #define TRACE_HPP 00003 00004 #include <string> 00005 #include <typeinfo> 00006 #include "hit_count.hpp" 00007 using namespace std; 00008 00009 /* 00010 * How it works: 00011 * 00012 * TRACE 00013 * We use a functor class "Tracer" to make TRACE look like a function that works 00014 * just like printf(). Note that Boost provides a multi-platform "name of 00015 * current function" macro, which we use. 00016 * 00017 * ASSERT 00018 * Boost asserts due to shared_ptr errors happen quite a lot. We compile with 00019 * BOOST_ENABLE_ASSERT_HANDLER defined which makes Boost call 00020 * boost::assertion_failed() when its own BOOST_ASSERT() fails. We fill this 00021 * in to print a message (using our Tracer class), and then crash in a way 00022 * that assures a stack dump. We define our own ASSERT() to use BOOST_ASSERT(). 00023 */ 00024 00025 class Tracer 00026 { 00027 public: 00028 enum Flags 00029 { 00030 FORCE = 1, // Generate the output even when not enabled 00031 DISABLE = 2, // Do nothing 00032 ABORT = 4 // Crash out in destructor 00033 }; 00034 Tracer( const char *f, int l, const char *fu, Flags fl=(Flags)0, const char *c=0 ); 00035 ~Tracer(); 00036 Tracer &operator()(); 00037 Tracer &operator()(const char *fmt, ...); 00038 Tracer &operator()(const string &s); // not a printf because of risk of accidental format specifiers 00039 00040 static void EndContinuation(); 00041 static void Enable( bool e ); ///< enable/disable tracing, only for top level funciton to call, overridden by flags 00042 inline static bool IsEnabled() { return enable; } 00043 00044 class Descend 00045 { 00046 public: 00047 inline Descend( string s=" " ) : 00048 os(pre.size()) 00049 { 00050 pre += s; 00051 Tracer::EndContinuation(); 00052 } 00053 inline ~Descend() 00054 { 00055 pre = pre.substr(0, os); 00056 if( pre.size() < leftmost_pre.size() ) 00057 leftmost_pre = pre; 00058 } 00059 static void Indent(); 00060 private: 00061 static string pre; 00062 static string last_traced_pre, leftmost_pre; 00063 const int os; 00064 }; 00065 00066 private: 00067 const char * const file; 00068 const int line; 00069 const char * const function; 00070 Flags flags; 00071 static bool continuation; 00072 static bool enable; 00073 }; 00074 00075 #define INFERNO_CURRENT_FUNCTION __func__ 00076 // can be BOOST_CURRENT_FUNCTION if you want full signature but I find 00077 // it can get in the way 00078 00079 #define TRACE if(Tracer::IsEnabled()) Tracer( __FILE__, __LINE__, INFERNO_CURRENT_FUNCTION ) 00080 00081 // New assert uses functor. Can be used as ASSERT(cond); or ASSERT(cond)(printf args); 00082 #define ASSERT(CONDITION) if(!(CONDITION)) Tracer( __FILE__, __LINE__, INFERNO_CURRENT_FUNCTION, (Tracer::Flags)(Tracer::ABORT|Tracer::FORCE), #CONDITION ) 00083 00084 // This one does an abort() in-line so you don't get "missing return" warning (which 00085 // we make an error). You can supply a message but no printf() formatting or arguments or std::string. 00086 #define ASSERTFAIL(MESSAGE) do { Tracer( __FILE__, __LINE__, INFERNO_CURRENT_FUNCTION, (Tracer::Flags)(Tracer::ABORT|Tracer::FORCE), #MESSAGE ); abort(); } while(0); 00087 00088 #define INDENT HIT; Tracer::Descend indent_ 00089 00090 #endif 00091