Inferno  0.2
trace.hpp
Go to the documentation of this file.
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