[llvm] r282346 - Add some predicated searching functions to StringRef.

Zachary Turner via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 24 20:27:30 PDT 2016


Author: zturner
Date: Sat Sep 24 22:27:29 2016
New Revision: 282346

URL: http://llvm.org/viewvc/llvm-project?rev=282346&view=rev
Log:
Add some predicated searching functions to StringRef.

This adds 4 new functions to StringRef, which can be used to
take or drop characters while a certain condition is met, or
until a certain condition is met.  They are:

take_while - Return characters until a condition is not met.
take_until - Return characters until a condition is met.
drop_while - Remove characters until a condition is not met.
drop_until - Remove characters until a condition is met.

Internally, all of these functions delegate to two additional
helper functions which can be used to search for the position
of a character meeting or not meeting a condition, which are:

find_if - Find the first character matching a predicate.
find_if_not - Find the first character not matching a predicate.

Differential Revision: https://reviews.llvm.org/D24842

Modified:
    llvm/trunk/include/llvm/ADT/StringRef.h
    llvm/trunk/unittests/ADT/StringRefTest.cpp

Modified: llvm/trunk/include/llvm/ADT/StringRef.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ADT/StringRef.h?rev=282346&r1=282345&r2=282346&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ADT/StringRef.h (original)
+++ llvm/trunk/include/llvm/ADT/StringRef.h Sat Sep 24 22:27:29 2016
@@ -10,6 +10,7 @@
 #ifndef LLVM_ADT_STRINGREF_H
 #define LLVM_ADT_STRINGREF_H
 
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/iterator_range.h"
 #include "llvm/Support/Compiler.h"
 #include <algorithm>
@@ -276,6 +277,32 @@ namespace llvm {
       return npos;
     }
 
+    /// Search for the first character satisfying the predicate \p F
+    ///
+    /// \returns The index of the first character satisfying \p F starting from
+    /// \p From, or npos if not found.
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    LLVM_ATTRIBUTE_UNUSED_RESULT
+    size_t find_if(function_ref<bool(char)> F, size_t From = 0) const {
+      StringRef S = drop_front(From);
+      while (!S.empty()) {
+        if (F(S.front()))
+          return size() - S.size();
+        S = S.drop_front();
+      }
+      return npos;
+    }
+
+    /// Search for the first character not satisfying the predicate \p F
+    ///
+    /// \returns The index of the first character not satisfying \p F starting
+    /// from \p From, or npos if not found.
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    LLVM_ATTRIBUTE_UNUSED_RESULT
+    size_t find_if_not(function_ref<bool(char)> F, size_t From = 0) const {
+      return find_if([F](char c) { return !F(c); }, From);
+    }
+
     /// Search for the first string \p Str in the string.
     ///
     /// \returns The index of the first occurrence of \p Str, or npos if not
