LLVM 22.0.0git
StringSwitch.h
Go to the documentation of this file.
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"
18#include <cassert>
19#include <cstring>
20#include <initializer_list>
21#include <optional>
22
23namespace llvm {
24
25/// A switch()-like statement whose cases are string literals.
26///
27/// The StringSwitch class is a simple form of a switch() statement that
28/// determines whether the given string matches one of the given string
29/// literals. The template type parameter \p T is the type of the value that
30/// will be returned from the string-switch expression. For example,
31/// the following code switches on the name of a color in \c argv[i]:
32///
33/// \code
34/// Color color = StringSwitch<Color>(argv[i])
35/// .Case("red", Red)
36/// .Case("orange", Orange)
37/// .Case("yellow", Yellow)
38/// .Case("green", Green)
39/// .Case("blue", Blue)
40/// .Case("indigo", Indigo)
41/// .Cases("violet", "purple", Violet)
42/// .Default(UnknownColor);
43/// \endcode
44template<typename T, typename R = T>
46 /// The string we are matching.
47 const StringRef Str;
48
49 /// The pointer to the result of this switch statement, once known,
50 /// null before that.
51 std::optional<T> Result;
52
53public:
55 : Str(S), Result() { }
56
58
59 // StringSwitch is not copyable.
60 StringSwitch(const StringSwitch &) = delete;
61
62 // StringSwitch is not assignable due to 'Str' being 'const'.
63 void operator=(const StringSwitch &) = delete;
64 void operator=(StringSwitch &&) = delete;
65
66 // Case-sensitive case matchers
68 CaseImpl(Value, S);
69 return *this;
70 }
71
73 if (!Result && Str.ends_with(S)) {
74 Result = std::move(Value);
75 }
76 return *this;
77 }
78
80 if (!Result && Str.starts_with(S)) {
81 Result = std::move(Value);
82 }
83 return *this;
84 }
85
86 StringSwitch &Cases(std::initializer_list<StringLiteral> CaseStrings,
87 T Value) {
88 return CasesImpl(Value, CaseStrings);
89 }
90
92 return CasesImpl(Value, {S0, S1});
93 }
94
96 T Value) {
97 return CasesImpl(Value, {S0, S1, S2});
98 }
99
101 StringLiteral S3, T Value) {
102 return CasesImpl(Value, {S0, S1, S2, S3});
103 }
104
107 return CasesImpl(Value, {S0, S1, S2, S3, S4});
108 }
109
112 T Value) {
113 return CasesImpl(Value, {S0, S1, S2, S3, S4, S5});
114 }
115
118 StringLiteral S6, T Value) {
119 return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6});
120 }
121
125 return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7});
126 }
127
131 T Value) {
132 return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7, S8});
133 }
134
138 StringLiteral S9, T Value) {
139 return CasesImpl(Value, {S0, S1, S2, S3, S4, S5, S6, S7, S8, S9});
140 }
141
142 // Case-insensitive case matchers.
144 CaseLowerImpl(Value, S);
145 return *this;
146 }
147
149 if (!Result && Str.ends_with_insensitive(S))
150 Result = Value;
151
152 return *this;
153 }
154
156 if (!Result && Str.starts_with_insensitive(S))
157 Result = std::move(Value);
158
159 return *this;
160 }
161
162 StringSwitch &CasesLower(std::initializer_list<StringLiteral> CaseStrings,
163 T Value) {
164 return CasesLowerImpl(Value, CaseStrings);
165 }
166
168 return CasesLowerImpl(Value, {S0, S1});
169 }
170
172 T Value) {
173 return CasesLowerImpl(Value, {S0, S1, S2});
174 }
175
177 StringLiteral S3, T Value) {
178 return CasesLowerImpl(Value, {S0, S1, S2, S3});
179 }
180
183 return CasesLowerImpl(Value, {S0, S1, S2, S3, S4});
184 }
185
186 [[nodiscard]] R Default(T Value) {
187 if (Result)
188 return std::move(*Result);
189 return Value;
190 }
191
192 /// Declare default as unreachable, making sure that all cases were handled.
193 [[nodiscard]] R DefaultUnreachable(
194 const char *Message = "Fell off the end of a string-switch") {
195 if (Result)
196 return std::move(*Result);
197 llvm_unreachable(Message);
198 }
199
200 [[nodiscard]] operator R() { return DefaultUnreachable(); }
201
202private:
203 // Returns true when `Str` matches the `S` argument, and stores the result.
204 bool CaseImpl(T &Value, StringLiteral S) {
205 if (!Result && Str == S) {
206 Result = std::move(Value);
207 return true;
208 }
209 return false;
210 }
211
212 // Returns true when `Str` matches the `S` argument (case-insensitive), and
213 // stores the result.
214 bool CaseLowerImpl(T &Value, StringLiteral S) {
215 if (!Result && Str.equals_insensitive(S)) {
216 Result = std::move(Value);
217 return true;
218 }
219 return false;
220 }
221
222 StringSwitch &CasesImpl(T &Value,
223 std::initializer_list<StringLiteral> Cases) {
224 // Stop matching after the string is found.
225 for (StringLiteral S : Cases)
226 if (CaseImpl(Value, S))
227 break;
228 return *this;
229 }
230
231 StringSwitch &CasesLowerImpl(T &Value,
232 std::initializer_list<StringLiteral> Cases) {
233 // Stop matching after the string is found.
234 for (StringLiteral S : Cases)
235 if (CaseLowerImpl(Value, S))
236 break;
237 return *this;
238 }
239};
240
241} // end namespace llvm
242
243#endif // LLVM_ADT_STRINGSWITCH_H
constexpr LLT S1
constexpr LLT S8
#define T
A wrapper around a string literal that serves as a proxy for constructing global tables of StringRefs...
Definition StringRef.h:854
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
StringSwitch & CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, StringLiteral S5, T Value)
StringSwitch & EndsWithLower(StringLiteral S, T Value)
StringSwitch & StartsWithLower(StringLiteral S, T Value)
StringSwitch & CaseLower(StringLiteral S, T Value)
StringSwitch & Case(StringLiteral S, T Value)
StringSwitch & CasesLower(StringLiteral S0, StringLiteral S1, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, T Value)
void operator=(StringSwitch &&)=delete
void operator=(const StringSwitch &)=delete
StringSwitch & CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, T Value)
R DefaultUnreachable(const char *Message="Fell off the end of a string-switch")
Declare default as unreachable, making sure that all cases were handled.
StringSwitch & CasesLower(std::initializer_list< StringLiteral > CaseStrings, T Value)
StringSwitch & StartsWith(StringLiteral S, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, StringLiteral S5, StringLiteral S6, StringLiteral S7, StringLiteral S8, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, T Value)
StringSwitch(const StringSwitch &)=delete
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, T Value)
StringSwitch & EndsWith(StringLiteral S, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, StringLiteral S5, StringLiteral S6, StringLiteral S7, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, StringLiteral S5, StringLiteral S6, T Value)
StringSwitch(StringSwitch &&)=default
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, T Value)
StringSwitch & Cases(std::initializer_list< StringLiteral > CaseStrings, T Value)
StringSwitch(StringRef S)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, StringLiteral S5, StringLiteral S6, StringLiteral S7, StringLiteral S8, StringLiteral S9, T Value)
StringSwitch & CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2, T Value)
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137