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
21namespace 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
42template<typename T, typename R = T>
43class 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
51public:
52 LLVM_ATTRIBUTE_ALWAYS_INLINE
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
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
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
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
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
94 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
95 return Case(S0, Value).Case(S1, Value);
96 }
97
98 LLVM_ATTRIBUTE_ALWAYS_INLINE
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
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
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
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
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
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
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
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
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
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
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
179 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
180 return CaseLower(S0, Value).CaseLower(S1, Value);
181 }
182
183 LLVM_ATTRIBUTE_ALWAYS_INLINE
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
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
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
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
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