llvm.org GIT mirror llvm / 3d8b511
[ADT] Simplify and optimize StringSwitch This change improves incremental rebuild performance on dual Xeon 8168 machines by 54%. This change also improves run time code gen by not forcing the case values to be lvalues. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@326109 91177308-0d34-0410-b5e6-96231b3b80d8 David Zarzycki 2 years ago
3 changed file(s) with 107 addition(s) and 132 deletion(s). Raw diff Collapse all Expand all
854854 /// constexpr StringLiteral S("test");
855855 ///
856856 class StringLiteral : public StringRef {
857 private:
858 constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
859 }
860
857861 public:
858862 template
859863 constexpr StringLiteral(const char (&Str)[N])
866870 #endif
867871 : StringRef(Str, N - 1) {
868872 }
873
874 // Explicit construction for strings like "foo\0bar".
875 template
876 static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
877 return StringLiteral(Str, N - 1);
878 }
869879 };
870880
871881 /// @name StringRef Comparison Operators
4141 template
4242 class StringSwitch {
4343 /// \brief The string we are matching.
44 StringRef Str;
44 const StringRef Str;
4545
4646 /// \brief The pointer to the result of this switch statement, once known,
4747 /// null before that.
48 const T *Result;
48 Optional Result;
4949
5050 public:
5151 LLVM_ATTRIBUTE_ALWAYS_INLINE
5252 explicit StringSwitch(StringRef S)
53 : Str(S), Result(nullptr) { }
53 : Str(S), Result() { }
5454
5555 // StringSwitch is not copyable.
5656 StringSwitch(const StringSwitch &) = delete;
6060 *this = std::move(other);
6161 }
6262 StringSwitch &operator=(StringSwitch &&other) {
63 Str = other.Str;
64 Result = other.Result;
63 Str = std::move(other.Str);
64 Result = std::move(other.Result);
6565 return *this;
6666 }
6767
6868 ~StringSwitch() = default;
6969
7070 // Case-sensitive case matchers
71 template
72 LLVM_ATTRIBUTE_ALWAYS_INLINE
73 StringSwitch& Case(const char (&S)[N], const T& Value) {
74 assert(N);
75 if (!Result && N-1 == Str.size() &&
76 (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
77 Result = &Value;
71 LLVM_ATTRIBUTE_ALWAYS_INLINE
72 StringSwitch &Case(StringLiteral S, T Value) {
73 if (!Result && Str == S) {
74 Result = std::move(Value);
7875 }
7976 return *this;
8077 }
8178
82 template
83 LLVM_ATTRIBUTE_ALWAYS_INLINE
84 StringSwitch& EndsWith(const char (&S)[N], const T &Value) {
85 assert(N);
86 if (!Result && Str.size() >= N-1 &&
87 (N == 1 || std::memcmp(S, Str.data() + Str.size() + 1 - N, N-1) == 0)) {
88 Result = &Value;
79 LLVM_ATTRIBUTE_ALWAYS_INLINE
80 StringSwitch& EndsWith(StringLiteral S, T Value) {
81 if (!Result && Str.endswith(S)) {
82 Result = std::move(Value);
8983 }
9084 return *this;
9185 }
9286
93 template
94 LLVM_ATTRIBUTE_ALWAYS_INLINE
95 StringSwitch& StartsWith(const char (&S)[N], const T &Value) {
96 assert(N);
97 if (!Result && Str.size() >= N-1 &&
98 (N == 1 || std::memcmp(S, Str.data(), N-1) == 0)) {
99 Result = &Value;
87 LLVM_ATTRIBUTE_ALWAYS_INLINE
88 StringSwitch& StartsWith(StringLiteral S, T Value) {
89 if (!Result && Str.startswith(S)) {
90 Result = std::move(Value);
10091 }
10192 return *this;
10293 }
10394
104 template
105 LLVM_ATTRIBUTE_ALWAYS_INLINE
106 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
107 const T& Value) {
95 LLVM_ATTRIBUTE_ALWAYS_INLINE
96 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, T Value) {
10897 return Case(S0, Value).Case(S1, Value);
10998 }
11099
111 template
112 LLVM_ATTRIBUTE_ALWAYS_INLINE
113 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
114 const char (&S2)[N2], const T& Value) {
100 LLVM_ATTRIBUTE_ALWAYS_INLINE
101 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
102 T Value) {
115103 return Case(S0, Value).Cases(S1, S2, Value);
116104 }
117105
118 template
119 LLVM_ATTRIBUTE_ALWAYS_INLINE
120 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
121 const char (&S2)[N2], const char (&S3)[N3],
122 const T& Value) {
106 LLVM_ATTRIBUTE_ALWAYS_INLINE
107 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
108 StringLiteral S3, T Value) {
123109 return Case(S0, Value).Cases(S1, S2, S3, Value);
124110 }
125111
126 template
127 LLVM_ATTRIBUTE_ALWAYS_INLINE
128 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
129 const char (&S2)[N2], const char (&S3)[N3],
130 const char (&S4)[N4], const T& Value) {
112 LLVM_ATTRIBUTE_ALWAYS_INLINE
113 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
114 StringLiteral S3, StringLiteral S4, T Value) {
131115 return Case(S0, Value).Cases(S1, S2, S3, S4, Value);
132116 }
133117
134 template
135 unsigned N5>
136 LLVM_ATTRIBUTE_ALWAYS_INLINE
137 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
138 const char (&S2)[N2], const char (&S3)[N3],
139 const char (&S4)[N4], const char (&S5)[N5],
140 const T &Value) {
118 LLVM_ATTRIBUTE_ALWAYS_INLINE
119 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
120 StringLiteral S3, StringLiteral S4, StringLiteral S5,
121 T Value) {
141122 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, Value);
142123 }
143124
144 template
145 unsigned N5, unsigned N6>
146 LLVM_ATTRIBUTE_ALWAYS_INLINE
147 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
148 const char (&S2)[N2], const char (&S3)[N3],
149 const char (&S4)[N4], const char (&S5)[N5],
150 const char (&S6)[N6], const T &Value) {
125 LLVM_ATTRIBUTE_ALWAYS_INLINE
126 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
127 StringLiteral S3, StringLiteral S4, StringLiteral S5,
128 StringLiteral S6, T Value) {
151129 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, Value);
152130 }
153131
154 template
155 unsigned N5, unsigned N6, unsigned N7>
156 LLVM_ATTRIBUTE_ALWAYS_INLINE
157 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
158 const char (&S2)[N2], const char (&S3)[N3],
159 const char (&S4)[N4], const char (&S5)[N5],
160 const char (&S6)[N6], const char (&S7)[N7],
161 const T &Value) {
132 LLVM_ATTRIBUTE_ALWAYS_INLINE
133 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
134 StringLiteral S3, StringLiteral S4, StringLiteral S5,
135 StringLiteral S6, StringLiteral S7, T Value) {
162136 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, Value);
163137 }
164138
165 template
166 unsigned N5, unsigned N6, unsigned N7, unsigned N8>
167 LLVM_ATTRIBUTE_ALWAYS_INLINE
168 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
169 const char (&S2)[N2], const char (&S3)[N3],
170 const char (&S4)[N4], const char (&S5)[N5],
171 const char (&S6)[N6], const char (&S7)[N7],
172 const char (&S8)[N8], const T &Value) {
139 LLVM_ATTRIBUTE_ALWAYS_INLINE
140 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
141 StringLiteral S3, StringLiteral S4, StringLiteral S5,
142 StringLiteral S6, StringLiteral S7, StringLiteral S8,
143 T Value) {
173144 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, Value);
174145 }
175146
176 template
177 unsigned N5, unsigned N6, unsigned N7, unsigned N8, unsigned N9>
178 LLVM_ATTRIBUTE_ALWAYS_INLINE
179 StringSwitch &Cases(const char (&S0)[N0], const char (&S1)[N1],
180 const char (&S2)[N2], const char (&S3)[N3],
181 const char (&S4)[N4], const char (&S5)[N5],
182 const char (&S6)[N6], const char (&S7)[N7],
183 const char (&S8)[N8], const char (&S9)[N9],
184 const T &Value) {
147 LLVM_ATTRIBUTE_ALWAYS_INLINE
148 StringSwitch &Cases(StringLiteral S0, StringLiteral S1, StringLiteral S2,
149 StringLiteral S3, StringLiteral S4, StringLiteral S5,
150 StringLiteral S6, StringLiteral S7, StringLiteral S8,
151 StringLiteral S9, T Value) {
185152 return Case(S0, Value).Cases(S1, S2, S3, S4, S5, S6, S7, S8, S9, Value);
186153 }
187154
188155 // Case-insensitive case matchers.
189 template
190 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &CaseLower(const char (&S)[N],
191 const T &Value) {
192 if (!Result && Str.equals_lower(StringRef(S, N - 1)))
193 Result = &Value;
194
195 return *this;
196 }
197
198 template
199 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &EndsWithLower(const char (&S)[N],
200 const T &Value) {
201 if (!Result && Str.endswith_lower(StringRef(S, N - 1)))
202 Result = &Value;
203
204 return *this;
205 }
206
207 template
208 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &StartsWithLower(const char (&S)[N],
209 const T &Value) {
210 if (!Result && Str.startswith_lower(StringRef(S, N - 1)))
211 Result = &Value;
212
213 return *this;
214 }
215 template
216 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
217 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const T &Value) {
156 LLVM_ATTRIBUTE_ALWAYS_INLINE
157 StringSwitch &CaseLower(StringLiteral S, T Value) {
158 if (!Result && Str.equals_lower(S))
159 Result = std::move(Value);
160
161 return *this;
162 }
163
164 LLVM_ATTRIBUTE_ALWAYS_INLINE
165 StringSwitch &EndsWithLower(StringLiteral S, T Value) {
166 if (!Result && Str.endswith_lower(S))
167 Result = Value;
168
169 return *this;
170 }
171
172 LLVM_ATTRIBUTE_ALWAYS_INLINE
173 StringSwitch &StartsWithLower(StringLiteral S, T Value) {
174 if (!Result && Str.startswith_lower(S))
175 Result = std::move(Value);
176
177 return *this;
178 }
179
180 LLVM_ATTRIBUTE_ALWAYS_INLINE
181 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, T Value) {
218182 return CaseLower(S0, Value).CaseLower(S1, Value);
219183 }
220184
221 template
222 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
223 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
224 const T &Value) {
185 LLVM_ATTRIBUTE_ALWAYS_INLINE
186 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
187 T Value) {
225188 return CaseLower(S0, Value).CasesLower(S1, S2, Value);
226189 }
227190
228 template
229 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
230 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
231 const char (&S3)[N3], const T &Value) {
191 LLVM_ATTRIBUTE_ALWAYS_INLINE
192 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
193 StringLiteral S3, T Value) {
232194 return CaseLower(S0, Value).CasesLower(S1, S2, S3, Value);
233195 }
234196
235 template
236 LLVM_ATTRIBUTE_ALWAYS_INLINE StringSwitch &
237 CasesLower(const char (&S0)[N0], const char (&S1)[N1], const char (&S2)[N2],
238 const char (&S3)[N3], const char (&S4)[N4], const T &Value) {
197 LLVM_ATTRIBUTE_ALWAYS_INLINE
198 StringSwitch &CasesLower(StringLiteral S0, StringLiteral S1, StringLiteral S2,
199 StringLiteral S3, StringLiteral S4, T Value) {
239200 return CaseLower(S0, Value).CasesLower(S1, S2, S3, S4, Value);
240201 }
241202
242 LLVM_ATTRIBUTE_ALWAYS_INLINE
243 R Default(const T &Value) const {
203 LLVM_NODISCARD
204 LLVM_ATTRIBUTE_ALWAYS_INLINE
205 R Default(T Value) {
244206 if (Result)
245 return *Result;
207 return std::move(*Result);
246208 return Value;
247209 }
248210
249 LLVM_ATTRIBUTE_ALWAYS_INLINE
250 operator R() const {
211 LLVM_NODISCARD
212 LLVM_ATTRIBUTE_ALWAYS_INLINE
213 operator R() {
251214 assert(Result && "Fell off the end of a string-switch");
252 return *Result;
215 return std::move(*Result);
253216 }
254217 };
255218
157157
158158 auto Translate = [](StringRef S) {
159159 return llvm::StringSwitch(S)
160 .Cases("wind\0ws", "win32", "winnt", OSType::Windows)
160 .Cases(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt",
161 OSType::Windows)
161162 .Cases("linux", "unix", "*nix", "posix", OSType::Linux)
162163 .Default(OSType::Unknown);
163164 };
183184
184185 auto Translate = [](StringRef S) {
185186 return llvm::StringSwitch(S)
186 .CasesLower("wind\0ws", "win32", "winnt", OSType::Windows)
187 .CasesLower(StringLiteral::withInnerNUL("wind\0ws"), "win32", "winnt",
188 OSType::Windows)
187189 .CasesLower("linux", "unix", "*nix", "posix", OSType::Linux)
188190 .Default(OSType::Unknown);
189191 };