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 <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>
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:
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
64 : Str(other.Str), Result(std::move(other.Result)) { }
65
66 ~StringSwitch() = default;
67
68 // Case-sensitive case matchers
70 CaseImpl(Value, S);
71 return *this;
72 }
73
75 if (!Result && Str.ends_with(S)) {
76 Result = std::move(Value);
77 }
78 return *this;
79 }
80
82 if (!Result && Str.starts_with(S)) {
83 Result = std::move(Value);
84 }
85 return *this;
86 }
87
89 return CasesImpl(Value, S0, S1);
90 }
91
93 T Value) {
94 return CasesImpl(Value, S0, S1, S2);
95 }
96
98 StringLiteral S3, T Value) {
99 return CasesImpl(Value, S0, S1, S2, S3);
100 }
101
104 return CasesImpl(Value, S0, S1, S2, S3, S4);
105 }
106
109 T Value) {
110 return CasesImpl(Value, S0, S1, S2, S3, S4, S5);
111 }
112
115 StringLiteral S6, T Value) {
116 return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6);
117 }
118
122 return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6, S7);
123 }
124
128 T Value) {
129 return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6, S7, S8);
130 }
131
135 StringLiteral S9, T Value) {
136 return CasesImpl(Value, S0, S1, S2, S3, S4, S5, S6, S7, S8, S9);
137 }
138
139 // Case-insensitive case matchers.
141 CaseLowerImpl(Value, S);
142 return *this;
143 }
144
146 if (!Result && Str.ends_with_insensitive(S))
147 Result = Value;
148
149 return *this;
150 }
151
153 if (!Result && Str.starts_with_insensitive(S))
154 Result = std::move(Value);
155
156 return *this;
157 }
158
160 return CasesLowerImpl(Value, S0, S1);
161 }
162
164 T Value) {
165 return CasesLowerImpl(Value, S0, S1, S2);
166 }
167
169 StringLiteral S3, T Value) {
170 return CasesLowerImpl(Value, S0, S1, S2, S3);
171 }
172
175 return CasesLowerImpl(Value, S0, S1, S2, S3, S4);
176 }
177
178 [[nodiscard]] R Default(T Value) {
179 if (Result)
180 return std::move(*Result);
181 return Value;
182 }
183
184 /// Declare default as unreachable, making sure that all cases were handled.
185 [[nodiscard]] R DefaultUnreachable(
186 const char *Message = "Fell off the end of a string-switch") {
187 if (Result)
188 return std::move(*Result);
189 llvm_unreachable(Message);
190 }
191
192 [[nodiscard]] operator R() { return DefaultUnreachable(); }
193
194private:
195 // Returns true when `Str` matches the `S` argument, and stores the result.
196 bool CaseImpl(T &Value, StringLiteral S) {
197 if (!Result && Str == S) {
198 Result = std::move(Value);
199 return true;
200 }
201 return false;
202 }
203
204 // Returns true when `Str` matches the `S` argument (case-insensitive), and
205 // stores the result.
206 bool CaseLowerImpl(T &Value, StringLiteral S) {
207 if (!Result && Str.equals_insensitive(S)) {
208 Result = std::move(Value);
209 return true;
210 }
211 return false;
212 }
213
214 template <typename... Args> StringSwitch &CasesImpl(T &Value, Args... Cases) {
215 // Stop matching after the string is found.
216 (... || CaseImpl(Value, Cases));
217 return *this;
218 }
219
220 template <typename... Args>
221 StringSwitch &CasesLowerImpl(T &Value, Args... Cases) {
222 // Stop matching after the string is found.
223 (... || CaseLowerImpl(Value, Cases));
224 return *this;
225 }
226};
227
228} // end namespace llvm
229
230#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=(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 & 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(StringSwitch &&other)
void operator=(StringSwitch &&other)=delete
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, StringLiteral S3, StringLiteral S4, StringLiteral S5, StringLiteral S6, T Value)
StringSwitch & Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2, 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)
~StringSwitch()=default
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
This is an optimization pass for GlobalISel generic memory operations.
FunctionAddr VTableAddr Value
Definition InstrProf.h:137
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1847
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:867