1 //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/ 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 //===----------------------------------------------------------------------===/ 8 // 9 // This file implements the StringSwitch template, which mimics a switch() 10 // statement whose cases are string literals. 11 // 12 //===----------------------------------------------------------------------===/ 13 #ifndef LLVM_ADT_STRINGSWITCH_H 14 #define LLVM_ADT_STRINGSWITCH_H 15 16 #include "llvm/ADT/StringRef.h" 17 #include "llvm/Support/Compiler.h" 18 #include <cassert> 19 #include <cstring> 20 21 namespace llvm { 22 23 /// A switch()-like statement whose cases are string literals. 24 /// 25 /// The StringSwitch class is a simple form of a switch() statement that 26 /// determines whether the given string matches one of the given string 27 /// literals. The template type parameter \p T is the type of the value that 28 /// will be returned from the string-switch expression. For example, 29 /// the following code switches on the name of a color in \c argv[i]: 30 /// 31 /// \code 32 /// Color color = StringSwitch<Color>(argv[i]) 33 /// .Case("red", Red) 34 /// .Case("orange", Orange) 35 /// .Case("yellow", Yellow) 36 /// .Case("green", Green) 37 /// .Case("blue", Blue) 38 /// .Case("indigo", Indigo) 39 /// .Cases("violet", "purple", Violet) 40 /// .Default(UnknownColor); 41 /// \endcode 42 template<typename T, typename R = T> 43 class StringSwitch { 44 /// The string we are matching. 45 const StringRef Str; 46 47 /// The pointer to the result of this switch statement, once known, 48 /// null before that. 49 Optional<T> Result; 50 51 public: 52 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch(StringRef S)53 explicit StringSwitch(StringRef S) 54 : Str(S), Result() { } 55 56 // StringSwitch is not copyable. 57 StringSwitch(const StringSwitch &) = delete; 58 59 // StringSwitch is not assignable due to 'Str' being 'const'. 60 void operator=(const StringSwitch &) = delete; 61 void operator=(StringSwitch &&other) = delete; 62 StringSwitch(StringSwitch && other)63 StringSwitch(StringSwitch &&other) 64 : Str(other.Str), Result(std::move(other.Result)) { } 65 66 ~StringSwitch() = default; 67 68 // Case-sensitive case matchers 69 LLVM_ATTRIBUTE_ALWAYS_INLINE Case(StringLiteral S,T Value)70 StringSwitch &Case(StringLiteral S, T Value) { 71 if (!Result && Str == S) { 72 Result = std::move(Value); 73 } 74 return *this; 75 } 76 77 LLVM_ATTRIBUTE_ALWAYS_INLINE EndsWith(StringLiteral S,T Value)78 StringSwitch& EndsWith(StringLiteral S, T Value) { 79 if (!Result && Str.endswith(S)) { 80 Result = std::move(Value); 81 } 82 return *this; 83 } 84 85 LLVM_ATTRIBUTE_ALWAYS_INLINE StartsWith(StringLiteral S,T Value)86 StringSwitch& StartsWith(StringLiteral S, T Value) { 87 if (!Result && Str.startswith(S)) { 88 Result = std::move(Value); 89 } 90 return *this; 91 } 92 93 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,T Value)94 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) { 95 return Case(S0, Value).Case(S1, Value); 96 } 97 98 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,T Value)99 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 100 T Value) { 101 return Case(S0, Value).Cases(S1, S2, Value); 102 } 103 104 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,T Value)105 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 106 StringLiteral S3, T Value) { 107 return Case(S0, Value).Cases(S1, S2, S3, Value); 108 } 109 110 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,T Value)111 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 112 StringLiteral S3, StringLiteral S4, T Value) { 113 return Case(S0, Value).Cases(S1, S2, S3, S4, Value); 114 } 115 116 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,StringLiteral S5,T Value)117 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 118 StringLiteral S3, StringLiteral S4, StringLiteral S5, 119 T Value) { 120 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value); 121 } 122 123 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,StringLiteral S5,StringLiteral S6,T Value)124 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 125 StringLiteral S3, StringLiteral S4, StringLiteral S5, 126 StringLiteral S6, T Value) { 127 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value); 128 } 129 130 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,StringLiteral S5,StringLiteral S6,StringLiteral S7,T Value)131 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 132 StringLiteral S3, StringLiteral S4, StringLiteral S5, 133 StringLiteral S6, StringLiteral S7, T Value) { 134 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value); 135 } 136 137 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,StringLiteral S5,StringLiteral S6,StringLiteral S7,StringLiteral S8,T Value)138 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 139 StringLiteral S3, StringLiteral S4, StringLiteral S5, 140 StringLiteral S6, StringLiteral S7, StringLiteral S8, 141 T Value) { 142 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value); 143 } 144 145 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,StringLiteral S5,StringLiteral S6,StringLiteral S7,StringLiteral S8,StringLiteral S9,T Value)146 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 147 StringLiteral S3, StringLiteral S4, StringLiteral S5, 148 StringLiteral S6, StringLiteral S7, StringLiteral S8, 149 StringLiteral S9, T Value) { 150 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value); 151 } 152 153 // Case-insensitive case matchers. 154 LLVM_ATTRIBUTE_ALWAYS_INLINE CaseLower(StringLiteral S,T Value)155 StringSwitch &CaseLower(StringLiteral S, T Value) { 156 if (!Result && Str.equals_lower(S)) 157 Result = std::move(Value); 158 159 return *this; 160 } 161 162 LLVM_ATTRIBUTE_ALWAYS_INLINE EndsWithLower(StringLiteral S,T Value)163 StringSwitch &EndsWithLower(StringLiteral S, T Value) { 164 if (!Result && Str.endswith_lower(S)) 165 Result = Value; 166 167 return *this; 168 } 169 170 LLVM_ATTRIBUTE_ALWAYS_INLINE StartsWithLower(StringLiteral S,T Value)171 StringSwitch &StartsWithLower(StringLiteral S, T Value) { 172 if (!Result && Str.startswith_lower(S)) 173 Result = std::move(Value); 174 175 return *this; 176 } 177 178 LLVM_ATTRIBUTE_ALWAYS_INLINE CasesLower(StringLiteral S0,StringLiteral S1,T Value)179 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) { 180 return CaseLower(S0, Value).CaseLower(S1, Value); 181 } 182 183 LLVM_ATTRIBUTE_ALWAYS_INLINE CasesLower(StringLiteral S0,StringLiteral S1,StringLiteral S2,T Value)184 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, 185 T Value) { 186 return CaseLower(S0, Value).CasesLower(S1, S2, Value); 187 } 188 189 LLVM_ATTRIBUTE_ALWAYS_INLINE CasesLower(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,T Value)190 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, 191 StringLiteral S3, T Value) { 192 return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value); 193 } 194 195 LLVM_ATTRIBUTE_ALWAYS_INLINE CasesLower(StringLiteral S0,StringLiteral S1,StringLiteral S2,StringLiteral S3,StringLiteral S4,T Value)196 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, 197 StringLiteral S3, StringLiteral S4, T Value) { 198 return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value); 199 } 200 201 LLVM_NODISCARD 202 LLVM_ATTRIBUTE_ALWAYS_INLINE Default(T Value)203 R Default(T Value) { 204 if (Result) 205 return std::move(*Result); 206 return Value; 207 } 208 209 LLVM_NODISCARD 210 LLVM_ATTRIBUTE_ALWAYS_INLINE R()211 operator R() { 212 assert(Result && "Fell off the end of a string-switch"); 213 return std::move(*Result); 214 } 215 }; 216 217 } // end namespace llvm 218 219 #endif // LLVM_ADT_STRINGSWITCH_H 220