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 /// \brief 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 /// \brief The string we are matching. 45 StringRef Str; 46 47 /// \brief The pointer to the result of this switch statement, once known, 48 /// null before that. 49 const T *Result; 50 51 public: 52 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch(StringRef S)53 explicit StringSwitch(StringRef S) 54 : Str(S), Result(nullptr) { } 55 56 // StringSwitch is not copyable. 57 StringSwitch(const StringSwitch &) = delete; 58 void operator=(const StringSwitch &) = delete; 59 StringSwitch(StringSwitch && other)60 StringSwitch(StringSwitch &&other) { 61 *this = std::move(other); 62 } 63 StringSwitch &operator=(StringSwitch &&other) { 64 Str = other.Str; 65 Result = other.Result; 66 return *this; 67 } 68 69 ~StringSwitch() = default; 70 71 // Case-sensitive case matchers 72 template<unsigned N> 73 LLVM_ATTRIBUTE_ALWAYS_INLINE Case(const char (& S)[N],const T & Value)74 StringSwitch& Case(const char (&S)[N], const T& Value) { 75 assert(N); 76 if (!Result && N-1 == Str.size() && 77 (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) { 78 Result = &Value; 79 } 80 return *this; 81 } 82 83 template<unsigned N> 84 LLVM_ATTRIBUTE_ALWAYS_INLINE EndsWith(const char (& S)[N],const T & Value)85 StringSwitch& EndsWith(const char (&S)[N], const T &Value) { 86 assert(N); 87 if (!Result && Str.size() >= N-1 && 88 (N == 1 || std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0)) { 89 Result = &Value; 90 } 91 return *this; 92 } 93 94 template<unsigned N> 95 LLVM_ATTRIBUTE_ALWAYS_INLINE StartsWith(const char (& S)[N],const T & Value)96 StringSwitch& StartsWith(const char (&S)[N], const T &Value) { 97 assert(N); 98 if (!Result && Str.size() >= N-1 && 99 (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) { 100 Result = &Value; 101 } 102 return *this; 103 } 104 105 template<unsigned N0, unsigned N1> 106 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const T & Value)107 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 108 const T& Value) { 109 return Case(S0, Value).Case(S1, Value); 110 } 111 112 template<unsigned N0, unsigned N1, unsigned N2> 113 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const T & Value)114 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 115 const char (&S2)[N2], const T& Value) { 116 return Case(S0, Value).Cases(S1, S2, Value); 117 } 118 119 template<unsigned N0, unsigned N1, unsigned N2, unsigned N3> 120 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const T & Value)121 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 122 const char (&S2)[N2], const char (&S3)[N3], 123 const T& Value) { 124 return Case(S0, Value).Cases(S1, S2, S3, Value); 125 } 126 127 template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> 128 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const T & Value)129 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 130 const char (&S2)[N2], const char (&S3)[N3], 131 const char (&S4)[N4], const T& Value) { 132 return Case(S0, Value).Cases(S1, S2, S3, S4, Value); 133 } 134 135 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, 136 unsigned N5> 137 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const char (& S5)[N5],const T & Value)138 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 139 const char (&S2)[N2], const char (&S3)[N3], 140 const char (&S4)[N4], const char (&S5)[N5], 141 const T &Value) { 142 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value); 143 } 144 145 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, 146 unsigned N5, unsigned N6> 147 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const char (& S5)[N5],const char (& S6)[N6],const T & Value)148 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 149 const char (&S2)[N2], const char (&S3)[N3], 150 const char (&S4)[N4], const char (&S5)[N5], 151 const char (&S6)[N6], const T &Value) { 152 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value); 153 } 154 155 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, 156 unsigned N5, unsigned N6, unsigned N7> 157 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const char (& S5)[N5],const char (& S6)[N6],const char (& S7)[N7],const T & Value)158 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 159 const char (&S2)[N2], const char (&S3)[N3], 160 const char (&S4)[N4], const char (&S5)[N5], 161 const char (&S6)[N6], const char (&S7)[N7], 162 const T &Value) { 163 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value); 164 } 165 166 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, 167 unsigned N5, unsigned N6, unsigned N7, unsigned N8> 168 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const char (& S5)[N5],const char (& S6)[N6],const char (& S7)[N7],const char (& S8)[N8],const T & Value)169 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 170 const char (&S2)[N2], const char (&S3)[N3], 171 const char (&S4)[N4], const char (&S5)[N5], 172 const char (&S6)[N6], const char (&S7)[N7], 173 const char (&S8)[N8], const T &Value) { 174 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value); 175 } 176 177 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, 178 unsigned N5, unsigned N6, unsigned N7, unsigned N8, unsigned N9> 179 LLVM_ATTRIBUTE_ALWAYS_INLINE Cases(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const char (& S5)[N5],const char (& S6)[N6],const char (& S7)[N7],const char (& S8)[N8],const char (& S9)[N9],const T & Value)180 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1], 181 const char (&S2)[N2], const char (&S3)[N3], 182 const char (&S4)[N4], const char (&S5)[N5], 183 const char (&S6)[N6], const char (&S7)[N7], 184 const char (&S8)[N8], const char (&S9)[N9], 185 const T &Value) { 186 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value); 187 } 188 189 // Case-insensitive case matchers. 190 template <unsigned N> CaseLower(const char (& S)[N],const T & Value)191 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &CaseLower(const char (&S)[N], 192 const T &Value) { 193 if (!Result && Str.equals_lower(StringRef(S, N - 1))) 194 Result = &Value; 195 196 return *this; 197 } 198 199 template <unsigned N> EndsWithLower(const char (& S)[N],const T & Value)200 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &EndsWithLower(const char (&S)[N], 201 const T &Value) { 202 if (!Result && Str.endswith_lower(StringRef(S, N - 1))) 203 Result = &Value; 204 205 return *this; 206 } 207 208 template <unsigned N> StartsWithLower(const char (& S)[N],const T & Value)209 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &StartsWithLower(const char (&S)[N], 210 const T &Value) { 211 if (!Result && Str.startswith_lower(StringRef(S, N - 1))) 212 Result = &Value; 213 214 return *this; 215 } 216 template <unsigned N0, unsigned N1> 217 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & CasesLower(const char (& S0)[N0],const char (& S1)[N1],const T & Value)218 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const T &Value) { 219 return CaseLower(S0, Value).CaseLower(S1, Value); 220 } 221 222 template <unsigned N0, unsigned N1, unsigned N2> 223 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & CasesLower(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const T & Value)224 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2], 225 const T &Value) { 226 return CaseLower(S0, Value).CasesLower(S1, S2, Value); 227 } 228 229 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3> 230 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & CasesLower(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const T & Value)231 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2], 232 const char (&S3)[N3], const T &Value) { 233 return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value); 234 } 235 236 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4> 237 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch & CasesLower(const char (& S0)[N0],const char (& S1)[N1],const char (& S2)[N2],const char (& S3)[N3],const char (& S4)[N4],const T & Value)238 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2], 239 const char (&S3)[N3], const char (&S4)[N4], const T &Value) { 240 return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value); 241 } 242 243 LLVM_ATTRIBUTE_ALWAYS_INLINE Default(const T & Value)244 R Default(const T &Value) const { 245 if (Result) 246 return *Result; 247 return Value; 248 } 249 250 LLVM_ATTRIBUTE_ALWAYS_INLINE R()251 operator R() const { 252 assert(Result && "Fell off the end of a string-switch"); 253 return *Result; 254 } 255 }; 256 257 } // end namespace llvm 258 259 #endif // LLVM_ADT_STRINGSWITCH_H 260