|
12 | 12 |
|
13 | 13 | #include "llvm/ADT/ArrayRef.h" |
14 | 14 | #include "llvm/ADT/iterator_range.h" |
| 15 | +#include "llvm/ADT/StringRef.h" |
15 | 16 |
|
16 | 17 | namespace glow { |
17 | 18 | using llvm::iterator_range; |
@@ -108,332 +109,7 @@ inline bool operator!=(MutableArrayRef<T> LHS, MutableArrayRef<T> RHS) { |
108 | 109 | return !(LHS == RHS); |
109 | 110 | } |
110 | 111 |
|
111 | | -/// StringRef - Represent a constant reference to a string, i.e. a character |
112 | | -/// array and a length, which need not be null terminated. |
113 | | -/// |
114 | | -/// This class does not own the string data, it is expected to be used in |
115 | | -/// situations where the character data resides in some other buffer, whose |
116 | | -/// lifetime extends past that of the StringRef. For this reason, it is not in |
117 | | -/// general safe to store a StringRef. |
118 | | -class StringRef { |
119 | | -public: |
120 | | - static const size_t npos = ~size_t(0); |
121 | | - |
122 | | - using iterator = const char *; |
123 | | - using const_iterator = const char *; |
124 | | - using size_type = size_t; |
125 | | - |
126 | | -private: |
127 | | - /// The start of the string, in an external buffer. |
128 | | - const char *Data = nullptr; |
129 | | - |
130 | | - /// The length of the string. |
131 | | - size_t Length = 0; |
132 | | - |
133 | | - // Workaround memcmp issue with null pointers (undefined behavior) |
134 | | - // by providing a specialized version |
135 | | - static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) { |
136 | | - if (Length == 0) { |
137 | | - return 0; |
138 | | - } |
139 | | - return ::memcmp(Lhs, Rhs, Length); |
140 | | - } |
141 | | - |
142 | | -public: |
143 | | - /// Construct an empty string ref. |
144 | | - StringRef() = default; |
145 | | - |
146 | | - /// Disable conversion from nullptr. This prevents things like |
147 | | - /// if (S == nullptr) |
148 | | - StringRef(std::nullptr_t) = delete; |
149 | | - |
150 | | - /// Construct a string ref from a cstring. |
151 | | - StringRef(const char *Str) : Data(Str), Length(Str ? ::strlen(Str) : 0) {} |
152 | | - |
153 | | - /// Construct a string ref from a pointer and length. |
154 | | - constexpr StringRef(const char *data, size_t length) |
155 | | - : Data(data), Length(length) {} |
156 | | - |
157 | | - /// Construct a string ref from an std::string. |
158 | | - StringRef(const std::string &Str) : Data(Str.data()), Length(Str.length()) {} |
159 | | - |
160 | | - static StringRef withNullAsEmpty(const char *data) { |
161 | | - return StringRef(data ? data : ""); |
162 | | - } |
163 | | - |
164 | | - iterator begin() const { return Data; } |
165 | | - iterator end() const { return Data + Length; } |
166 | | - |
167 | | - const unsigned char *bytes_begin() const { |
168 | | - return reinterpret_cast<const unsigned char *>(begin()); |
169 | | - } |
170 | | - const unsigned char *bytes_end() const { |
171 | | - return reinterpret_cast<const unsigned char *>(end()); |
172 | | - } |
173 | | - iterator_range<const unsigned char *> bytes() const { |
174 | | - return make_range(bytes_begin(), bytes_end()); |
175 | | - } |
176 | | - |
177 | | - /// data - Get a pointer to the start of the string (which may not be null |
178 | | - /// terminated). |
179 | | - const char *data() const { return Data; } |
180 | | - |
181 | | - /// empty - Check if the string is empty. |
182 | | - bool empty() const { return Length == 0; } |
183 | | - |
184 | | - /// size - Get the string size. |
185 | | - size_t size() const { return Length; } |
186 | | - |
187 | | - /// front - Get the first character in the string. |
188 | | - char front() const { |
189 | | - assert(!empty()); |
190 | | - return Data[0]; |
191 | | - } |
192 | | - |
193 | | - /// back - Get the last character in the string. |
194 | | - char back() const { |
195 | | - assert(!empty()); |
196 | | - return Data[Length - 1]; |
197 | | - } |
198 | | - |
199 | | - // copy - Allocate copy in Allocator and return StringRef to it. |
200 | | - template <typename Allocator> StringRef copy(Allocator &A) const { |
201 | | - // Don't request a length 0 copy from the allocator. |
202 | | - if (empty()) |
203 | | - return StringRef(); |
204 | | - char *S = A.template Allocate<char>(Length); |
205 | | - std::copy(begin(), end(), S); |
206 | | - return StringRef(S, Length); |
207 | | - } |
208 | | - |
209 | | - /// equals - Check for string equality, this is more efficient than |
210 | | - /// compare() when the relative ordering of inequal strings isn't needed. |
211 | | - bool equals(StringRef RHS) const { |
212 | | - return (Length == RHS.Length && |
213 | | - compareMemory(Data, RHS.Data, RHS.Length) == 0); |
214 | | - } |
215 | | - |
216 | | - /// compare - Compare two strings; the result is -1, 0, or 1 if this string |
217 | | - /// is lexicographically less than, equal to, or greater than the \p RHS. |
218 | | - int compare(StringRef RHS) const { |
219 | | - // Check the prefix for a mismatch. |
220 | | - if (int Res = compareMemory(Data, RHS.Data, std::min(Length, RHS.Length))) |
221 | | - return Res < 0 ? -1 : 1; |
222 | | - |
223 | | - // Otherwise the prefixes match, so we only need to check the lengths. |
224 | | - if (Length == RHS.Length) |
225 | | - return 0; |
226 | | - return Length < RHS.Length ? -1 : 1; |
227 | | - } |
228 | | - |
229 | | - /// str - Get the contents as an std::string. |
230 | | - std::string str() const { |
231 | | - if (!Data) |
232 | | - return std::string(); |
233 | | - return std::string(Data, Length); |
234 | | - } |
235 | | - |
236 | | - char operator[](size_t Index) const { |
237 | | - assert(Index < Length && "Invalid index!"); |
238 | | - return Data[Index]; |
239 | | - } |
240 | | - |
241 | | - /// Disallow accidental assignment from a temporary std::string. |
242 | | - /// |
243 | | - /// The declaration here is extra complicated so that `stringRef = {}` |
244 | | - /// and `stringRef = "abc"` continue to select the move assignment operator. |
245 | | - template <typename T> |
246 | | - typename std::enable_if<std::is_same<T, std::string>::value, StringRef>::type |
247 | | - & |
248 | | - operator=(T &&Str) = delete; |
249 | | - |
250 | | - operator std::string() const { return str(); } |
251 | | - |
252 | | - /// Check if this string starts with the given \p Prefix. |
253 | | - bool startswith(StringRef Prefix) const { |
254 | | - return Length >= Prefix.Length && |
255 | | - compareMemory(Data, Prefix.Data, Prefix.Length) == 0; |
256 | | - } |
257 | | - |
258 | | - /// Check if this string ends with the given \p Suffix. |
259 | | - bool endswith(StringRef Suffix) const { |
260 | | - return Length >= Suffix.Length && |
261 | | - compareMemory(end() - Suffix.Length, Suffix.Data, Suffix.Length) == |
262 | | - 0; |
263 | | - } |
264 | | - |
265 | | - /// Search for the first character \p C in the string. |
266 | | - /// |
267 | | - /// \returns The index of the first occurrence of \p C, or npos if not |
268 | | - /// found. |
269 | | - size_t find(char C, size_t From = 0) const { |
270 | | - size_t FindBegin = std::min(From, Length); |
271 | | - if (FindBegin < Length) { // Avoid calling memchr with nullptr. |
272 | | - // Just forward to memchr, which is faster than a hand-rolled loop. |
273 | | - if (const void *P = ::memchr(Data + FindBegin, C, Length - FindBegin)) |
274 | | - return static_cast<const char *>(P) - Data; |
275 | | - } |
276 | | - return npos; |
277 | | - } |
278 | | - |
279 | | - /// Search for the last character \p C in the string. |
280 | | - /// |
281 | | - /// \returns The index of the last occurrence of \p C, or npos if not |
282 | | - /// found. |
283 | | - size_t rfind(char C, size_t From = npos) const { |
284 | | - From = std::min(From, Length); |
285 | | - size_t i = From; |
286 | | - while (i != 0) { |
287 | | - --i; |
288 | | - if (Data[i] == C) |
289 | | - return i; |
290 | | - } |
291 | | - return npos; |
292 | | - } |
293 | | - |
294 | | - /// Find the first character in the string that is \p C, or npos if not |
295 | | - /// found. Same as find. |
296 | | - size_t find_first_of(char C, size_t From = 0) const { return find(C, From); } |
297 | | - |
298 | | - /// Find the last character in the string that is \p C, or npos if not |
299 | | - /// found. |
300 | | - size_t find_last_of(char C, size_t From = npos) const { |
301 | | - return rfind(C, From); |
302 | | - } |
303 | | - |
304 | | - /// Return the number of occurrences of \p C in the string. |
305 | | - size_t count(char C) const { |
306 | | - size_t Count = 0; |
307 | | - for (size_t i = 0, e = Length; i != e; ++i) |
308 | | - if (Data[i] == C) |
309 | | - ++Count; |
310 | | - return Count; |
311 | | - } |
312 | | - |
313 | | - /// Return a reference to the substring from [Start, Start + N). |
314 | | - /// |
315 | | - /// \param Start The index of the starting character in the substring; if |
316 | | - /// the index is npos or greater than the length of the string then the |
317 | | - /// empty substring will be returned. |
318 | | - /// |
319 | | - /// \param N The number of characters to included in the substring. If N |
320 | | - /// exceeds the number of characters remaining in the string, the string |
321 | | - /// suffix (starting with \p Start) will be returned. |
322 | | - StringRef substr(size_t Start, size_t N = npos) const { |
323 | | - Start = std::min(Start, Length); |
324 | | - return StringRef(Data + Start, std::min(N, Length - Start)); |
325 | | - } |
326 | | - |
327 | | - /// Return a StringRef equal to 'this' but with only the first \p N |
328 | | - /// elements remaining. If \p N is greater than the length of the |
329 | | - /// string, the entire string is returned. |
330 | | - StringRef take_front(size_t N = 1) const { |
331 | | - if (N >= size()) |
332 | | - return *this; |
333 | | - return drop_back(size() - N); |
334 | | - } |
335 | | - |
336 | | - /// Return a StringRef equal to 'this' but with only the last \p N |
337 | | - /// elements remaining. If \p N is greater than the length of the |
338 | | - /// string, the entire string is returned. |
339 | | - StringRef take_back(size_t N = 1) const { |
340 | | - if (N >= size()) |
341 | | - return *this; |
342 | | - return drop_front(size() - N); |
343 | | - } |
344 | | - |
345 | | - /// Return a StringRef equal to 'this' but with the first \p N elements |
346 | | - /// dropped. |
347 | | - StringRef drop_front(size_t N = 1) const { |
348 | | - assert(size() >= N && "Dropping more elements than exist"); |
349 | | - return substr(N); |
350 | | - } |
351 | | - |
352 | | - /// Return a StringRef equal to 'this' but with the last \p N elements |
353 | | - /// dropped. |
354 | | - StringRef drop_back(size_t N = 1) const { |
355 | | - assert(size() >= N && "Dropping more elements than exist"); |
356 | | - return substr(0, size() - N); |
357 | | - } |
358 | | - |
359 | | - /// Returns true if this StringRef has the given prefix and removes that |
360 | | - /// prefix. |
361 | | - bool consume_front(StringRef Prefix) { |
362 | | - if (!startswith(Prefix)) |
363 | | - return false; |
364 | | - |
365 | | - *this = drop_front(Prefix.size()); |
366 | | - return true; |
367 | | - } |
368 | | - |
369 | | - /// Returns true if this StringRef has the given suffix and removes that |
370 | | - /// suffix. |
371 | | - bool consume_back(StringRef Suffix) { |
372 | | - if (!endswith(Suffix)) |
373 | | - return false; |
374 | | - |
375 | | - *this = drop_back(Suffix.size()); |
376 | | - return true; |
377 | | - } |
378 | | - |
379 | | - /// Return a reference to the substring from [Start, End). |
380 | | - /// |
381 | | - /// \param Start The index of the starting character in the substring; if |
382 | | - /// the index is npos or greater than the length of the string then the |
383 | | - /// empty substring will be returned. |
384 | | - /// |
385 | | - /// \param End The index following the last character to include in the |
386 | | - /// substring. If this is npos or exceeds the number of characters |
387 | | - /// remaining in the string, the string suffix (starting with \p Start) |
388 | | - /// will be returned. If this is less than \p Start, an empty string will |
389 | | - /// be returned. |
390 | | - StringRef slice(size_t Start, size_t End) const { |
391 | | - Start = std::min(Start, Length); |
392 | | - End = std::min(std::max(Start, End), Length); |
393 | | - return StringRef(Data + Start, End - Start); |
394 | | - } |
395 | | - |
396 | | - /// Split into two substrings around the first occurrence of a separator |
397 | | - /// character. |
398 | | - /// |
399 | | - /// If \p Separator is in the string, then the result is a pair (LHS, RHS) |
400 | | - /// such that (*this == LHS + Separator + RHS) is true and RHS is |
401 | | - /// maximal. If \p Separator is not in the string, then the result is a |
402 | | - /// pair (LHS, RHS) where (*this == LHS) and (RHS == ""). |
403 | | - /// |
404 | | - /// \param Separator The character to split on. |
405 | | - /// \returns The split substrings. |
406 | | - std::pair<StringRef, StringRef> split(char Separator) const { |
407 | | - size_t Idx = find(Separator); |
408 | | - if (Idx == npos) |
409 | | - return std::make_pair(*this, StringRef()); |
410 | | - return std::make_pair(slice(0, Idx), slice(Idx + 1, npos)); |
411 | | - } |
412 | | -}; |
413 | | - |
414 | | -inline bool operator==(StringRef LHS, StringRef RHS) { return LHS.equals(RHS); } |
415 | | - |
416 | | -inline bool operator!=(StringRef LHS, StringRef RHS) { return !(LHS == RHS); } |
417 | | - |
418 | | -inline bool operator<(StringRef LHS, StringRef RHS) { |
419 | | - return LHS.compare(RHS) == -1; |
420 | | -} |
421 | | - |
422 | | -inline bool operator<=(StringRef LHS, StringRef RHS) { |
423 | | - return LHS.compare(RHS) != 1; |
424 | | -} |
425 | | - |
426 | | -inline bool operator>(StringRef LHS, StringRef RHS) { |
427 | | - return LHS.compare(RHS) == 1; |
428 | | -} |
429 | | - |
430 | | -inline bool operator>=(StringRef LHS, StringRef RHS) { |
431 | | - return LHS.compare(RHS) != -1; |
432 | | -} |
433 | | - |
434 | | -inline std::string &operator+=(std::string &buffer, StringRef string) { |
435 | | - return buffer.append(string.data(), string.size()); |
436 | | -} |
| 112 | +using llvm::StringRef; |
437 | 113 |
|
438 | 114 | } // namespace glow |
439 | 115 |
|
|
0 commit comments