1//===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
2//
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//===----------------------------------------------------------------------===/
7///
8/// \file
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#include <optional>
21
22namespace llvm {
23
24/// A switch()-like statement whose cases are string literals.
25///
26/// The StringSwitch class is a simple form of a switch() statement that
27/// determines whether the given string matches one of the given string
28/// literals. The template type parameter \p T is the type of the value that
29/// will be returned from the string-switch expression. For example,
30/// the following code switches on the name of a color in \c argv[i]:
31///
32/// \code
33/// Color color = StringSwitch<Color>(argv[i])
34/// .Case("red", Red)
35/// .Case("orange", Orange)
36/// .Case("yellow", Yellow)
37/// .Case("green", Green)
38/// .Case("blue", Blue)
39/// .Case("indigo", Indigo)
40/// .Cases("violet", "purple", Violet)
41/// .Default(UnknownColor);
42/// \endcode
43template<typename T, typename R = T>
44class StringSwitch {
45 /// The string we are matching.
46 const StringRef Str;
47
48 /// The pointer to the result of this switch statement, once known,
49 /// null before that.
50 std::optional<T> Result;
51
52public:
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 StringSwitch &Case(StringLiteral S, T Value) {
70 if (!Result && Str == S) {
71 Result = std::move(Value);
72 }
73 return *this;
74 }
75
76 StringSwitch& EndsWith(StringLiteral S, T Value) {
77 if (!Result && Str.ends_with(Suffix: S)) {
78 Result = std::move(Value);
79 }
80 return *this;
81 }
82
83 StringSwitch& StartsWith(StringLiteral S, T Value) {
84 if (!Result && Str.starts_with(Prefix: S)) {
85 Result = std::move(Value);
86 }
87 return *this;
88 }
89
90 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
91 return Case(S: S0, Value).Case(S1, Value);
92 }
93
94 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
95 T Value) {
96 return Case(S: S0, Value).Cases(S1, S2, Value);
97 }
98
99 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
100 StringLiteral S3, T Value) {
101 return Case(S: S0, Value).Cases(S1, S2, S3, Value);
102 }
103
104 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
105 StringLiteral S3, StringLiteral S4, T Value) {
106 return Case(S: S0, Value).Cases(S1, S2, S3, S4, Value);
107 }
108
109 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
110 StringLiteral S3, StringLiteral S4, StringLiteral S5,
111 T Value) {
112 return Case(S: S0, Value).Cases(S1, S2, S3, S4, S5, Value);
113 }
114
115 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
116 StringLiteral S3, StringLiteral S4, StringLiteral S5,
117 StringLiteral S6, T Value) {
118 return Case(S: S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
119 }
120
121 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
122 StringLiteral S3, StringLiteral S4, StringLiteral S5,
123 StringLiteral S6, StringLiteral S7, T Value) {
124 return Case(S: S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
125 }
126
127 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
128 StringLiteral S3, StringLiteral S4, StringLiteral S5,
129 StringLiteral S6, StringLiteral S7, StringLiteral S8,
130 T Value) {
131 return Case(S: S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
132 }
133
134 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
135 StringLiteral S3, StringLiteral S4, StringLiteral S5,
136 StringLiteral S6, StringLiteral S7, StringLiteral S8,
137 StringLiteral S9, T Value) {
138 return Case(S: S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
139 }
140
141 // Case-insensitive case matchers.
142 StringSwitch &CaseLower(StringLiteral S, T Value) {
143 if (!Result && Str.equals_insensitive(RHS: S))
144 Result = std::move(Value);
145
146 return *this;
147 }
148
149 StringSwitch &EndsWithLower(StringLiteral S, T Value) {
150 if (!Result && Str.ends_with_insensitive(Suffix: S))
151 Result = Value;
152
153 return *this;
154 }
155
156 StringSwitch &StartsWithLower(StringLiteral S, T Value) {
157 if (!Result && Str.starts_with_insensitive(Prefix: S))
158 Result = std::move(Value);
159
160 return *this;
161 }
162
163 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
164 return CaseLower(S: S0, Value).CaseLower(S1, Value);
165 }
166
167 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
168 T Value) {
169 return CaseLower(S: S0, Value).CasesLower(S1, S2, Value);
170 }
171
172 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
173 StringLiteral S3, T Value) {
174 return CaseLower(S: S0, Value).CasesLower(S1, S2, S3, Value);
175 }
176
177 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
178 StringLiteral S3, StringLiteral S4, T Value) {
179 return CaseLower(S: S0, Value).CasesLower(S1, S2, S3, S4, Value);
180 }
181
182 [[nodiscard]] R Default(T Value) {
183 if (Result)
184 return std::move(*Result);
185 return Value;
186 }
187
188 [[nodiscard]] operator R() {
189 assert(Result && "Fell off the end of a string-switch");
190 return std::move(*Result);
191 }
192};
193
194} // end namespace llvm
195
196#endif // LLVM_ADT_STRINGSWITCH_H
197

source code of llvm/include/llvm/ADT/StringSwitch.h