Bug 1271483 - p11. Implement comma-sep-string for-range iterator - r=cpearce, a=lizzard
authorGerald Squelart <gsquelart@mozilla.com>
Thu, 26 May 2016 16:43:16 +1000
changeset 339799 5d717e3c331f03d167c71669837fb9deb16c7b59
parent 339798 83def5aed3dabab6259be8debb4a7e92117acd2d
child 339800 c99836f4707dcff72ac1f16bf99edcfb8fa61660
push id6249
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 13:59:36 +0000
treeherdermozilla-beta@bad9d4f5bf7e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscpearce, lizzard
bugs1271483
milestone49.0a2
Bug 1271483 - p11. Implement comma-sep-string for-range iterator - r=cpearce, a=lizzard Utility class&function that creates an iteratable range from a comma-separated string, where each iteration will give a dependent substring (i.e., no string copy happening). This will help with going through lists of unplayable formats, to see if issues have been solved. If useful enough, this could later be published to a more public location (e.g. mfbt or xpcom). MozReview-Commit-ID: 3XP5PwQZFA1
dom/media/DecoderDoctorDiagnostics.cpp
--- a/dom/media/DecoderDoctorDiagnostics.cpp
+++ b/dom/media/DecoderDoctorDiagnostics.cpp
@@ -232,16 +232,129 @@ DecoderDoctorDocumentWatcher::EnsureTime
     if (NS_WARN_IF(NS_FAILED(
           mTimer->InitWithCallback(
             this, sAnalysisPeriod_ms, nsITimer::TYPE_ONE_SHOT)))) {
       mTimer = nullptr;
     }
   }
 }
 
+template <typename String>
+class StringListRange
+{
+  typedef typename String::char_type CharType;
+  typedef const CharType* Pointer;
+
+public:
+  // Iterator into range, trims items and skips empty items.
+  class Iterator
+  {
+  public:
+    bool operator!=(const Iterator& a) const
+    {
+      return mStart != a.mStart || mEnd != a.mEnd;
+    }
+    Iterator& operator++()
+    {
+      SearchItemAt(mComma + 1);
+      return *this;
+    }
+    typedef decltype(Substring(Pointer(), Pointer())) DereferencedType;
+    DereferencedType operator*()
+    {
+      return Substring(mStart, mEnd);
+    }
+  private:
+    friend class StringListRange;
+    Iterator(const CharType* aRangeStart, uint32_t aLength)
+      : mRangeEnd(aRangeStart + aLength)
+    {
+      SearchItemAt(aRangeStart);
+    }
+    void SearchItemAt(Pointer start)
+    {
+      // First, skip leading whitespace.
+      for (Pointer p = start; ; ++p) {
+        if (p >= mRangeEnd) {
+          mStart = mEnd = mComma = mRangeEnd;
+          return;
+        }
+        auto c = *p;
+        if (c == CharType(',')) {
+          // Comma -> Empty item -> Skip.
+        } else if (c != CharType(' ')) {
+          mStart = p;
+          break;
+        }
+      }
+      // Find comma, recording start of trailing space.
+      Pointer trailingWhitespace = nullptr;
+      for (Pointer p = mStart + 1; ; ++p) {
+        if (p >= mRangeEnd) {
+          mEnd = trailingWhitespace ? trailingWhitespace : p;
+          mComma = p;
+          return;
+        }
+        auto c = *p;
+        if (c == CharType(',')) {
+          mEnd = trailingWhitespace ? trailingWhitespace : p;
+          mComma = p;
+          return;
+        }
+        if (c == CharType(' ')) {
+          // Found a whitespace -> Record as trailing if not first one.
+          if (!trailingWhitespace) {
+            trailingWhitespace = p;
+          }
+        } else {
+          // Found a non-whitespace -> Reset trailing whitespace if needed.
+          if (trailingWhitespace) {
+            trailingWhitespace = nullptr;
+          }
+        }
+      }
+    }
+    const Pointer mRangeEnd;
+    Pointer mStart;
+    Pointer mEnd;
+    Pointer mComma;
+  };
+
+  explicit StringListRange(const String& aList) : mList(aList) {}
+  Iterator begin()
+  {
+    return Iterator(mList.Data(), mList.Length());
+  }
+  Iterator end()
+  {
+    return Iterator(mList.Data() + mList.Length(), 0);
+  }
+private:
+  const String& mList;
+};
+
+template <typename String>
+StringListRange<String>
+MakeStringListRange(const String& aList)
+{
+  return StringListRange<String>(aList);
+}
+
+template <typename ListString, typename ItemString>
+static bool
+StringListContains(const ListString& aList, const ItemString& aItem)
+{
+  for (const auto& listItem : MakeStringListRange(aList)) {
+    if (listItem.Equals(aItem)) {
+      return true;
+    }
+  }
+  return false;
+}
+
 static void
 DispatchNotification(nsISupports* aSubject,
                      dom::DecoderDoctorNotificationType aNotificationType,
                      bool aIsSolved,
                      const char* aReportStringId,
                      const nsAString& aFormats)
 {
   if (!aSubject) {