diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp @@ -355,10 +355,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+") @@ -1659,10 +1656,8 @@ error_extractor.GetHexByteString(error_string); error.SetErrorString(error_string.c_str()); } else if (name.equals("dirty-pages")) { - llvm::SmallVector split_value; std::vector dirty_page_list; - value.split(split_value, ','); - for (llvm::StringRef x : split_value) { + for (llvm::StringRef x : llvm::Split(value, ',')) { addr_t page; x.consume_front("0x"); if (llvm::to_integer(x, page, 16)) diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/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 diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp --- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp @@ -383,9 +383,7 @@ const llvm::StringRef &comma_separated_register_numbers, std::vector ®nums, int base) { regnums.clear(); - llvm::SmallVector split_string; - comma_separated_register_numbers.split(split_string, ','); - for (llvm::StringRef x : split_string) { + for (llvm::StringRef x : llvm::Split(comma_separated_register_numbers, ',')) { uint32_t reg; if (llvm::to_integer(x, reg, base)) regnums.push_back(reg); @@ -1457,9 +1455,7 @@ size_t ProcessGDBRemote::UpdateThreadPCsFromStopReplyThreadsValue( llvm::StringRef value) { m_thread_pcs.clear(); - llvm::SmallVector split_value; - value.split(split_value, ','); - for (llvm::StringRef x : split_value) { + for (llvm::StringRef x : llvm::Split(value, ',')) { lldb::addr_t pc; if (llvm::to_integer(x, pc, 16)) m_thread_pcs.push_back(pc); @@ -5111,9 +5107,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); } diff --git a/llvm/include/llvm/ADT/StringExtras.h b/llvm/include/llvm/ADT/StringExtras.h --- a/llvm/include/llvm/ADT/StringExtras.h +++ b/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 : llvm::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 diff --git a/llvm/unittests/ADT/StringExtrasTest.cpp b/llvm/unittests/ADT/StringExtrasTest.cpp --- a/llvm/unittests/ADT/StringExtrasTest.cpp +++ b/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); +}