Skip to content

Commit ff3eca4

Browse files
authored
Merge pull request #32076 from compnerd/switching-strings
stdlib: add `StringSwitch` to LLVMSupport fork
2 parents b4a202c + d4f4871 commit ff3eca4

File tree

1 file changed

+198
-0
lines changed

1 file changed

+198
-0
lines changed
Lines changed: 198 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,198 @@
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+
// This file implements the StringSwitch template, which mimics a switch()
9+
// statement whose cases are string literals.
10+
//
11+
//===----------------------------------------------------------------------===/
12+
#ifndef LLVM_ADT_STRINGSWITCH_H
13+
#define LLVM_ADT_STRINGSWITCH_H
14+
15+
#include "llvm/ADT/StringRef.h"
16+
#include "llvm/Support/Compiler.h"
17+
#include <cassert>
18+
#include <cstring>
19+
20+
inline namespace __swift { inline namespace __runtime {
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+
explicit StringSwitch(StringRef S)
53+
: Str(S), Result() { }
54+
55+
// StringSwitch is not copyable.
56+
StringSwitch(const StringSwitch &) = delete;
57+
58+
// StringSwitch is not assignable due to 'Str' being 'const'.
59+
void operator=(const StringSwitch &) = delete;
60+
void operator=(StringSwitch &&other) = delete;
61+
62+
StringSwitch(StringSwitch &&other)
63+
: Str(other.Str), Result(std::move(other.Result)) { }
64+
65+
~StringSwitch() = default;
66+
67+
// Case-sensitive case matchers
68+
StringSwitch &Case(StringLiteral S, T Value) {
69+
if (!Result && Str == S) {
70+
Result = std::move(Value);
71+
}
72+
return *this;
73+
}
74+
75+
StringSwitch& EndsWith(StringLiteral S, T Value) {
76+
if (!Result && Str.endswith(S)) {
77+
Result = std::move(Value);
78+
}
79+
return *this;
80+
}
81+
82+
StringSwitch& StartsWith(StringLiteral S, T Value) {
83+
if (!Result && Str.startswith(S)) {
84+
Result = std::move(Value);
85+
}
86+
return *this;
87+
}
88+
89+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
90+
return Case(S0, Value).Case(S1, Value);
91+
}
92+
93+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
94+
T Value) {
95+
return Case(S0, Value).Cases(S1, S2, Value);
96+
}
97+
98+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
99+
StringLiteral S3, T Value) {
100+
return Case(S0, Value).Cases(S1, S2, S3, Value);
101+
}
102+
103+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
104+
StringLiteral S3, StringLiteral S4, T Value) {
105+
return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
106+
}
107+
108+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
109+
StringLiteral S3, StringLiteral S4, StringLiteral S5,
110+
T Value) {
111+
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
112+
}
113+
114+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
115+
StringLiteral S3, StringLiteral S4, StringLiteral S5,
116+
StringLiteral S6, T Value) {
117+
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
118+
}
119+
120+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
121+
StringLiteral S3, StringLiteral S4, StringLiteral S5,
122+
StringLiteral S6, StringLiteral S7, T Value) {
123+
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
124+
}
125+
126+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
127+
StringLiteral S3, StringLiteral S4, StringLiteral S5,
128+
StringLiteral S6, StringLiteral S7, StringLiteral S8,
129+
T Value) {
130+
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
131+
}
132+
133+
StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
134+
StringLiteral S3, StringLiteral S4, StringLiteral S5,
135+
StringLiteral S6, StringLiteral S7, StringLiteral S8,
136+
StringLiteral S9, T Value) {
137+
return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
138+
}
139+
140+
// Case-insensitive case matchers.
141+
StringSwitch &CaseLower(StringLiteral S, T Value) {
142+
if (!Result && Str.equals_lower(S))
143+
Result = std::move(Value);
144+
145+
return *this;
146+
}
147+
148+
StringSwitch &EndsWithLower(StringLiteral S, T Value) {
149+
if (!Result && Str.endswith_lower(S))
150+
Result = Value;
151+
152+
return *this;
153+
}
154+
155+
StringSwitch &StartsWithLower(StringLiteral S, T Value) {
156+
if (!Result && Str.startswith_lower(S))
157+
Result = std::move(Value);
158+
159+
return *this;
160+
}
161+
162+
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
163+
return CaseLower(S0, Value).CaseLower(S1, Value);
164+
}
165+
166+
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
167+
T Value) {
168+
return CaseLower(S0, Value).CasesLower(S1, S2, Value);
169+
}
170+
171+
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
172+
StringLiteral S3, T Value) {
173+
return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
174+
}
175+
176+
StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
177+
StringLiteral S3, StringLiteral S4, T Value) {
178+
return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
179+
}
180+
181+
LLVM_NODISCARD
182+
R Default(T Value) {
183+
if (Result)
184+
return std::move(*Result);
185+
return Value;
186+
}
187+
188+
LLVM_NODISCARD
189+
operator R() {
190+
assert(Result && "Fell off the end of a string-switch");
191+
return std::move(*Result);
192+
}
193+
};
194+
195+
} // end namespace llvm
196+
}}
197+
198+
#endif // LLVM_ADT_STRINGSWITCH_H

0 commit comments

Comments
 (0)