1 //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //===----------------------------------------------------------------------===/
9 // This file implements the StringSwitch template, which mimics a switch()
10 // statement whose cases are string literals.
12 //===----------------------------------------------------------------------===/
13 #ifndef LLVM_ADT_STRINGSWITCH_H
14 #define LLVM_ADT_STRINGSWITCH_H
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Compiler.h"
23 /// \brief A switch()-like statement whose cases are string literals.
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]:
32 /// Color color = StringSwitch<Color>(argv[i])
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);
42 template<typename T, typename R = T>
44 /// \brief The string we are matching.
47 /// \brief The pointer to the result of this switch statement, once known,
52 LLVM_ATTRIBUTE_ALWAYS_INLINE
53 explicit StringSwitch(StringRef S)
54 : Str(S), Result(nullptr) { }
56 // StringSwitch is not copyable.
57 StringSwitch(const StringSwitch &) = delete;
58 void operator=(const StringSwitch &) = delete;
60 StringSwitch(StringSwitch &&other) {
61 *this = std::move(other);
63 StringSwitch &operator=(StringSwitch &&other) {
65 Result = other.Result;
69 ~StringSwitch() = default;
71 // Case-sensitive case matchers
73 LLVM_ATTRIBUTE_ALWAYS_INLINE
74 StringSwitch& Case(const char (&S)[N], const T& Value) {
76 if (!Result && N-1 == Str.size() &&
77 (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
84 LLVM_ATTRIBUTE_ALWAYS_INLINE
85 StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
87 if (!Result && Str.size() >= N-1 &&
88 (N == 1 || std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0)) {
95 LLVM_ATTRIBUTE_ALWAYS_INLINE
96 StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
98 if (!Result && Str.size() >= N-1 &&
99 (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
105 template<unsigned N0, unsigned N1>
106 LLVM_ATTRIBUTE_ALWAYS_INLINE
107 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
109 return Case(S0, Value).Case(S1, Value);
112 template<unsigned N0, unsigned N1, unsigned N2>
113 LLVM_ATTRIBUTE_ALWAYS_INLINE
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);
119 template<unsigned N0, unsigned N1, unsigned N2, unsigned N3>
120 LLVM_ATTRIBUTE_ALWAYS_INLINE
121 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
122 const char (&S2)[N2], const char (&S3)[N3],
124 return Case(S0, Value).Cases(S1, S2, S3, Value);
127 template<unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
128 LLVM_ATTRIBUTE_ALWAYS_INLINE
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);
135 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
137 LLVM_ATTRIBUTE_ALWAYS_INLINE
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],
142 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
145 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
146 unsigned N5, unsigned N6>
147 LLVM_ATTRIBUTE_ALWAYS_INLINE
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);
155 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4,
156 unsigned N5, unsigned N6, unsigned N7>
157 LLVM_ATTRIBUTE_ALWAYS_INLINE
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],
163 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
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
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);
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
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],
186 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
189 // Case-insensitive case matchers.
190 template <unsigned N>
191 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &CaseLower(const char (&S)[N],
193 if (!Result && Str.equals_lower(StringRef(S, N - 1)))
199 template <unsigned N>
200 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &EndsWithLower(const char (&S)[N],
202 if (!Result && Str.endswith_lower(StringRef(S, N - 1)))
208 template <unsigned N>
209 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &StartsWithLower(const char (&S)[N],
211 if (!Result && Str.startswith_lower(StringRef(S, N - 1)))
216 template <unsigned N0, unsigned N1>
217 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
218 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const T &Value) {
219 return CaseLower(S0, Value).CaseLower(S1, Value);
222 template <unsigned N0, unsigned N1, unsigned N2>
223 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
224 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
226 return CaseLower(S0, Value).CasesLower(S1, S2, Value);
229 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3>
230 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
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);
236 template <unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4>
237 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
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);
243 LLVM_ATTRIBUTE_ALWAYS_INLINE
244 R Default(const T &Value) const {
250 LLVM_ATTRIBUTE_ALWAYS_INLINE
252 assert(Result && "Fell off the end of a string-switch");
257 } // end namespace llvm
259 #endif // LLVM_ADT_STRINGSWITCH_H