#ifndef _DEBUG_H #define _DEBUG_H // // This file is distributed under the MIT License. See LICENSE.md for details. // // Standard includes #include #include #include #include #include // LLVM includes #include "llvm/ADT/StringRef.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ManagedStatic.h" // TODO: use a dedicated namespace extern bool DebuggingEnabled; extern std::ostream &dbg; bool isDebugFeatureEnabled(std::string Name); void enableDebugFeature(std::string Name); void disableDebugFeature(std::string Name); /// \brief Executes \p code only if \p feature is enabled /// /// \note This approach is deprecated, please consider using Logger and letting /// the DCE do its job for you. #define DBG(feature, code) do { \ if (DebuggingEnabled && isDebugFeatureEnabled(feature)) { \ code; \ } \ } while (0) /// \brief Enables a debug feature and disables it when goes out of scope class ScopedDebugFeature { public: /// \param Name the name of the debugging feature /// \param Enable whether to actually enable it or not ScopedDebugFeature(std::string Name, bool Enable) : Name(Name), Enabled(Enable) { if (Enabled) enableDebugFeature(Name); } ~ScopedDebugFeature() { if (Enabled) disableDebugFeature(Name); } private: std::string Name; bool Enabled; }; /// \brief Stream an instance of this class to call Logger::emit() struct LogTerminator { }; extern LogTerminator DoLog; /// \brief Logger that self-registers itself, can be disable, has a name and /// follows the global indentation level /// /// The typical usage of this class is to be a static global variable in a /// translation unit. template class Logger { private: static unsigned IndentLevel; public: Logger(llvm::StringRef Name) : Name(Name), Enabled(false) { init(); } void indent(unsigned Level=1) { if (isEnabled()) IndentLevel += Level; } void unindent(unsigned Level=1) { if (isEnabled()) { assert(IndentLevel - Level >= 0); IndentLevel -= Level; } } void setIndentation(unsigned Level) { if (isEnabled()) IndentLevel = Level; } bool isEnabled() const { return StaticEnabled && Enabled; } llvm::StringRef name() const { return Name; } void enable() { Enabled = true; } void disable() { Enabled = false; } /// \brief Write a log line /// /// To call this method using the stream syntax, see LogTerminator, or simply /// MyLogger << DoLog; void emit(); template inline Logger &operator<<(const T Other) { writeToLog(*this, Other, static_cast(0)); return *this; } template friend void writeToLog(Logger &This, const LogTerminator T, int Ignore); template friend void writeToLog(Logger &This, const T Other, LowPrio Ignore); private: void init(); private: llvm::StringRef Name; std::stringstream Buffer; bool Enabled; }; /// \brief Indent all loggers within the scope of this object template class LoggerIndent { public: LoggerIndent(Logger &L) : L(L) { L.indent(); } ~LoggerIndent() { L.unindent(); } private: Logger &L; }; /// \brief Emit a message for the specified logger upon return /// /// You can create an instance of this object associated to a Logger, so that /// when the object goes out of scope (typically, on return), the emit method /// will be invoked. template class LogOnReturn { public: LogOnReturn(Logger &L) : L(L) { } ~LogOnReturn() { L.emit(); } private: Logger &L; }; /// \brief The catch-all function for logging, it can log any type not already /// handled /// /// The \p Ignore argument is not used. It's only purpose is having a template /// argument as type, which makes it less specific that other functions that /// have a non-template type for the same argument. /// /// In practice, you can overload this function, specifying as type of \p Ignore /// int, and then choose the type T you want to handle. /// /// Note that here we introduced only two levels of priority, the fall back /// level (this function) and the ad-hoc level. Therefore, all the ad-hoc /// overloads should never have overlapping types for \p Other. /// /// For an example see the next specialization. template inline void writeToLog(Logger &This, const T Other, LowPrio Ignore) { (void) Other; (void) Ignore; if (This.isEnabled()) This.Buffer << Other; } /// \brief Specialization of writeToLog to emit a message template inline void writeToLog(Logger &This, const LogTerminator T, int Ignore) { (void) T; (void) Ignore; This.emit(); } /// \brief A global registry for all the loggers /// /// Loggers are usually global static variables in translation units, the role /// of this class is collecting them. class LoggersRegistry { public: LoggersRegistry() { } void add(Logger *L) { Loggers.push_back(L); } void add(Logger *L) { (void) L; } void enable(llvm::StringRef Name) { for (Logger *L : Loggers) if (L->name() == Name) L->enable(); } void disable(llvm::StringRef Name) { for (Logger *L : Loggers) if (L->name() == Name) L->disable(); } private: std::vector *> Loggers; }; extern llvm::ManagedStatic Loggers; template<> inline void Logger::init() { Loggers->add(this); } template<> inline void Logger::init() { } #endif // _DEBUG_H