Bug 1330326 - Add Split() function on String classes. r=froydnj draft
authorGian-Carlo Pascutto <gcp@mozilla.com>
Mon, 30 Jan 2017 12:34:35 +0100
changeset 467945 e39f37936f5b07411921b9875a85fd55241847be
parent 467944 64495294736db7a9c21f16dc23449a3d6f477534
child 467946 058d894f8fd021a9643d0fdec89ce8e84fd458a7
push id43309
push usergpascutto@mozilla.com
push dateMon, 30 Jan 2017 11:35:32 +0000
reviewersfroydnj
bugs1330326
milestone54.0a1
Bug 1330326 - Add Split() function on String classes. r=froydnj MozReview-Commit-ID: 3xug2xMR60j
xpcom/string/nsTSubstring.cpp
xpcom/string/nsTSubstring.h
xpcom/string/string-template-def-char.h
xpcom/string/string-template-def-unichar.h
xpcom/string/string-template-undef.h
xpcom/tests/gtest/TestStrings.cpp
--- a/xpcom/string/nsTSubstring.cpp
+++ b/xpcom/string/nsTSubstring.cpp
@@ -1078,8 +1078,17 @@ nsTSubstring_CharT::SizeOfIncludingThisI
 
 size_t
 nsTSubstring_CharT::SizeOfIncludingThisEvenIfShared(
     mozilla::MallocSizeOf aMallocSizeOf) const
 {
   return aMallocSizeOf(this) + SizeOfExcludingThisEvenIfShared(aMallocSizeOf);
 }
 
+nsTSubstringSplitter_CharT nsTSubstring_CharT::Split(const nsTSubstring_CharT::char_type aChar)
+{
+  return nsTSubstringSplitter_CharT(this, aChar);
+}
+
+const nsTSubstring_CharT& nsTSubstringSplitter_CharT::nsTSubstringSplit_Iter::operator* () const
+{
+   return mObj.Get(mPos);
+}
--- a/xpcom/string/nsTSubstring.h
+++ b/xpcom/string/nsTSubstring.h
@@ -1,16 +1,17 @@
 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 // IWYU pragma: private, include "nsString.h"
 
 #include "mozilla/Casting.h"
