Line data Source code
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
53 38502084 : explicit StringSwitch(StringRef S)
54 90774744 : : 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 1217092048 : if (!Result && Str == S) {
72 17701156 : Result = std::move(Value);
73 : }
74 : return *this;
75 : }
76 :
77 : LLVM_ATTRIBUTE_ALWAYS_INLINE
78 : StringSwitch& EndsWith(StringLiteral S, T Value) {
79 2815162 : if (!Result && Str.endswith(S)) {
80 6051 : Result = std::move(Value);
81 : }
82 : return *this;
83 : }
84 :
85 : LLVM_ATTRIBUTE_ALWAYS_INLINE
86 : StringSwitch& StartsWith(StringLiteral S, T Value) {
87 42048617 : if (!Result && Str.startswith(S)) {
88 2509650 : 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 33722226 : 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 18221129 : 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 10561511 : 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 6038787 : 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 1591458 : 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 15858 : if (!Result && Str.equals_lower(S))
157 3519 : 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 12226 : 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 8114 : 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 90762846 : if (Result)
205 28369203 : return std::move(*Result);
206 0 : 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 15799 : return std::move(*Result);
214 : }
215 : };
216 :
217 : } // end namespace llvm
218 :
219 : #endif // LLVM_ADT_STRINGSWITCH_H
|