#ifndef CRUCIBLE_CHATTER_H #define CRUCIBLE_CHATTER_H #include #include #include #include #include #include #include /** \brief Chatter wraps a std::ostream reference with a destructor that writes a newline, and inserts timestamp, pid, and tid prefixes on output. Typical usage is expressions like the following: int six = 6, nine = 9; \n Chatter() << "What you get when you multiply" << six << "by" << nine << '?'; \n Chatter() << "forty two!"; which results in output like the following: What you get when you multiply 6 by 9 ?\n forty-two! Note that newlines and timestamps are injected automatically in the output by the Chatter destructor. You can also use std::endl explicitly, although it will not have the effect of flushing the buffer. */ namespace crucible { using namespace std; class Chatter { int m_loglevel; string m_name; ostream &m_os; ostringstream m_oss; public: Chatter(int loglevel, string name, ostream &os = cerr); Chatter(Chatter &&c); ostream &get_os() { return m_oss; } template Chatter &operator<<(const T& arg); ~Chatter(); static void enable_timestamp(bool prefix_timestamp); static void enable_level(bool prefix_level); }; template struct ChatterTraits { Chatter &operator()(Chatter &c, const Argument &arg) { c.get_os() << arg; return c; } }; template Chatter & Chatter::operator<<(const T& arg) { return ChatterTraits()(*this, arg); } template struct ChatterTraits { Chatter &operator()(Chatter &c, const Argument *arg) { if (arg) { c.get_os() << "(pointer to " << typeid(*arg).name() << ")(" << reinterpret_cast(arg) << ")"; } else { c.get_os() << "(NULL pointer to " << typeid(arg).name() << ')'; } return c; } }; template <> struct ChatterTraits { Chatter & operator()(Chatter &c, const char *arg) { c.get_os() << arg; return c; } }; class ChatterBox { string m_file; int m_line; string m_pretty_function; bool m_enabled; ostream& m_os; static set s_boxes; public: ChatterBox(string file, int line, string pretty_function, ostream &os = cerr); ~ChatterBox(); template Chatter operator<<(const T &t) { Chatter c(LOG_NOTICE, m_pretty_function, m_os); c << t; return c; } bool enabled() const { return m_enabled; } void set_enable(bool en); static set& all_boxes(); }; class ChatterUnwinder { function m_func; public: ChatterUnwinder(function f); ~ChatterUnwinder(); }; }; #define CHATTER(x) do { \ using namespace crucible; \ static ChatterBox crucible_chatterbox_cb(__FILE__, __LINE__, __func__); \ if (crucible_chatterbox_cb.enabled()) { \ crucible_chatterbox_cb << x; \ } \ } while (0) #define CHATTER_TRACE(x) do { \ using namespace crucible; \ static ChatterBox crucible_chatterbox_cb(__FILE__, __LINE__, __func__); \ if (crucible_chatterbox_cb.enabled()) { \ crucible_chatterbox_cb << __FILE__ << ":" << __LINE__ << ": " << x; \ } \ } while (0) #define WTF_C(x, y) x##y #define SRSLY_WTF_C(x, y) WTF_C(x, y) #define CHATTER_UNWIND(x) \ crucible::ChatterUnwinder SRSLY_WTF_C(chatterUnwinder_, __LINE__) ([&]() { \ CHATTER_TRACE(x); \ }) #endif // CRUCIBLE_CHATTER_H