@@ -352,6 +379,9 @@ namespace llvm {
     LLVM_ATTRIBUTE_ALWAYS_INLINE
     bool contains(StringRef Other) const { return find(Other) != npos; }
 
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    bool contains(char C) const { return find_first_of(C) != npos; }
+
     /// @}
     /// @name Helpful Algorithms
     /// @{
@@ -496,6 +526,22 @@ namespace llvm {
       return drop_front(size() - N);
     }
 
+    /// Return the longest prefix of 'this' such that every character
+    /// in the prefix satisfies the given predicate.
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    LLVM_ATTRIBUTE_UNUSED_RESULT
+    StringRef take_while(function_ref<bool(char)> F) const {
+      return substr(0, find_if_not(F));
+    }
+
+    /// Return the longest prefix of 'this' such that no character in
+    /// the prefix satisfies the given predicate.
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    LLVM_ATTRIBUTE_UNUSED_RESULT
+    StringRef take_until(function_ref<bool(char)> F) const {
+      return substr(0, find_if(F));
+    }
+
     /// Return a StringRef equal to 'this' but with the first \p N elements
     /// dropped.
     LLVM_ATTRIBUTE_ALWAYS_INLINE
@@ -514,6 +560,22 @@ namespace llvm {
       return substr(0, size()-N);
     }
 
+    /// Return a StringRef equal to 'this', but with all characters satisfying
+    /// the given predicate dropped from the beginning of the string.
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    LLVM_ATTRIBUTE_UNUSED_RESULT
+    StringRef drop_while(function_ref<bool(char)> F) const {
+      return substr(find_if_not(F));
+    }
+
+    /// Return a StringRef equal to 'this', but with all characters not
+    /// satisfying the given predicate dropped from the beginning of the string.
+    LLVM_ATTRIBUTE_ALWAYS_INLINE
+    LLVM_ATTRIBUTE_UNUSED_RESULT
+    StringRef drop_until(function_ref<bool(char)> F) const {
+      return substr(find_if(F));
+    }
+
     /// Returns true if this StringRef has the given prefix and removes that
     /// prefix.
     LLVM_ATTRIBUTE_ALWAYS_INLINE

Modified: llvm/trunk/unittests/ADT/StringRefTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/ADT/StringRefTest.cpp?rev=282346&r1=282345&r2=282346&view=diff
==============================================================================
--- llvm/trunk/unittests/ADT/StringRefTest.cpp (original)
+++ llvm/trunk/unittests/ADT/StringRefTest.cpp Sat Sep 24 22:27:29 2016
@@ -864,4 +864,60 @@ TEST(StringRefTest, Take) {
   EXPECT_TRUE(Taken.empty());
 }
 
+TEST(StringRefTest, FindIf) {
+  StringRef Punct("Test.String");
+  StringRef NoPunct("ABCDEFG");
+  StringRef Empty;
+
+  auto IsPunct = [](char c) { return ::ispunct(c); };
+  auto IsAlpha = [](char c) { return ::isalpha(c); };
+  EXPECT_EQ(4, Punct.find_if(IsPunct));
+  EXPECT_EQ(StringRef::npos, NoPunct.find_if(IsPunct));
+  EXPECT_EQ(StringRef::npos, Empty.find_if(IsPunct));
+
+  EXPECT_EQ(4, Punct.find_if_not(IsAlpha));
+  EXPECT_EQ(StringRef::npos, NoPunct.find_if_not(IsAlpha));
+  EXPECT_EQ(StringRef::npos, Empty.find_if_not(IsAlpha));
+}
+
+TEST(StringRefTest, TakeWhileUntil) {
+  StringRef Test("String With 1 Number");
+
+  StringRef Taken = Test.take_while([](char c) { return ::isdigit(c); });
+  EXPECT_EQ("", Taken);
+
+  Taken = Test.take_until([](char c) { return ::isdigit(c); });
+  EXPECT_EQ("String With ", Taken);
+
+  Taken = Test.take_while([](char c) { return true; });
+  EXPECT_EQ(Test, Taken);
+
+  Taken = Test.take_until([](char c) { return true; });
+  EXPECT_EQ("", Taken);
+
+  Test = "";
+  Taken = Test.take_while([](char c) { return true; });
+  EXPECT_EQ("", Taken);
+}
+
+TEST(StringRefTest, DropWhileUntil) {
+  StringRef Test("String With 1 Number");
+
+  StringRef Taken = Test.drop_while([](char c) { return ::isdigit(c); });
+  EXPECT_EQ(Test, Taken);
+
+  Taken = Test.drop_until([](char c) { return ::isdigit(c); });
+  EXPECT_EQ("1 Number", Taken);
+
+  Taken = Test.drop_while([](char c) { return true; });
+  EXPECT_EQ("", Taken);
+
+  Taken = Test.drop_until([](char c) { return true; });
+  EXPECT_EQ(Test, Taken);
+
+  StringRef EmptyString = "";
+  Taken = EmptyString.drop_while([](char c) { return true; });
+  EXPECT_EQ("", Taken);
+}
+
 } // end anonymous namespace




More information about the llvm-commits mailing list