]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/include/llvm/ADT/StringSwitch.h
Merge clang 7.0.1 and several follow-up changes
[FreeBSD/FreeBSD.git] / contrib / llvm / include / llvm / ADT / StringSwitch.h
1 //===--- StringSwitch.h - Switch-on-literal-string Construct --------------===/
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //===----------------------------------------------------------------------===/
8 //
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
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   LLVM_ATTRIBUTE_ALWAYS_INLINE
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   LLVM_ATTRIBUTE_ALWAYS_INLINE
70   StringSwitch &Case(StringLiteral S, T Value) {
71     if (!Result && Str == S) {
72       Result = std::move(Value);
73     }
74     return *this;
75   }
76
77   LLVM_ATTRIBUTE_ALWAYS_INLINE
78   StringSwitch& EndsWith(StringLiteral S, T Value) {
79     if (!Result && Str.endswith(S)) {
80       Result = std::move(Value);
81     }
82     return *this;
83   }
84
85   LLVM_ATTRIBUTE_ALWAYS_INLINE
86   StringSwitch& StartsWith(StringLiteral S, T Value) {
87     if (!Result && Str.startswith(S)) {
88       Result = std::move(Value);
89     }
90     return *this;
91   }
92
93   LLVM_ATTRIBUTE_ALWAYS_INLINE
94   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
95     return Case(S0, Value).Case(S1, Value);
96   }
97
98   LLVM_ATTRIBUTE_ALWAYS_INLINE
99   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
100                       T Value) {
101     return Case(S0, Value).Cases(S1, S2, Value);
102   }
103
104   LLVM_ATTRIBUTE_ALWAYS_INLINE
105   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
106                       StringLiteral S3, T Value) {
107     return Case(S0, Value).Cases(S1, S2, S3, Value);
108   }
109
110   LLVM_ATTRIBUTE_ALWAYS_INLINE
111   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
112                       StringLiteral S3, StringLiteral S4, T Value) {
113     return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
114   }
115
116   LLVM_ATTRIBUTE_ALWAYS_INLINE
117   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
118                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
119                       T Value) {
120     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
121   }
122
123   LLVM_ATTRIBUTE_ALWAYS_INLINE
124   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
125                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
126                       StringLiteral S6, T Value) {
127     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
128   }
129
130   LLVM_ATTRIBUTE_ALWAYS_INLINE
131   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
132                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
133                       StringLiteral S6, StringLiteral S7, T Value) {
134     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
135   }
136
137   LLVM_ATTRIBUTE_ALWAYS_INLINE
138   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
139                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
140                       StringLiteral S6, StringLiteral S7, StringLiteral S8,
141                       T Value) {
142     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
143   }
144
145   LLVM_ATTRIBUTE_ALWAYS_INLINE
146   StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
147                       StringLiteral S3, StringLiteral S4, StringLiteral S5,
148                       StringLiteral S6, StringLiteral S7, StringLiteral S8,
149                       StringLiteral S9, T Value) {
150     return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
151   }
152
153   // Case-insensitive case matchers.
154   LLVM_ATTRIBUTE_ALWAYS_INLINE
155   StringSwitch &CaseLower(StringLiteral S, T Value) {
156     if (!Result && Str.equals_lower(S))
157       Result = std::move(Value);
158
159     return *this;
160   }
161
162   LLVM_ATTRIBUTE_ALWAYS_INLINE
163   StringSwitch &EndsWithLower(StringLiteral S, T Value) {
164     if (!Result && Str.endswith_lower(S))
165       Result = Value;
166
167     return *this;
168   }
169
170   LLVM_ATTRIBUTE_ALWAYS_INLINE
171   StringSwitch &StartsWithLower(StringLiteral S, T Value) {
172     if (!Result && Str.startswith_lower(S))
173       Result = std::move(Value);
174
175     return *this;
176   }
177
178   LLVM_ATTRIBUTE_ALWAYS_INLINE
179   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
180     return CaseLower(S0, Value).CaseLower(S1, Value);
181   }
182
183   LLVM_ATTRIBUTE_ALWAYS_INLINE
184   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
185                            T Value) {
186     return CaseLower(S0, Value).CasesLower(S1, S2, Value);
187   }
188
189   LLVM_ATTRIBUTE_ALWAYS_INLINE
190   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
191                            StringLiteral S3, T Value) {
192     return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
193   }
194
195   LLVM_ATTRIBUTE_ALWAYS_INLINE
196   StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
197                            StringLiteral S3, StringLiteral S4, T Value) {
198     return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
199   }
200
201   LLVM_NODISCARD
202   LLVM_ATTRIBUTE_ALWAYS_INLINE
203   R Default(T Value) {
204     if (Result)
205       return std::move(*Result);
206     return Value;
207   }
208
209   LLVM_NODISCARD
210   LLVM_ATTRIBUTE_ALWAYS_INLINE
211   operator R() {
212     assert(Result && "Fell off the end of a string-switch");
213     return std::move(*Result);
214   }
215 };
216
217 } // end namespace llvm
218
219 #endif // LLVM_ADT_STRINGSWITCH_H