Bug 958596 - Add support a tree logging utility. r=Bas
☠☠ backed out by c9f4f70e46e1 ☠ ☠
authorBotond Ballo <botond@mozilla.com>
Tue, 21 Jan 2014 20:14:47 -0500
changeset 170927 715fe9eb5dfda2782f59d8efb1c7241dc7c8bb42
parent 170926 66dde9d67ffa7ffb59ffdd4d636ddad9021535fb
child 170928 0d1d26d588e3b9641aa344657e55b8b527307b7c
push id270
push userpvanderbeken@mozilla.com
push dateThu, 06 Mar 2014 09:24:21 +0000
reviewersBas
bugs958596
milestone30.0a1
Bug 958596 - Add support a tree logging utility. r=Bas
gfx/2d/Logging.h
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -86,19 +86,29 @@ MOZ_BEGIN_ENUM_CLASS(LogOptions, int)
 MOZ_END_ENUM_CLASS(LogOptions)
 
 template<int L>
 class Log
 {
 public:
   Log(LogOptions aOptions = LogOptions(0)) : mOptions(aOptions) {}
   ~Log() {
-    if (!(int(mOptions) & int(LogOptions::NoNewline)))
+    Flush();
+  }
+
+  void Flush() {
+    if (!(int(mOptions) & int(LogOptions::NoNewline))) {
       mMessage << '\n';
-    WriteLog(mMessage.str());
+    }
+    std::string str = mMessage.str();
+    if (!str.empty()) {
+      WriteLog(str);
+    }
+    mMessage.str("");
+    mMessage.clear();
   }
 
   Log &operator <<(char aChar) { mMessage << aChar; return *this; }
   Log &operator <<(const std::string &aLogText) { mMessage << aLogText; return *this; }
   Log &operator <<(const char aStr[]) { mMessage << static_cast<const char*>(aStr); return *this; }
   Log &operator <<(bool aBool) { mMessage << (aBool ? "true" : "false"); return *this; }
   Log &operator <<(int aInt) { mMessage << aInt; return *this; }
   Log &operator <<(unsigned int aInt) { mMessage << aInt; return *this; }
@@ -138,12 +148,78 @@ typedef Log<LOG_WARNING> WarningLog;
 #define gfxDebug if (1) ; else NoLog
 #endif
 #ifdef GFX_LOG_WARNING
 #define gfxWarning WarningLog
 #else
 #define gfxWarning if (1) ; else NoLog
 #endif
 
+const int INDENT_PER_LEVEL = 2;
+
+class TreeLog
+{
+public:
+  TreeLog(const std::string& aPrefix = "")
+        : mLog(LogOptions::NoNewline),
+          mPrefix(aPrefix),
+          mDepth(0),
+          mStartOfLine(true) {}
+
+  template <typename T>
+  TreeLog& operator<<(const T& aObject) {
+    if (mStartOfLine) {
+      mLog << '[' << mPrefix << "] " << std::string(mDepth * INDENT_PER_LEVEL, ' ');
+      mStartOfLine = false;
+    }
+    mLog << aObject;
+    if (EndsInNewline(aObject)) {
+      // Don't indent right here as the user may change the indent
+      // between now and the first output to the next line.
+      mLog.Flush();
+      mStartOfLine = true;
+    }
+    return *this;
+  }
+
+  void IncreaseIndent() { ++mDepth; }
+  void DecreaseIndent() { --mDepth; }
+private:
+  Log<LOG_DEBUG> mLog;
+  std::string mPrefix;
+  uint32_t mDepth;
+  bool mStartOfLine;
+
+  template <typename T>
+  static bool EndsInNewline(const T& aObject) {
+    return false;
+  }
+
+  static bool EndsInNewline(const std::string& aString) {
+    return !aString.empty() && aString[aString.length() - 1] == '\n';
+  }
+
+  static bool EndsInNewline(char aChar) {
+    return aChar == '\n';
+  }
+
+  static bool EndsInNewline(const char* aString) {
+    return EndsInNewline(std::string(aString));
+  }
+};
+
+class TreeAutoIndent
+{
+public:
+  TreeAutoIndent(TreeLog& aTreeLog) : mTreeLog(aTreeLog) {
+    mTreeLog.IncreaseIndent();
+  }
+  ~TreeAutoIndent() {
+    mTreeLog.DecreaseIndent();
+  }
+private:
+  TreeLog& mTreeLog;
+};
+
 }
 }
 
 #endif /* MOZILLA_GFX_LOGGING_H_ */