Bug 1271483 - p11. Implement comma-sep-string for-range iterator - r=cpearce
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
--- 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) {