diff options
Diffstat (limited to 'indra/test/debug.h')
-rw-r--r-- | indra/test/debug.h | 69 |
1 files changed, 40 insertions, 29 deletions
diff --git a/indra/test/debug.h b/indra/test/debug.h index 76dbb973b2..2f6a114761 100644 --- a/indra/test/debug.h +++ b/indra/test/debug.h @@ -30,43 +30,56 @@ #define LL_DEBUG_H #include "print.h" +#include "stringize.h" +#include <exception> // std::uncaught_exceptions() /***************************************************************************** * Debugging stuff *****************************************************************************/ /** - * This class is intended to illuminate entry to a given block, exit from the - * same block and checkpoints along the way. It also provides a convenient - * place to turn std::cerr output on and off. - * - * If the environment variable LOGTEST is non-empty, each Debug instance will - * announce its construction and destruction, presumably at entry and exit to - * the block in which it's declared. Moreover, any arguments passed to its - * operator()() will be streamed to std::cerr, prefixed by the block - * description. + * Return true if the environment variable LOGTEST is non-empty. * * The variable LOGTEST is used because that's the environment variable * checked by test.cpp, our TUT main() program, to turn on LLError logging. It * is expected that Debug is solely for use in test programs. */ +inline +bool LOGTEST_enabled() +{ + auto LOGTEST{ getenv("LOGTEST") }; + // debug output enabled when LOGTEST is set AND non-empty + return LOGTEST && *LOGTEST; +} + +/** + * This class is intended to illuminate entry to a given block, exit from the + * same block and checkpoints along the way. It also provides a convenient + * place to turn std::cerr output on and off. + * + * If enabled, each Debug instance will announce its construction and + * destruction, presumably at entry and exit to the block in which it's + * declared. Moreover, any arguments passed to its operator()() will be + * streamed to std::cerr, prefixed by the block description. + */ class Debug { public: - Debug(const std::string& block): - mBlock(block), - mLOGTEST(getenv("LOGTEST")), - // debug output enabled when LOGTEST is set AND non-empty - mEnabled(mLOGTEST && *mLOGTEST) + template <typename... ARGS> + Debug(ARGS&&... args): + mBlock(stringize(std::forward<ARGS>(args)...)), + mEnabled(LOGTEST_enabled()) { (*this)("entry"); } // non-copyable Debug(const Debug&) = delete; + Debug& operator=(const Debug&) = delete; ~Debug() { - (*this)("exit"); + auto exceptional{ std::uncaught_exceptions()? "exceptional " : "" }; + (*this)(exceptional, "exit"); } template <typename... ARGS> @@ -80,7 +93,6 @@ public: private: const std::string mBlock; - const char* mLOGTEST; bool mEnabled; }; @@ -88,20 +100,19 @@ private: // of the Debug block. #define DEBUG Debug debug(LL_PRETTY_FUNCTION) -// These BEGIN/END macros are specifically for debugging output -- please -// don't assume you must use such for coroutines in general! They only help to -// make control flow (as well as exception exits) explicit. -#define BEGIN \ -{ \ - DEBUG; \ - try +/// If enabled, debug_expr(expression) gives you output concerning an inline +/// expression such as a class member initializer. +#define debug_expr(expr) debug_expr_(#expr, [&](){ return expr; }) -#define END \ - catch (...) \ - { \ - debug("*** exceptional "); \ - throw; \ - } \ +template <typename EXPR> +inline auto debug_expr_(const char* strexpr, EXPR&& lambda) +{ + if (! LOGTEST_enabled()) + return std::forward<EXPR>(lambda)(); + print("Before: ", strexpr); + auto result{ std::forward<EXPR>(lambda)() }; + print(strexpr, " -> ", result); + return result; } #endif /* ! defined(LL_DEBUG_H) */ |