[llvm] [ADT] Add predicate based match support to StringSwitch (PR #188046)

via llvm-commits llvm-commits at lists.llvm.org
Mon Mar 23 07:43:31 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-adt

Author: Oliver Hunt (ojhunt)

<details>
<summary>Changes</summary>

This introduces `Predicate` and `IfNotPredicate` case selection to StringSwitch to allow use cases like

```
StringSwitch<...>(..)
  .Case("foo", FooTok)
  .Predicate(isAlpha, IdentifierTok)
...
```

This is mostly useful for improving conciseness and clarity when processing generated strings, diagnostics, and similar.

---
Full diff: https://github.com/llvm/llvm-project/pull/188046.diff


2 Files Affected:

- (modified) llvm/include/llvm/ADT/StringSwitch.h (+32) 
- (modified) llvm/unittests/ADT/StringSwitchTest.cpp (+69) 


``````````diff
diff --git a/llvm/include/llvm/ADT/StringSwitch.h b/llvm/include/llvm/ADT/StringSwitch.h
index b144d51364855..3072f3ddbb8b1 100644
--- a/llvm/include/llvm/ADT/StringSwitch.h
+++ b/llvm/include/llvm/ADT/StringSwitch.h
@@ -123,6 +123,38 @@ class StringSwitch {
     return *this;
   }
 
+  // A StringSwitch case that is selected if the specified predicate
+  // returns true for every character in a subject string.
+  StringSwitch &Predicate(function_ref<bool(char)> Pred, T Value) {
+    if (!Result && Str.find_if_not(Pred) == StringRef::npos)
+      Result = std::move(Value);
+    return *this;
+  }
+
+  // A StringSwitch case that is selected if the specified predicate
+  // returns true for the subject string.
+  StringSwitch &Predicate(function_ref<bool(StringRef)> Pred, T Value) {
+    if (!Result && Pred(Str))
+      Result = std::move(Value);
+    return *this;
+  }
+
+  // A StringSwitch case that is selected if the specified predicate
+  // returns false for any character in a subject string.
+  StringSwitch &IfNotPredicate(function_ref<bool(char)> Pred, T Value) {
+    if (!Result && Str.find_if(Pred) == StringRef::npos)
+      Result = std::move(Value);
+    return *this;
+  }
+
+  // A StringSwitch case that is selected if the specified predicate
+  // returns false for the subject string.
+  StringSwitch &IfNotPredicate(function_ref<bool(StringRef)> Pred, T Value) {
+    if (!Result && !Pred(Str))
+      Result = std::move(Value);
+    return *this;
+  }
+
   [[nodiscard]] R Default(T Value) {
     if (Result)
       return std::move(*Result);
diff --git a/llvm/unittests/ADT/StringSwitchTest.cpp b/llvm/unittests/ADT/StringSwitchTest.cpp
index 75d50f4dd1b5b..6975e004534dd 100644
--- a/llvm/unittests/ADT/StringSwitchTest.cpp
+++ b/llvm/unittests/ADT/StringSwitchTest.cpp
@@ -257,6 +257,75 @@ TEST(StringSwitchTest, StringSwitchMultipleMatches) {
   EXPECT_EQ(1, Translate("b"));
 }
 
+TEST(StringPredicateTest, PredicateChar) {
+  auto IsAlpha = [](char Ch) {
+    return (Ch >= 'a' && Ch <= 'z') || (Ch >= 'A' && Ch <= 'Z');
+  };
+  auto PredicateMatch = [&](StringRef S) {
+    return llvm::StringSwitch<int>(S)
+        .Case("A", 0)
+        .Predicate(IsAlpha, 1)
+        .Case("B", 2)
+        .Case("C D", 3)
+        .Default(4);
+  };
+  EXPECT_EQ(0, PredicateMatch("A"));
+  EXPECT_EQ(1, PredicateMatch("abcdef"));
+  EXPECT_EQ(1, PredicateMatch("B"));
+  EXPECT_EQ(3, PredicateMatch("C D"));
+  EXPECT_EQ(4, PredicateMatch("1234"));
+}
+
+TEST(StringPredicateTest, PredicateStr) {
+  auto MatchFn = [](StringRef Str) { return Str == "abc" || Str == "def"; };
+  auto PredicateMatch = [&](StringRef S) {
+    return llvm::StringSwitch<int>(S)
+        .Case("abc", 0)
+        .Predicate(MatchFn, 1)
+        .Case("def", 2)
+        .Default(3);
+  };
+  EXPECT_EQ(0, PredicateMatch("abc"));
+  EXPECT_EQ(1, PredicateMatch("def"));
+  EXPECT_EQ(3, PredicateMatch("ghi"));
+}
+
+TEST(StringPredicateTest, IfNotPredicateChar) {
+  auto IsAlpha = [](char Ch) {
+    return (Ch >= 'a' && Ch <= 'z') || (Ch >= 'A' && Ch <= 'Z');
+  };
+  auto PredicateMatch = [&](StringRef Str) {
+    return llvm::StringSwitch<int>(Str)
+        .Case("AA", 0)
+        .Case("11", 1)
+        .IfNotPredicate(IsAlpha, 2)
+        .Case("BB", 3)
+        .Case("22", 4)
+        .Default(5);
+  };
+  EXPECT_EQ(0, PredicateMatch("AA"));
+  EXPECT_EQ(1, PredicateMatch("11"));
+  EXPECT_EQ(2, PredicateMatch("22"));
+  EXPECT_EQ(2, PredicateMatch("22"));
+  EXPECT_EQ(3, PredicateMatch("BB"));
+  EXPECT_EQ(5, PredicateMatch("ABC123"));
+  EXPECT_EQ(5, PredicateMatch("123ABC"));
+}
+
+TEST(StringPredicateTest, IfNotPredicateStr) {
+  auto MatchFn = [](StringRef Str) { return Str == "abc" || Str == "def"; };
+  auto PredicateMatch = [&](StringRef S) {
+    return llvm::StringSwitch<int>(S)
+        .Case("abc", 0)
+        .IfNotPredicate(MatchFn, 1)
+        .Case("def", 2)
+        .Default(3);
+  };
+  EXPECT_EQ(0, PredicateMatch("abc"));
+  EXPECT_EQ(1, PredicateMatch("ghi"));
+  EXPECT_EQ(2, PredicateMatch("def"));
+}
+
 TEST(StringSwitchTest, DefaultUnreachable) {
   auto Translate = [](StringRef S) {
     return llvm::StringSwitch<int>(S)

``````````

</details>


https://github.com/llvm/llvm-project/pull/188046


More information about the llvm-commits mailing list