Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -356,10 +356,7 @@ // configuration of the transport before attaching/launching the process. m_qSupported_response = response.GetStringRef().str(); - llvm::SmallVector server_features; - response.GetStringRef().split(server_features, ';'); - - for (llvm::StringRef x : server_features) { + for (llvm::StringRef x : llvm::split(response.GetStringRef(), ';')) { if (x == "qXfer:auxv:read+") m_supports_qXfer_auxv_read = eLazyBoolYes; else if (x == "qXfer:libraries-svr4:read+") Index: lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -3656,10 +3656,7 @@ StringRef packet_str{packet.GetStringRef()}; assert(packet_str.startswith("qSaveCore")); if (packet_str.consume_front("qSaveCore;")) { - llvm::SmallVector fields; - packet_str.split(fields, ';'); - - for (auto x : fields) { + for (auto x : llvm::split(packet_str, ';')) { if (x.consume_front("path-hint:")) StringExtractor(x).GetHexByteString(path_hint); else Index: lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp =================================================================== --- lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -5121,9 +5121,7 @@ std::string path; // process the response - llvm::SmallVector reply_data; - response.GetStringRef().split(reply_data, ';'); - for (auto x : reply_data) { + for (auto x : llvm::split(response.GetStringRef(), ';')) { if (x.consume_front("core-path:")) StringExtractor(x).GetHexByteString(path); } Index: llvm/include/llvm/ADT/StringExtras.h =================================================================== --- llvm/include/llvm/ADT/StringExtras.h +++ llvm/include/llvm/ADT/StringExtras.h @@ -501,6 +501,62 @@ } }; +/// A forward iterator over partitions of string over a separator. +class SplittingIterator + : public iterator_facade_base { + StringRef Current; + StringRef Next; + StringRef Separator; + +public: + SplittingIterator(StringRef Str, StringRef Separator) + : Next(Str), Separator(Separator) { + ++*this; + } + + bool operator==(const SplittingIterator &R) const { + return Current == R.Current && Next == R.Next && Separator == R.Separator; + } + + const StringRef &operator*() const { return Current; } + + StringRef &operator*() { return Current; } + + SplittingIterator &operator++() { + std::pair res = Next.split(Separator); + Current = res.first; + Next = res.second; + return *this; + } +}; + +/// Split the specified string over a separator and return a range-compatible +/// iterable over its partitions. Used to permit conveniently iterating +/// over separated strings like so: +/// +/// \code +/// for (StringRef x : split("foo,bar,baz", ',')) +/// ...; +/// \end +/// +/// Note that the passed string must remain valid throuhgout lifetime +/// of the iterators. +class split { + StringRef Str; + std::string SeparatorStr; + +public: + split(StringRef NewStr, StringRef Separator) + : Str(NewStr), SeparatorStr(Separator) {} + split(StringRef NewStr, char Separator) + : Str(NewStr), SeparatorStr(1, Separator) {} + + SplittingIterator begin() { return SplittingIterator(Str, SeparatorStr); } + + SplittingIterator end() { return SplittingIterator("", SeparatorStr); } +}; + } // end namespace llvm #endif // LLVM_ADT_STRINGEXTRAS_H Index: llvm/lib/IR/DataLayout.cpp =================================================================== --- llvm/lib/IR/DataLayout.cpp +++ llvm/lib/IR/DataLayout.cpp @@ -216,8 +216,8 @@ } /// Checked version of split, to ensure mandatory subparts. -static Error split(StringRef Str, char Separator, - std::pair &Split) { +static Error dataLayoutSplit(StringRef Str, char Separator, + std::pair &Split) { assert(!Str.empty() && "parse error, string can't be empty here"); Split = Str.split(Separator); if (Split.second.empty() && Split.first != Str) @@ -260,12 +260,12 @@ while (!Desc.empty()) { // Split at '-'. std::pair Split; - if (Error Err = split(Desc, '-', Split)) + if (Error Err = dataLayoutSplit(Desc, '-', Split)) return Err; Desc = Split.second; // Split at ':'. - if (Error Err = split(Split.first, ':', Split)) + if (Error Err = dataLayoutSplit(Split.first, ':', Split)) return Err; // Aliases used below. @@ -274,7 +274,7 @@ if (Tok == "ni") { do { - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; Rest = Split.second; unsigned AS; @@ -315,7 +315,7 @@ if (Rest.empty()) return reportError( "Missing size specification for pointer in datalayout string"); - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; unsigned PointerMemSize; if (Error Err = getIntInBytes(Tok, PointerMemSize)) @@ -327,7 +327,7 @@ if (Rest.empty()) return reportError( "Missing alignment specification for pointer in datalayout string"); - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; unsigned PointerABIAlign; if (Error Err = getIntInBytes(Tok, PointerABIAlign)) @@ -342,7 +342,7 @@ // Preferred alignment. unsigned PointerPrefAlign = PointerABIAlign; if (!Rest.empty()) { - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; if (Error Err = getIntInBytes(Tok, PointerPrefAlign)) return Err; @@ -352,7 +352,7 @@ // Now read the index. It is the second optional parameter here. if (!Rest.empty()) { - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; if (Error Err = getIntInBytes(Tok, IndexSize)) return Err; @@ -393,7 +393,7 @@ if (Rest.empty()) return reportError( "Missing alignment specification in datalayout string"); - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; unsigned ABIAlign; if (Error Err = getIntInBytes(Tok, ABIAlign)) @@ -410,7 +410,7 @@ // Preferred alignment. unsigned PrefAlign = ABIAlign; if (!Rest.empty()) { - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; if (Error Err = getIntInBytes(Tok, PrefAlign)) return Err; @@ -439,7 +439,7 @@ LegalIntWidths.push_back(Width); if (Rest.empty()) break; - if (Error Err = split(Rest, ':', Split)) + if (Error Err = dataLayoutSplit(Rest, ':', Split)) return Err; } break; Index: llvm/unittests/ADT/StringExtrasTest.cpp =================================================================== --- llvm/unittests/ADT/StringExtrasTest.cpp +++ llvm/unittests/ADT/StringExtrasTest.cpp @@ -274,3 +274,35 @@ EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 10), "-1"); EXPECT_EQ(toString(APSInt(APInt(8, 255), isUnsigned), 16), "-1"); } + +TEST(StringExtrasTest, splitStringRef) { + auto spl = split("foo<=>bar<=><=>baz", "<=>"); + auto it = spl.begin(); + auto end = spl.end(); + + ASSERT_NE(it, end); + EXPECT_EQ(*it, StringRef("foo")); + ASSERT_NE(++it, end); + EXPECT_EQ(*it, StringRef("bar")); + ASSERT_NE(++it, end); + EXPECT_EQ(*it, StringRef("")); + ASSERT_NE(++it, end); + EXPECT_EQ(*it, StringRef("baz")); + ASSERT_EQ(++it, end); +} + +TEST(StringExtrasTest, splitChar) { + auto spl = split("foo,bar,,baz", ','); + auto it = spl.begin(); + auto end = spl.end(); + + ASSERT_NE(it, end); + EXPECT_EQ(*it, StringRef("foo")); + ASSERT_NE(++it, end); + EXPECT_EQ(*it, StringRef("bar")); + ASSERT_NE(++it, end); + EXPECT_EQ(*it, StringRef("")); + ASSERT_NE(++it, end); + EXPECT_EQ(*it, StringRef("baz")); + ASSERT_EQ(++it, end); +}