+#include "mozilla/UniquePtr.h"
 #include "mozilla/MemoryReporting.h"
 
 #ifndef MOZILLA_INTERNAL_API
 #error Cannot use internal string classes without MOZILLA_INTERNAL_API defined. Use the frozen header nsStringAPI.h instead.
 #endif
 
 /**
  * The base for string comparators
@@ -41,16 +42,18 @@ public:
   nsTDefaultStringComparator_CharT()
   {
   }
 
   virtual int operator()(const char_type*, const char_type*,
                          uint32_t, uint32_t) const override;
 };
 
+class nsTSubstringSplitter_CharT;
+
 /**
  * nsTSubstring is the most abstract class in the string hierarchy. It
  * represents a single contiguous array of characters, which may or may not
  * be null-terminated. This type is not instantiated directly.  A sub-class
  * is instantiated instead.  For example, see nsTString.
  *
  * NAMES:
  *   nsAString for wide characters
@@ -704,16 +707,17 @@ public:
     ReplaceLiteral(aPos, 0, aStr, N - 1);
   }
 
   void Cut(index_type aCutStart, size_type aCutLength)
   {
     Replace(aCutStart, aCutLength, char_traits::sEmptyBuffer, 0);
   }
 
+  nsTSubstringSplitter_CharT Split(const char_type aChar);
 
   /**
    * buffer sizing
    */
 
   /**
    * Attempts to set the capacity to the given size in number of
    * characters, without affecting the length of the string.
@@ -902,18 +906,17 @@ public:
   {
     ::NS_ABORT_OOM(aLength * sizeof(char_type));
   }
 
 protected:
 
   friend class nsTObsoleteAStringThunk_CharT;
   friend class nsTSubstringTuple_CharT;
-
-  // XXX GCC 3.4 needs this :-(
+  friend class nsTSubstringSplitter_CharT;
   friend class nsTPromiseFlatString_CharT;
 
   char_type*  mData;
   size_type   mLength;
   uint32_t    mFlags;
 
   // default initialization
   nsTSubstring_CharT()
@@ -1163,8 +1166,97 @@ operator>=(const nsTSubstring_CharT::bas
 }
 
 inline bool
 operator>(const nsTSubstring_CharT::base_string_type& aLhs,
           const nsTSubstring_CharT::base_string_type& aRhs)
 {
   return Compare(aLhs, aRhs) > 0;
 }
+
+// You should not need to instantiate this class directly.
+// Use nsTSubstring::Split instead.
+class nsTSubstringSplitter_CharT
+{
+  class nsTSubstringSplit_Iter
+  {
+  public:
+    nsTSubstringSplit_Iter(const nsTSubstringSplitter_CharT& aObj,
+                           nsTSubstring_CharT::size_type aPos)
+      : mObj(aObj)
+      , mPos(aPos)
+    {
+    }
+
+    bool operator!=(const nsTSubstringSplit_Iter& other) const
+    {
+      return mPos != other.mPos;
+    }
+
+    const nsTSubstring_CharT& operator*() const;
+
+    const nsTSubstringSplit_Iter& operator++()
+    {
+      ++mPos;
+      return *this;
+    }
+
+  private:
+    const nsTSubstringSplitter_CharT& mObj;
+    nsTSubstring_CharT::size_type mPos;
+  };
+
+private:
+  const nsTSubstring_CharT* mStr;
+  mozilla::UniquePtr<nsTSubstring_CharT[]> mArray;
+  nsTSubstring_CharT::size_type mArraySize;
+  const nsTSubstring_CharT::char_type mDelim;
+
+public:
+  nsTSubstringSplitter_CharT(const nsTSubstring_CharT* aStr,
+                             nsTSubstring_CharT::char_type aDelim)
+    : mStr(aStr)
+    , mArray(nullptr)
+    , mDelim(aDelim)
+  {
+    if (mStr->IsEmpty()) {
+      mArraySize = 0;
+      return;
+    }
+
+    nsTSubstring_CharT::size_type delimCount = mStr->CountChar(aDelim);
+    mArraySize = delimCount + 1;
+    mArray.reset(new nsTSubstring_CharT[mArraySize]);
+
+    size_t seenParts = 0;
+    nsTSubstring_CharT::size_type start = 0;
+    do {
+      MOZ_ASSERT(seenParts < mArraySize);
+      int32_t offset = mStr->FindChar(aDelim, start);
+      if (offset != -1) {
+        nsTSubstring_CharT::size_type length =
+          static_cast<nsTSubstring_CharT::size_type>(offset) - start;
+        mArray[seenParts++].Assign(mStr->Data() + start, length);
+        start = static_cast<nsTSubstring_CharT::size_type>(offset) + 1;
+      } else {
+        // Get the remainder
+        mArray[seenParts++].Assign(mStr->Data() + start, mStr->Length() - start);
+        break;
+      }
+    } while (start < mStr->Length());
+  }
+
+  nsTSubstringSplit_Iter begin() const
+  {
+    return nsTSubstringSplit_Iter(*this, 0);
+  }
+
+  nsTSubstringSplit_Iter end() const
+  {
+    return nsTSubstringSplit_Iter(*this, mArraySize);
+  }
+
+  const nsTSubstring_CharT& Get(const nsTSubstring_CharT::size_type index) const
+  {
+    MOZ_ASSERT(index < mArraySize);
+    return mArray[index];
+  }
+};
--- a/xpcom/string/string-template-def-char.h
+++ b/xpcom/string/string-template-def-char.h
@@ -18,8 +18,9 @@
 #define nsTDependentString_CharT            nsDependentCString
 #define nsTDependentSubstring_CharT         nsDependentCSubstring
 #define nsTLiteralString_CharT              nsLiteralCString
 #define nsTXPIDLString_CharT                nsXPIDLCString
 #define nsTGetterCopies_CharT               nsCGetterCopies
 #define nsTAdoptingString_CharT             nsAdoptingCString
 #define nsTPromiseFlatString_CharT          nsPromiseFlatCString
 #define TPromiseFlatString_CharT            PromiseFlatCString
+#define nsTSubstringSplitter_CharT          nsCSubstringSplitter
--- a/xpcom/string/string-template-def-unichar.h
+++ b/xpcom/string/string-template-def-unichar.h
@@ -18,8 +18,9 @@
 #define nsTDependentString_CharT            nsDependentString
 #define nsTDependentSubstring_CharT         nsDependentSubstring
 #define nsTLiteralString_CharT              nsLiteralString
 #define nsTXPIDLString_CharT                nsXPIDLString
 #define nsTGetterCopies_CharT               nsGetterCopies
 #define nsTAdoptingString_CharT             nsAdoptingString
 #define nsTPromiseFlatString_CharT          nsPromiseFlatString
 #define TPromiseFlatString_CharT            PromiseFlatString
+#define nsTSubstringSpliiter_CharT          nsSubstringSplitter
--- a/xpcom/string/string-template-undef.h
+++ b/xpcom/string/string-template-undef.h
@@ -19,8 +19,9 @@
 #undef nsTDependentString_CharT
 #undef nsTDependentSubstring_CharT
 #undef nsTLiteralString_CharT
 #undef nsTXPIDLString_CharT
 #undef nsTGetterCopies_CharT
 #undef nsTAdoptingString_CharT
 #undef nsTPromiseFlatString_CharT
 #undef TPromiseFlatString_CharT
+#undef nsTSubstringSplitter_CharT
--- a/xpcom/tests/gtest/TestStrings.cpp
+++ b/xpcom/tests/gtest/TestStrings.cpp
@@ -6,16 +6,17 @@
 
 #include <stdio.h>
 #include <stdlib.h>
 #include "nsString.h"
 #include "nsStringBuffer.h"
 #include "nsReadableUtils.h"
 #include "nsCRTGlue.h"
 #include "mozilla/RefPtr.h"
+#include "mozilla/Unused.h"
 #include "nsTArray.h"
 #include "gtest/gtest.h"
 
 namespace TestStrings {
 
 using mozilla::fallible;
 
 void test_assign_helper(const nsACString& in, nsACString &_retval)
@@ -973,9 +974,79 @@ TEST(Strings, todouble)
   test_todouble_helper(NS_LITERAL_STRING("123456789.98765432123456"), 123456789.98765432123456, true);
   test_todouble_helper(NS_LITERAL_STRING("0"), 0, true);
   test_todouble_helper(NS_LITERAL_STRING("1.e5"), 100000, true);
   test_todouble_helper(NS_LITERAL_STRING(""), 0, false);
   test_todouble_helper(NS_LITERAL_STRING("42foo"), 42, false);
   test_todouble_helper(NS_LITERAL_STRING("foo"), 0, false);
 }
 
+TEST(Strings, Split)
+{
+   nsCString one("one"),
+             two("one;two"),
+             three("one--three"),
+             empty(""),
+             delimStart("-two"),
+             delimEnd("one-");
+
+  size_t counter = 0;
+  for (const nsCSubstring& token : one.Split(',')) {
+    EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)1);
+
+  counter = 0;
+  for (const nsCSubstring& token : two.Split(';')) {
+    if (counter == 0) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    } else if (counter == 1) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("two")));
+    }
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)2);
+
+  counter = 0;
+  for (const nsCSubstring& token : three.Split('-')) {
+    if (counter == 0) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    } else if (counter == 1) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("")));
+    } else if (counter == 2) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("three")));
+    }
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)3);
+
+  counter = 0;
+  for (const nsCSubstring& token : empty.Split(',')) {
+    mozilla::Unused << token;
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)0);
+
+  counter = 0;
+  for (const nsCSubstring& token : delimStart.Split('-')) {
+    if (counter == 0) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("")));
+    } else if (counter == 1) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("two")));
+    }
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)2);
+
+  counter = 0;
+  for (const nsCSubstring& token : delimEnd.Split('-')) {
+    if (counter == 0) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("one")));
+    } else if (counter == 1) {
+      EXPECT_TRUE(token.Equals(NS_LITERAL_CSTRING("")));
+    }
+    counter++;
+  }
+  EXPECT_EQ(counter, (size_t)2);
+}
+
 } // namespace TestStrings