1 //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //===----------------------------------------------------------------------===/
8 // This file implements the StringSwitch template, which mimics a switch()
9 // statement whose cases are string literals.
11 //===----------------------------------------------------------------------===/
12 #ifndef LLVM_ADT_STRINGSWITCH_H
13 #define LLVM_ADT_STRINGSWITCH_H
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Compiler.h"
22 /// A switch()-like statement whose cases are string literals.
24 /// The StringSwitch class is a simple form of a switch() statement that
25 /// determines whether the given string matches one of the given string
26 /// literals. The template type parameter \p T is the type of the value that
27 /// will be returned from the string-switch expression. For example,
28 /// the following code switches on the name of a color in \c argv[i]:
31 /// Color color = StringSwitch<Color>(argv[i])
33 /// .Case("orange", Orange)
34 /// .Case("yellow", Yellow)
35 /// .Case("green", Green)
36 /// .Case("blue", Blue)
37 /// .Case("indigo", Indigo)
38 /// .Cases("violet", "purple", Violet)
39 /// .Default(UnknownColor);
41 template<typename T
, typename R
= T
>
43 /// The string we are matching.
46 /// The pointer to the result of this switch statement, once known,
51 explicit StringSwitch(StringRef S
)
52 : Str(S
), Result() { }
54 // StringSwitch is not copyable.
55 StringSwitch(const StringSwitch
&) = delete;
57 // StringSwitch is not assignable due to 'Str' being 'const'.
58 void operator=(const StringSwitch
&) = delete;
59 void operator=(StringSwitch
&&other
) = delete;
61 StringSwitch(StringSwitch
&&other
)
62 : Str(other
.Str
), Result(std::move(other
.Result
)) { }
64 ~StringSwitch() = default;
66 // Case-sensitive case matchers
67 StringSwitch
&Case(StringLiteral S
, T Value
) {
68 if (!Result
&& Str
== S
) {
69 Result
= std::move(Value
);
74 StringSwitch
& EndsWith(StringLiteral S
, T Value
) {
75 if (!Result
&& Str
.endswith(S
)) {
76 Result
= std::move(Value
);
81 StringSwitch
& StartsWith(StringLiteral S
, T Value
) {
82 if (!Result
&& Str
.startswith(S
)) {
83 Result
= std::move(Value
);
88 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, T Value
) {
89 return Case(S0
, Value
).Case(S1
, Value
);
92 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
94 return Case(S0
, Value
).Cases(S1
, S2
, Value
);
97 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
98 StringLiteral S3
, T Value
) {
99 return Case(S0
, Value
).Cases(S1
, S2
, S3
, Value
);
102 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
103 StringLiteral S3
, StringLiteral S4
, T Value
) {
104 return Case(S0
, Value
).Cases(S1
, S2
, S3
, S4
, Value
);
107 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
108 StringLiteral S3
, StringLiteral S4
, StringLiteral S5
,
110 return Case(S0
, Value
).Cases(S1
, S2
, S3
, S4
, S5
, Value
);
113 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
114 StringLiteral S3
, StringLiteral S4
, StringLiteral S5
,
115 StringLiteral S6
, T Value
) {
116 return Case(S0
, Value
).Cases(S1
, S2
, S3
, S4
, S5
, S6
, Value
);
119 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
120 StringLiteral S3
, StringLiteral S4
, StringLiteral S5
,
121 StringLiteral S6
, StringLiteral S7
, T Value
) {
122 return Case(S0
, Value
).Cases(S1
, S2
, S3
, S4
, S5
, S6
, S7
, Value
);
125 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
126 StringLiteral S3
, StringLiteral S4
, StringLiteral S5
,
127 StringLiteral S6
, StringLiteral S7
, StringLiteral S8
,
129 return Case(S0
, Value
).Cases(S1
, S2
, S3
, S4
, S5
, S6
, S7
, S8
, Value
);
132 StringSwitch
&Cases(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
133 StringLiteral S3
, StringLiteral S4
, StringLiteral S5
,
134 StringLiteral S6
, StringLiteral S7
, StringLiteral S8
,
135 StringLiteral S9
, T Value
) {
136 return Case(S0
, Value
).Cases(S1
, S2
, S3
, S4
, S5
, S6
, S7
, S8
, S9
, Value
);
139 // Case-insensitive case matchers.
140 StringSwitch
&CaseLower(StringLiteral S
, T Value
) {
141 if (!Result
&& Str
.equals_lower(S
))
142 Result
= std::move(Value
);
147 StringSwitch
&EndsWithLower(StringLiteral S
, T Value
) {
148 if (!Result
&& Str
.endswith_lower(S
))
154 StringSwitch
&StartsWithLower(StringLiteral S
, T Value
) {
155 if (!Result
&& Str
.startswith_lower(S
))
156 Result
= std::move(Value
);
161 StringSwitch
&CasesLower(StringLiteral S0
, StringLiteral S1
, T Value
) {
162 return CaseLower(S0
, Value
).CaseLower(S1
, Value
);
165 StringSwitch
&CasesLower(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
167 return CaseLower(S0
, Value
).CasesLower(S1
, S2
, Value
);
170 StringSwitch
&CasesLower(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
171 StringLiteral S3
, T Value
) {
172 return CaseLower(S0
, Value
).CasesLower(S1
, S2
, S3
, Value
);
175 StringSwitch
&CasesLower(StringLiteral S0
, StringLiteral S1
, StringLiteral S2
,
176 StringLiteral S3
, StringLiteral S4
, T Value
) {
177 return CaseLower(S0
, Value
).CasesLower(S1
, S2
, S3
, S4
, Value
);
183 return std::move(*Result
);
189 assert(Result
&& "Fell off the end of a string-switch");
190 return std::move(*Result
);
194 } // end namespace llvm
196 #endif // LLVM_ADT_STRINGSWITCH_H