Bug 1158430 - A small construct to allow only sending errors and warnings once per statement. r=botond
authorMilan Sreckovic <milan@mozilla.com>
Mon, 27 Apr 2015 14:44:13 -0400
changeset 273135 7516ef90ea6045ccecdc611bcd2794b662bcb403
parent 273134 86f56b03114ed1c4b8a606e3a6051c59774ee678
child 273136 20406039cdebb797c6990dbbb7d3bf42bbacaa30
push id863
push userraliiev@mozilla.com
push dateMon, 03 Aug 2015 13:22:43 +0000
treeherdermozilla-release@f6321b14228d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbotond
bugs1158430
milestone40.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1158430 - A small construct to allow only sending errors and warnings once per statement. r=botond
gfx/2d/Logging.h
--- a/gfx/2d/Logging.h
+++ b/gfx/2d/Logging.h
@@ -215,16 +215,19 @@ public:
 };
 
 class NoLog
 {
 public:
   NoLog() {}
   ~NoLog() {}
 
+  // No-op
+  MOZ_IMPLICIT NoLog(const NoLog&) {}
+
   template<typename T>
   NoLog &operator <<(const T &aLogText) { return *this; }
 };
 
 enum class LogOptions : int {
   NoNewline = 0x01,
   AutoPrefix = 0x02,
   AssertOnCall = 0x04
@@ -248,45 +251,31 @@ public:
     return (int(LogOptions::AutoPrefix) |
             (aWithAssert ? int(LogOptions::AssertOnCall) : 0));
   }
 
   // Note that we're calling BasicLogger::ShouldOutputMessage, rather than
   // Logger::ShouldOutputMessage.  Since we currently don't have a different
   // version of that method for different loggers, this is OK. Once we do,
   // change BasicLogger::ShouldOutputMessage to Logger::ShouldOutputMessage.
-  explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL))
-    : mOptions(aOptions)
-    , mLogIt(BasicLogger::ShouldOutputMessage(L))
-  {
-    if (mLogIt && AutoPrefix()) {
-      if (mOptions & int(LogOptions::AssertOnCall)) {
-        mMessage << "[GFX" << L << "]: ";
-      } else {
-        mMessage << "[GFX" << L << "-]: ";
-      }
-    }
+  explicit Log(int aOptions = Log::DefaultOptions(L == LOG_CRITICAL)) {
+    Init(aOptions, BasicLogger::ShouldOutputMessage(L));
   }
+
   ~Log() {
     Flush();
   }
 
   void Flush() {
     if (MOZ_LIKELY(!LogIt())) return;
 
     std::string str = mMessage.str();
     if (!str.empty()) {
       WriteLog(str);
     }
-    if (AutoPrefix()) {
-      mMessage.str("[GFX");
-      mMessage << L << "]: ";
-    } else {
-      mMessage.str("");
-    }
     mMessage.clear();
   }
 
   Log &operator <<(char aChar) {
     if (MOZ_UNLIKELY(LogIt())) {
       mMessage << aChar;
     }
     return *this;
@@ -473,18 +462,34 @@ public:
     }
     return *this;
   }
 
   inline bool LogIt() const { return mLogIt; }
   inline bool NoNewline() const { return mOptions & int(LogOptions::NoNewline); }
   inline bool AutoPrefix() const { return mOptions & int(LogOptions::AutoPrefix); }
 
+  // We do not want this version to do any work, and stringstream can't be
+  // copied anyway.  It does come in handy for the "Once" macro defined below.
+  MOZ_IMPLICIT Log(const Log& log) { Init(log.mOptions, false); }
 
 private:
+  // Initialization common to two constructors
+  void Init(int aOptions, bool aLogIt) {
+    mOptions = aOptions;
+    mLogIt = aLogIt;
+    if (mLogIt && AutoPrefix()) {
+      if (mOptions & int(LogOptions::AssertOnCall)) {
+        mMessage << "[GFX" << L << "]: ";
+      } else {
+        mMessage << "[GFX" << L << "-]: ";
+      }
+    }
+  }
+
   void WriteLog(const std::string &aString) {
     if (MOZ_UNLIKELY(LogIt())) {
       Logger::OutputMessage(aString, L, NoNewline());
       if (mOptions & int(LogOptions::AssertOnCall)) {
         MOZ_ASSERT(false, "An assert from the graphics logger");
       }
     }
   }
@@ -493,30 +498,50 @@ private:
   int mOptions;
   bool mLogIt;
 };
 
 typedef Log<LOG_DEBUG> DebugLog;
 typedef Log<LOG_WARNING> WarningLog;
 typedef Log<LOG_CRITICAL, CriticalLogger> CriticalLog;
 
+// Macro to glue names to get us less chance of name clashing.
+#if defined GFX_LOGGING_GLUE1 || defined GFX_LOGGING_GLUE
+#error "Clash of the macro GFX_LOGGING_GLUE1 or GFX_LOGGING_GLUE"
+#endif
+#define GFX_LOGGING_GLUE1(x, y)  x##y
+#define GFX_LOGGING_GLUE(x, y)   GFX_LOGGING_GLUE1(x, y)
+
+// This log goes into crash reports, use with care.
+#define gfxCriticalError mozilla::gfx::CriticalLog
+#define gfxCriticalErrorOnce static gfxCriticalError GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxCriticalError
+
+// The "once" versions will only trigger the first time through. You can do this:
+// gfxCriticalErrorOnce() << "This message only shows up once;
+// instead of the usual:
+// static bool firstTime = true;
+// if (firstTime) {
+//   firstTime = false;
+//   gfxCriticalError() << "This message only shows up once;
+// }
 #ifdef GFX_LOG_DEBUG
 #define gfxDebug mozilla::gfx::DebugLog
+#define gfxDebugOnce static gfxDebug GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxDebug
 #else
 #define gfxDebug if (1) ; else mozilla::gfx::NoLog
+#define gfxDebugOnce if (1) ; else mozilla::gfx::NoLog
 #endif
 #ifdef GFX_LOG_WARNING
 #define gfxWarning mozilla::gfx::WarningLog
+#define gfxWarningOnce static gfxWarning GFX_LOGGING_GLUE(sOnceAtLine,__LINE__) = gfxWarning
 #else
 #define gfxWarning if (1) ; else mozilla::gfx::NoLog
+#define gfxWarningOnce if (1) ; else mozilla::gfx::NoLog
 #endif
 
-// This log goes into crash reports, use with care.
-#define gfxCriticalError mozilla::gfx::CriticalLog
-
 // See nsDebug.h and the NS_WARN_IF macro
 
 #ifdef __cplusplus
  // For now, have MOZ2D_ERROR_IF available in debug and non-debug builds
 inline bool MOZ2D_error_if_impl(bool aCondition, const char* aExpr,
                                 const char* aFile, int32_t aLine)
 {
   if (MOZ_UNLIKELY(aCondition)) {