Bug 1330326 - Add Split() function on String classes. r=froydnj
MozReview-Commit-ID: 3xug2xMR60j
--- 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