Bug 1523878 - Update ContentBlockingLog to use struct instead of tuple<>, r=ehsan
☠☠ backed out by a5f0e7af6f5c ☠ ☠
authorAndrea Marchesini <amarchesini@mozilla.com>
Wed, 30 Jan 2019 14:06:09 +0100
changeset 456397 5f53c5571125b1c05187ceeaef7d21c30608e5b3
parent 456396 dd571576b11bea63719d7f178d4ea5e19305d196
child 456398 648e0d2c5ef838186b7a4f688cf5568fea4829bb
push id19
push usermdeboer@mozilla.com
push dateFri, 01 Feb 2019 10:05:45 +0000
reviewersehsan
bugs1523878
milestone67.0a1
Bug 1523878 - Update ContentBlockingLog to use struct instead of tuple<>, r=ehsan Differential Revision: https://phabricator.services.mozilla.com/D18052
dom/base/ContentBlockingLog.h
--- a/dom/base/ContentBlockingLog.h
+++ b/dom/base/ContentBlockingLog.h
@@ -21,194 +21,206 @@ namespace dom {
 
 class ContentBlockingLog final {
   struct LogEntry {
     uint32_t mType;
     uint32_t mRepeatCount;
     bool mBlocked;
   };
 
-  // Each element is a tuple of (type, blocked, repeatCount). The type values
-  // come from the blocking types defined in nsIWebProgressListener.
-  typedef nsTArray<LogEntry> OriginLog;
-  typedef Tuple<bool, Maybe<bool>, OriginLog> OriginData;
-  typedef nsTArray<Tuple<nsCString, UniquePtr<OriginData>>> OriginDataTable;
+  struct OriginDataEntry {
+    OriginDataEntry() : mHasTrackingContentLoaded(false) {}
+
+    bool mHasTrackingContentLoaded;
+    Maybe<bool> mHasCookiesLoaded;
+    nsTArray<LogEntry> mLogs;
+  };
+
+  struct OriginEntry {
+    OriginEntry() { mData = MakeUnique<OriginDataEntry>(); }
+
+    nsCString mOrigin;
+    UniquePtr<OriginDataEntry> mData;
+  };
+
+  typedef nsTArray<OriginEntry> OriginDataTable;
 
   struct StringWriteFunc : public JSONWriteFunc {
     nsACString&
         mBuffer;  // The lifetime of the struct must be bound to the buffer
     explicit StringWriteFunc(nsACString& aBuffer) : mBuffer(aBuffer) {}
 
     void Write(const char* aStr) override { mBuffer.Append(aStr); }
   };
 
   struct Comparator {
    public:
     bool Equals(const OriginDataTable::elem_type& aLeft,
                 const OriginDataTable::elem_type& aRight) const {
-      return Get<0>(aLeft).Equals(Get<0>(aRight));
+      return aLeft.mOrigin.Equals(aRight.mOrigin);
     }
 
     bool Equals(const OriginDataTable::elem_type& aLeft,
                 const nsACString& aRight) const {
-      return Get<0>(aLeft).Equals(aRight);
+      return aLeft.mOrigin.Equals(aRight);
     }
   };
 
  public:
   ContentBlockingLog() = default;
   ~ContentBlockingLog() = default;
 
   void RecordLog(const nsACString& aOrigin, uint32_t aType, bool aBlocked) {
     if (aOrigin.IsVoid()) {
       return;
     }
     auto index = mLog.IndexOf(aOrigin, 0, Comparator());
     if (index != OriginDataTable::NoIndex) {
-      auto& data = Get<1>(mLog[index]);
+      OriginEntry& entry = mLog[index];
+      if (!entry.mData) {
+        return;
+      }
+
       if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
-        Get<0>(*data) = aBlocked;
+        entry.mData->mHasTrackingContentLoaded = aBlocked;
         return;
       }
       if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
-        if (Get<1>(*data).isSome()) {
-          Get<1>(*data).ref() = aBlocked;
+        if (entry.mData->mHasCookiesLoaded.isSome()) {
+          entry.mData->mHasCookiesLoaded.ref() = aBlocked;
         } else {
-          Get<1>(*data).emplace(aBlocked);
+          entry.mData->mHasCookiesLoaded.emplace(aBlocked);
         }
         return;
       }
-      auto& log = Get<2>(*data);
-      if (!log.IsEmpty()) {
-        auto& last = log.LastElement();
+      if (!entry.mData->mLogs.IsEmpty()) {
+        auto& last = entry.mData->mLogs.LastElement();
         if (last.mType == aType && last.mBlocked == aBlocked) {
           ++last.mRepeatCount;
           // Don't record recorded events.  This helps compress our log.
           return;
         }
       }
-      if (log.Length() ==
+      if (entry.mData->mLogs.Length() ==
           std::max(1u,
                    StaticPrefs::browser_contentblocking_originlog_length())) {
         // Cap the size at the maximum length adjustable by the pref
-        log.RemoveElementAt(0);
+        entry.mData->mLogs.RemoveElementAt(0);
       }
-      log.AppendElement(LogEntry{aType, 1u, aBlocked});
+      entry.mData->mLogs.AppendElement(LogEntry{aType, 1u, aBlocked});
+      return;
+    }
+
+    // The entry has not been found.
+
+    OriginEntry* entry = mLog.AppendElement();
+    if (NS_WARN_IF(!entry || !entry->mData)) {
+      return;
+    }
+
+    entry->mOrigin = aOrigin;
+
+    if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
+      entry->mData->mHasTrackingContentLoaded = aBlocked;
+    } else if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
+      MOZ_ASSERT(entry->mData->mHasCookiesLoaded.isNothing());
+      entry->mData->mHasCookiesLoaded.emplace(aBlocked);
     } else {
-      auto data = MakeUnique<OriginData>(false, Maybe<bool>(), OriginLog());
-      if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
-        Get<0>(*data) = aBlocked;
-      } else if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
-        if (Get<1>(*data).isSome()) {
-          Get<1>(*data).ref() = aBlocked;
-        } else {
-          Get<1>(*data).emplace(aBlocked);
-        }
-      } else {
-        Get<2>(*data).AppendElement(LogEntry{aType, 1u, aBlocked});
-      }
-      nsAutoCString origin(aOrigin);
-      mLog.AppendElement(Tuple<nsCString, UniquePtr<OriginData>>(
-          std::move(origin), std::move(data)));
+      entry->mData->mLogs.AppendElement(LogEntry{aType, 1u, aBlocked});
     }
   }
 
   nsAutoCString Stringify() {
     nsAutoCString buffer;
 
     JSONWriter w(MakeUnique<StringWriteFunc>(buffer));
     w.Start();
 
-    const auto end = mLog.end();
-    for (auto iter = mLog.begin(); iter != end; ++iter) {
-      if (!Get<1>(*iter)) {
-        w.StartArrayProperty(Get<0>(*iter).get(), w.SingleLineStyle);
-        w.EndArray();
+    for (const OriginEntry& entry : mLog) {
+      if (!entry.mData) {
         continue;
       }
 
-      w.StartArrayProperty(Get<0>(*iter).get(), w.SingleLineStyle);
-      auto& data = Get<1>(*iter);
-      if (Get<0>(*data)) {
+      w.StartArrayProperty(entry.mOrigin.get(), w.SingleLineStyle);
+
+      if (entry.mData->mHasTrackingContentLoaded) {
         w.StartArrayElement(w.SingleLineStyle);
         {
           w.IntElement(nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT);
           w.BoolElement(true);  // blocked
           w.IntElement(1);      // repeat count
         }
         w.EndArray();
       }
-      if (Get<1>(*data).isSome()) {
+      if (entry.mData->mHasCookiesLoaded.isSome()) {
         w.StartArrayElement(w.SingleLineStyle);
         {
           w.IntElement(nsIWebProgressListener::STATE_COOKIES_LOADED);
-          w.BoolElement(Get<1>(*data).value());  // blocked
-          w.IntElement(1);                       // repeat count
+          w.BoolElement(entry.mData->mHasCookiesLoaded.value());  // blocked
+          w.IntElement(1);  // repeat count
         }
         w.EndArray();
       }
-      for (auto& item : Get<2>(*data)) {
+      for (const LogEntry& item : entry.mData->mLogs) {
         w.StartArrayElement(w.SingleLineStyle);
         {
           w.IntElement(item.mType);
           w.BoolElement(item.mBlocked);
           w.IntElement(item.mRepeatCount);
         }
         w.EndArray();
       }
       w.EndArray();
     }
 
     w.End();
 
     return buffer;
   }
 
-  bool HasBlockedAnyOfType(uint32_t aType) {
+  bool HasBlockedAnyOfType(uint32_t aType) const {
     // Note: nothing inside this loop should return false, the goal for the
     // loop is to scan the log to see if we find a matching entry, and if so
     // we would return true, otherwise in the end of the function outside of
     // the loop we take the common `return false;` statement.
-    const auto end = mLog.end();
-    for (auto iter = mLog.begin(); iter != end; ++iter) {
-      if (!Get<1>(*iter)) {
+    for (const OriginEntry& entry : mLog) {
+      if (!entry.mData) {
         continue;
       }
 
       if (aType == nsIWebProgressListener::STATE_LOADED_TRACKING_CONTENT) {
-        if (Get<0>(*Get<1>(*iter))) {
+        if (entry.mData->mHasTrackingContentLoaded) {
           return true;
         }
       } else if (aType == nsIWebProgressListener::STATE_COOKIES_LOADED) {
-        if (Get<1>(*Get<1>(*iter)).isSome() && Get<1>(*Get<1>(*iter)).value()) {
+        if (entry.mData->mHasCookiesLoaded.isSome() &&
+            entry.mData->mHasCookiesLoaded.value()) {
           return true;
         }
       } else {
-        for (auto& item : Get<2>(*Get<1>(*iter))) {
+        for (const auto& item : entry.mData->mLogs) {
           if (((item.mType & aType) != 0) && item.mBlocked) {
             return true;
           }
         }
       }
     }
     return false;
   }
 
   void AddSizeOfExcludingThis(nsWindowSizes& aSizes) const {
     aSizes.mDOMOtherSize +=
         mLog.ShallowSizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
 
     // Now add the sizes of each origin log queue.
-    const auto end = mLog.end();
-    for (auto iter = mLog.begin(); iter != end; ++iter) {
-      if (!Get<1>(*iter)) {
-        aSizes.mDOMOtherSize +=
-            aSizes.mState.mMallocSizeOf(Get<1>(*iter).get()) +
-            Get<2>(*Get<1>(*iter))
-                .ShallowSizeOfExcludingThis(aSizes.mState.mMallocSizeOf);
+    for (const OriginEntry& entry : mLog) {
+      if (entry.mData) {
+        aSizes.mDOMOtherSize += aSizes.mState.mMallocSizeOf(entry.mData.get()) +
+                                entry.mData->mLogs.ShallowSizeOfExcludingThis(
+                                    aSizes.mState.mMallocSizeOf);
       }
     }
   }
 
  private:
   OriginDataTable mLog;
 };