Index: include/llvm/ADT/StringRef.h =================================================================== --- include/llvm/ADT/StringRef.h +++ include/llvm/ADT/StringRef.h @@ -277,6 +277,8 @@ return npos; } + size_t find_lower(char C, size_t From = 0) const; + /// Search for the first character satisfying the predicate \p F /// /// \returns The index of the first character satisfying \p F starting from @@ -309,6 +311,8 @@ /// found. size_t find(StringRef Str, size_t From = 0) const; + size_t find_lower(StringRef Str, size_t From = 0) const; + /// Search for the last character \p C in the string. /// /// \returns The index of the last occurrence of \p C, or npos if not @@ -384,6 +388,18 @@ LLVM_ATTRIBUTE_ALWAYS_INLINE bool contains(char C) const { return find_first_of(C) != npos; } + /// Return true if the given string is a substring of *this, and false + /// otherwise. + LLVM_ATTRIBUTE_ALWAYS_INLINE + bool contains_lower(StringRef Other) const { + return find_lower(Other) != npos; + } + + /// Return true if the given character is contained in *this, and false + /// otherwise. + LLVM_ATTRIBUTE_ALWAYS_INLINE + bool contains_lower(char C) const { return find_lower(C) != npos; } + /// @} /// @name Helpful Algorithms /// @{ Index: lib/Support/StringRef.cpp =================================================================== --- lib/Support/StringRef.cpp +++ lib/Support/StringRef.cpp @@ -69,6 +69,11 @@ ascii_strncasecmp(end() - Suffix.Length, Suffix.Data, Suffix.Length) == 0; } +size_t StringRef::find_lower(char C, size_t From) const { + char L = ascii_tolower(C); + return find_if([L](char D) { return ascii_tolower(D) == L; }, From); +} + /// compare_numeric - Compare strings, handle embedded numbers. int StringRef::compare_numeric(StringRef RHS) const { for (size_t I = 0, E = std::min(Length, RHS.Length); I != E; ++I) { @@ -182,6 +187,12 @@ return npos; } +size_t StringRef::find_lower(StringRef Str, size_t From) const { + std::string ThisLower = lower(); + std::string ThatLower = Str.lower(); + return ThisLower.find(ThatLower, From); +} + /// rfind - Search for the last string \arg Str in the string. /// /// \return - The index of the last occurrence of \arg Str, or npos if not Index: unittests/ADT/StringRefTest.cpp =================================================================== --- unittests/ADT/StringRefTest.cpp +++ unittests/ADT/StringRefTest.cpp @@ -375,20 +375,49 @@ TEST(StringRefTest, Find) { StringRef Str("hello"); - EXPECT_EQ(2U, Str.find('l')); - EXPECT_EQ(StringRef::npos, Str.find('z')); - EXPECT_EQ(StringRef::npos, Str.find("helloworld")); - EXPECT_EQ(0U, Str.find("hello")); - EXPECT_EQ(1U, Str.find("ello")); - EXPECT_EQ(StringRef::npos, Str.find("zz")); - EXPECT_EQ(2U, Str.find("ll", 2)); - EXPECT_EQ(StringRef::npos, Str.find("ll", 3)); - EXPECT_EQ(0U, Str.find("")); StringRef LongStr("hellx xello hell ello world foo bar hello"); - EXPECT_EQ(36U, LongStr.find("hello")); - EXPECT_EQ(28U, LongStr.find("foo")); - EXPECT_EQ(12U, LongStr.find("hell", 2)); - EXPECT_EQ(0U, LongStr.find("")); + + struct { + StringRef Str; + std::size_t Pos; + char C; + std::size_t From; + } CharExpectations[] = { + {Str, 0U, 'h', 0U}, {Str, 1U, 'e', 0U}, {Str, 2U, 'l', 0U}, + {Str, 3U, 'l', 3U}, {Str, 4U, 'o', 0U}, {Str, StringRef::npos, 'z'}, + }; + + struct { + StringRef Str; + std::size_t Pos; + llvm::StringRef S; + std::size_t From; + } StrExpectations[] = {{Str, StringRef::npos, "helloword", 0}, + {Str, 0u, "hello", 0}, + {Str, 1u, "ello", 0}, + {Str, StringRef::npos, "zz", 0}, + {Str, 2U, "ll", 2U}, + {Str, StringRef::npos, "ll", 3U}, + {Str, 0u, "", 0U}, + {LongStr, 36U, "hello", 0U}, + {LongStr, 28U, "foo", 0U}, + {LongStr, 12U, "hell", 2U}, + {LongStr, 0U, "", 0U}}; + + for (auto &E : CharExpectations) { + EXPECT_EQ(E.Pos, E.Str.find(E.C, E.From)); + EXPECT_EQ(E.Pos, E.Str.find_lower(E.C, E.From)); + EXPECT_EQ(E.Pos, E.Str.find_lower(toupper(E.C), E.From)); + EXPECT_EQ(StringRef::npos, E.Str.find(toupper(E.C), E.From)); + } + + for (auto &E : StrExpectations) { + EXPECT_EQ(E.Pos, E.Str.find(E.S, E.From)); + EXPECT_EQ(E.Pos, E.Str.find_lower(E.S, E.From)); + EXPECT_EQ(E.Pos, E.Str.find_lower(E.S.upper(), E.From)); + if (!E.S.empty()) + EXPECT_EQ(StringRef::npos, E.Str.find(E.S.upper(), E.From)); + } EXPECT_EQ(3U, Str.rfind('l')); EXPECT_EQ(StringRef::npos, Str.rfind('z'));