/// Split into substrings around the occurrences of a separator string.
///
/// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
- /// \p MaxSplit splits are done and consequently <= \p MaxSplit
+ /// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
/// elements are added to A.
/// If \p KeepEmpty is false, empty strings are not added to \p A. They
/// still count when considering \p MaxSplit
/// Split into substrings around the occurrences of a separator character.
///
/// Each substring is stored in \p A. If \p MaxSplit is >= 0, at most
- /// \p MaxSplit splits are done and consequently <= \p MaxSplit
+ /// \p MaxSplit splits are done and consequently <= \p MaxSplit + 1
/// elements are added to A.
/// If \p KeepEmpty is false, empty strings are not added to \p A. They
/// still count when considering \p MaxSplit
}
void StringRef::split(SmallVectorImpl<StringRef> &A,
- StringRef Separators, int MaxSplit,
+ StringRef Separator, int MaxSplit,
bool KeepEmpty) const {
- StringRef rest = *this;
-
- // rest.data() is used to distinguish cases like "a," that splits into
- // "a" + "" and "a" that splits into "a" + 0.
- for (int splits = 0;
- rest.data() != nullptr && (MaxSplit < 0 || splits < MaxSplit);
- ++splits) {
- std::pair<StringRef, StringRef> p = rest.split(Separators);
-
- if (KeepEmpty || p.first.size() != 0)
- A.push_back(p.first);
- rest = p.second;
+ StringRef S = *this;
+
+ // Count down from MaxSplit. When MaxSplit is -1, this will just split
+ // "forever". This doesn't support splitting more than 2^31 times
+ // intentionally; if we ever want that we can make MaxSplit a 64-bit integer
+ // but that seems unlikely to be useful.
+ while (MaxSplit-- != 0) {
+ size_t Idx = S.find(Separator);
+ if (Idx == npos)
+ break;
+
+ // Push this split.
+ if (KeepEmpty || Idx > 0)
+ A.push_back(S.slice(0, Idx));
+
+ // Jump forward.
+ S = S.slice(Idx + Separator.size(), npos);
}
- // If we have a tail left, add it.
- if (rest.data() != nullptr && (rest.size() != 0 || KeepEmpty))
- A.push_back(rest);
+
+ // Push the tail.
+ if (KeepEmpty || !S.empty())
+ A.push_back(S);
}
void StringRef::split(SmallVectorImpl<StringRef> &A, char Separator,
int MaxSplit, bool KeepEmpty) const {
- StringRef rest = *this;
-
- // rest.data() is used to distinguish cases like "a," that splits into
- // "a" + "" and "a" that splits into "a" + 0.
- for (int splits = 0;
- rest.data() != nullptr && (MaxSplit < 0 || splits < MaxSplit);
- ++splits) {
- std::pair<StringRef, StringRef> p = rest.split(Separator);
-
- if (KeepEmpty || p.first.size() != 0)
- A.push_back(p.first);
- rest = p.second;
+ StringRef S = *this;
+
+ // Count down from MaxSplit. When MaxSplit is -1, this will just split
+ // "forever". This doesn't support splitting more than 2^31 times
+ // intentionally; if we ever want that we can make MaxSplit a 64-bit integer
+ // but that seems unlikely to be useful.
+ while (MaxSplit-- != 0) {
+ size_t Idx = S.find(Separator);
+ if (Idx == npos)
+ break;
+
+ // Push this split.
+ if (KeepEmpty || Idx > 0)
+ A.push_back(S.slice(0, Idx));
+
+ // Jump forward.
+ S = S.slice(Idx + 1, npos);
}
- // If we have a tail left, add it.
- if (rest.data() != nullptr && (rest.size() != 0 || KeepEmpty))
- A.push_back(rest);
+
+ // Push the tail.
+ if (KeepEmpty || !S.empty())
+ A.push_back(S);
}
//===----------------------------------------------------------------------===//
expected.push_back("a"); expected.push_back("b"); expected.push_back("c");
StringRef("a,,b,c").split(parts, ',', 3, false);
EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ expected.push_back("");
+ StringRef().split(parts, ",", 0, true);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ expected.push_back(StringRef());
+ StringRef("").split(parts, ",", 0, true);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ StringRef("").split(parts, ",", 0, false);
+ EXPECT_TRUE(parts == expected);
+ StringRef().split(parts, ",", 0, false);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ expected.push_back("a");
+ expected.push_back("");
+ expected.push_back("b");
+ expected.push_back("c,d");
+ StringRef("a,,b,c,d").split(parts, ",", 3, true);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ expected.push_back("");
+ StringRef().split(parts, ',', 0, true);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ expected.push_back(StringRef());
+ StringRef("").split(parts, ',', 0, true);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ StringRef("").split(parts, ',', 0, false);
+ EXPECT_TRUE(parts == expected);
+ StringRef().split(parts, ',', 0, false);
+ EXPECT_TRUE(parts == expected);
+
+ expected.clear(); parts.clear();
+ expected.push_back("a");
+ expected.push_back("");
+ expected.push_back("b");
+ expected.push_back("c,d");
+ StringRef("a,,b,c,d").split(parts, ',', 3, true);
+ EXPECT_TRUE(parts == expected);
}
TEST(StringRefTest, Trim) {