File indexing completed on 2026-05-10 08:43:10
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef LLVM_ADT_STRINGREF_H
0010 #define LLVM_ADT_STRINGREF_H
0011
0012 #include "llvm/ADT/DenseMapInfo.h"
0013 #include "llvm/ADT/STLFunctionalExtras.h"
0014 #include "llvm/ADT/iterator_range.h"
0015 #include "llvm/Support/Compiler.h"
0016 #include <algorithm>
0017 #include <cassert>
0018 #include <cstddef>
0019 #include <cstring>
0020 #include <iterator>
0021 #include <limits>
0022 #include <string>
0023 #include <string_view>
0024 #include <type_traits>
0025 #include <utility>
0026
0027 namespace llvm {
0028
0029 class APInt;
0030 class hash_code;
0031 template <typename T> class SmallVectorImpl;
0032 class StringRef;
0033
0034
0035 bool getAsUnsignedInteger(StringRef Str, unsigned Radix,
0036 unsigned long long &Result);
0037
0038 bool getAsSignedInteger(StringRef Str, unsigned Radix, long long &Result);
0039
0040 bool consumeUnsignedInteger(StringRef &Str, unsigned Radix,
0041 unsigned long long &Result);
0042 bool consumeSignedInteger(StringRef &Str, unsigned Radix, long long &Result);
0043
0044
0045
0046
0047
0048
0049
0050
0051 class LLVM_GSL_POINTER StringRef {
0052 public:
0053 static constexpr size_t npos = ~size_t(0);
0054
0055 using iterator = const char *;
0056 using const_iterator = const char *;
0057 using size_type = size_t;
0058 using value_type = char;
0059 using reverse_iterator = std::reverse_iterator<iterator>;
0060 using const_reverse_iterator = std::reverse_iterator<const_iterator>;
0061
0062 private:
0063
0064 const char *Data = nullptr;
0065
0066
0067 size_t Length = 0;
0068
0069
0070
0071 static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) {
0072 if (Length == 0) { return 0; }
0073 return ::memcmp(Lhs,Rhs,Length);
0074 }
0075
0076 public:
0077
0078
0079
0080
0081 StringRef() = default;
0082
0083
0084
0085 StringRef(std::nullptr_t) = delete;
0086
0087
0088 constexpr StringRef(const char *Str LLVM_LIFETIME_BOUND)
0089 : Data(Str), Length(Str ?
0090
0091 #if defined(_GLIBCXX_RELEASE) && _GLIBCXX_RELEASE < 8
0092 __builtin_strlen(Str)
0093 #else
0094 std::char_traits<char>::length(Str)
0095 #endif
0096 : 0) {
0097 }
0098
0099
0100 constexpr StringRef(const char *data LLVM_LIFETIME_BOUND,
0101 size_t length)
0102 : Data(data), Length(length) {}
0103
0104
0105 StringRef(const std::string &Str)
0106 : Data(Str.data()), Length(Str.length()) {}
0107
0108
0109 constexpr StringRef(std::string_view Str)
0110 : Data(Str.data()), Length(Str.size()) {}
0111
0112
0113
0114
0115
0116 iterator begin() const { return data(); }
0117
0118 iterator end() const { return data() + size(); }
0119
0120 reverse_iterator rbegin() const {
0121 return std::make_reverse_iterator(end());
0122 }
0123
0124 reverse_iterator rend() const {
0125 return std::make_reverse_iterator(begin());
0126 }
0127
0128 const unsigned char *bytes_begin() const {
0129 return reinterpret_cast<const unsigned char *>(begin());
0130 }
0131 const unsigned char *bytes_end() const {
0132 return reinterpret_cast<const unsigned char *>(end());
0133 }
0134 iterator_range<const unsigned char *> bytes() const {
0135 return make_range(bytes_begin(), bytes_end());
0136 }
0137
0138
0139
0140
0141
0142
0143
0144 [[nodiscard]] constexpr const char *data() const { return Data; }
0145
0146
0147 [[nodiscard]] constexpr bool empty() const { return size() == 0; }
0148
0149
0150 [[nodiscard]] constexpr size_t size() const { return Length; }
0151
0152
0153 [[nodiscard]] char front() const {
0154 assert(!empty());
0155 return data()[0];
0156 }
0157
0158
0159 [[nodiscard]] char back() const {
0160 assert(!empty());
0161 return data()[size() - 1];
0162 }
0163
0164
0165 template <typename Allocator>
0166 [[nodiscard]] StringRef copy(Allocator &A) const {
0167
0168 if (empty())
0169 return StringRef();
0170 char *S = A.template Allocate<char>(size());
0171 std::copy(begin(), end(), S);
0172 return StringRef(S, size());
0173 }
0174
0175
0176 [[nodiscard]] bool equals_insensitive(StringRef RHS) const {
0177 return size() == RHS.size() && compare_insensitive(RHS) == 0;
0178 }
0179
0180
0181
0182
0183 [[nodiscard]] int compare(StringRef RHS) const {
0184
0185 if (int Res =
0186 compareMemory(data(), RHS.data(), std::min(size(), RHS.size())))
0187 return Res < 0 ? -1 : 1;
0188
0189
0190 if (size() == RHS.size())
0191 return 0;
0192 return size() < RHS.size() ? -1 : 1;
0193 }
0194
0195
0196 [[nodiscard]] int compare_insensitive(StringRef RHS) const;
0197
0198
0199
0200 [[nodiscard]] int compare_numeric(StringRef RHS) const;
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220 [[nodiscard]] unsigned edit_distance(StringRef Other,
0221 bool AllowReplacements = true,
0222 unsigned MaxEditDistance = 0) const;
0223
0224 [[nodiscard]] unsigned
0225 edit_distance_insensitive(StringRef Other, bool AllowReplacements = true,
0226 unsigned MaxEditDistance = 0) const;
0227
0228
0229 [[nodiscard]] std::string str() const {
0230 if (!data())
0231 return std::string();
0232 return std::string(data(), size());
0233 }
0234
0235
0236
0237
0238
0239 [[nodiscard]] char operator[](size_t Index) const {
0240 assert(Index < size() && "Invalid index!");
0241 return data()[Index];
0242 }
0243
0244
0245
0246
0247
0248 template <typename T>
0249 std::enable_if_t<std::is_same<T, std::string>::value, StringRef> &
0250 operator=(T &&Str) = delete;
0251
0252
0253
0254
0255
0256 constexpr operator std::string_view() const {
0257 return std::string_view(data(), size());
0258 }
0259
0260
0261
0262
0263
0264
0265 [[nodiscard]] bool starts_with(StringRef Prefix) const {
0266 return size() >= Prefix.size() &&
0267 compareMemory(data(), Prefix.data(), Prefix.size()) == 0;
0268 }
0269 [[nodiscard]] bool starts_with(char Prefix) const {
0270 return !empty() && front() == Prefix;
0271 }
0272
0273
0274 [[nodiscard]] bool starts_with_insensitive(StringRef Prefix) const;
0275
0276
0277 [[nodiscard]] bool ends_with(StringRef Suffix) const {
0278 return size() >= Suffix.size() &&
0279 compareMemory(end() - Suffix.size(), Suffix.data(),
0280 Suffix.size()) == 0;
0281 }
0282 [[nodiscard]] bool ends_with(char Suffix) const {
0283 return !empty() && back() == Suffix;
0284 }
0285
0286
0287 [[nodiscard]] bool ends_with_insensitive(StringRef Suffix) const;
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297 [[nodiscard]] size_t find(char C, size_t From = 0) const {
0298 return std::string_view(*this).find(C, From);
0299 }
0300
0301
0302
0303
0304
0305 [[nodiscard]] size_t find_insensitive(char C, size_t From = 0) const;
0306
0307
0308
0309
0310
0311 [[nodiscard]] size_t find_if(function_ref<bool(char)> F,
0312 size_t From = 0) const {
0313 StringRef S = drop_front(From);
0314 while (!S.empty()) {
0315 if (F(S.front()))
0316 return size() - S.size();
0317 S = S.drop_front();
0318 }
0319 return npos;
0320 }
0321
0322
0323
0324
0325
0326 [[nodiscard]] size_t find_if_not(function_ref<bool(char)> F,
0327 size_t From = 0) const {
0328 return find_if([F](char c) { return !F(c); }, From);
0329 }
0330
0331
0332
0333
0334
0335 [[nodiscard]] size_t find(StringRef Str, size_t From = 0) const;
0336
0337
0338
0339
0340
0341 [[nodiscard]] size_t find_insensitive(StringRef Str, size_t From = 0) const;
0342
0343
0344
0345
0346
0347 [[nodiscard]] size_t rfind(char C, size_t From = npos) const {
0348 size_t I = std::min(From, size());
0349 while (I) {
0350 --I;
0351 if (data()[I] == C)
0352 return I;
0353 }
0354 return npos;
0355 }
0356
0357
0358
0359
0360
0361 [[nodiscard]] size_t rfind_insensitive(char C, size_t From = npos) const;
0362
0363
0364
0365
0366
0367 [[nodiscard]] size_t rfind(StringRef Str) const;
0368
0369
0370
0371
0372
0373 [[nodiscard]] size_t rfind_insensitive(StringRef Str) const;
0374
0375
0376
0377 [[nodiscard]] size_t find_first_of(char C, size_t From = 0) const {
0378 return find(C, From);
0379 }
0380
0381
0382
0383
0384
0385 [[nodiscard]] size_t find_first_of(StringRef Chars, size_t From = 0) const;
0386
0387
0388
0389 [[nodiscard]] size_t find_first_not_of(char C, size_t From = 0) const;
0390
0391
0392
0393
0394
0395 [[nodiscard]] size_t find_first_not_of(StringRef Chars,
0396 size_t From = 0) const;
0397
0398
0399
0400 [[nodiscard]] size_t find_last_of(char C, size_t From = npos) const {
0401 return rfind(C, From);
0402 }
0403
0404
0405
0406
0407
0408 [[nodiscard]] size_t find_last_of(StringRef Chars,
0409 size_t From = npos) const;
0410
0411
0412
0413 [[nodiscard]] size_t find_last_not_of(char C, size_t From = npos) const;
0414
0415
0416
0417
0418
0419 [[nodiscard]] size_t find_last_not_of(StringRef Chars,
0420 size_t From = npos) const;
0421
0422
0423
0424 [[nodiscard]] bool contains(StringRef Other) const {
0425 return find(Other) != npos;
0426 }
0427
0428
0429
0430 [[nodiscard]] bool contains(char C) const {
0431 return find_first_of(C) != npos;
0432 }
0433
0434
0435
0436 [[nodiscard]] bool contains_insensitive(StringRef Other) const {
0437 return find_insensitive(Other) != npos;
0438 }
0439
0440
0441
0442 [[nodiscard]] bool contains_insensitive(char C) const {
0443 return find_insensitive(C) != npos;
0444 }
0445
0446
0447
0448
0449
0450
0451 [[nodiscard]] size_t count(char C) const {
0452 size_t Count = 0;
0453 for (size_t I = 0; I != size(); ++I)
0454 if (data()[I] == C)
0455 ++Count;
0456 return Count;
0457 }
0458
0459
0460
0461 size_t count(StringRef Str) const;
0462
0463
0464
0465
0466
0467
0468
0469
0470 template <typename T> bool getAsInteger(unsigned Radix, T &Result) const {
0471 if constexpr (std::numeric_limits<T>::is_signed) {
0472 long long LLVal;
0473 if (getAsSignedInteger(*this, Radix, LLVal) ||
0474 static_cast<T>(LLVal) != LLVal)
0475 return true;
0476 Result = LLVal;
0477 } else {
0478 unsigned long long ULLVal;
0479
0480
0481
0482 if (getAsUnsignedInteger(*this, Radix, ULLVal) ||
0483 static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
0484 return true;
0485 Result = ULLVal;
0486 }
0487 return false;
0488 }
0489
0490
0491
0492
0493
0494
0495
0496
0497
0498
0499 template <typename T> bool consumeInteger(unsigned Radix, T &Result) {
0500 if constexpr (std::numeric_limits<T>::is_signed) {
0501 long long LLVal;
0502 if (consumeSignedInteger(*this, Radix, LLVal) ||
0503 static_cast<long long>(static_cast<T>(LLVal)) != LLVal)
0504 return true;
0505 Result = LLVal;
0506 } else {
0507 unsigned long long ULLVal;
0508 if (consumeUnsignedInteger(*this, Radix, ULLVal) ||
0509 static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal)
0510 return true;
0511 Result = ULLVal;
0512 }
0513 return false;
0514 }
0515
0516
0517
0518
0519
0520
0521
0522
0523
0524
0525
0526 bool getAsInteger(unsigned Radix, APInt &Result) const;
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537 bool consumeInteger(unsigned Radix, APInt &Result);
0538
0539
0540
0541
0542
0543
0544
0545
0546 bool getAsDouble(double &Result, bool AllowInexact = true) const;
0547
0548
0549
0550
0551
0552
0553 [[nodiscard]] std::string lower() const;
0554
0555
0556 [[nodiscard]] std::string upper() const;
0557
0558
0559
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571 [[nodiscard]] constexpr StringRef substr(size_t Start,
0572 size_t N = npos) const {
0573 Start = std::min(Start, size());
0574 return StringRef(data() + Start, std::min(N, size() - Start));
0575 }
0576
0577
0578
0579
0580 [[nodiscard]] StringRef take_front(size_t N = 1) const {
0581 if (N >= size())
0582 return *this;
0583 return drop_back(size() - N);
0584 }
0585
0586
0587
0588
0589 [[nodiscard]] StringRef take_back(size_t N = 1) const {
0590 if (N >= size())
0591 return *this;
0592 return drop_front(size() - N);
0593 }
0594
0595
0596
0597 [[nodiscard]] StringRef take_while(function_ref<bool(char)> F) const {
0598 return substr(0, find_if_not(F));
0599 }
0600
0601
0602
0603 [[nodiscard]] StringRef take_until(function_ref<bool(char)> F) const {
0604 return substr(0, find_if(F));
0605 }
0606
0607
0608
0609 [[nodiscard]] StringRef drop_front(size_t N = 1) const {
0610 assert(size() >= N && "Dropping more elements than exist");
0611 return substr(N);
0612 }
0613
0614
0615
0616 [[nodiscard]] StringRef drop_back(size_t N = 1) const {
0617 assert(size() >= N && "Dropping more elements than exist");
0618 return substr(0, size()-N);
0619 }
0620
0621
0622
0623 [[nodiscard]] StringRef drop_while(function_ref<bool(char)> F) const {
0624 return substr(find_if_not(F));
0625 }
0626
0627
0628
0629 [[nodiscard]] StringRef drop_until(function_ref<bool(char)> F) const {
0630 return substr(find_if(F));
0631 }
0632
0633
0634
0635 bool consume_front(StringRef Prefix) {
0636 if (!starts_with(Prefix))
0637 return false;
0638
0639 *this = substr(Prefix.size());
0640 return true;
0641 }
0642
0643
0644
0645 bool consume_front_insensitive(StringRef Prefix) {
0646 if (!starts_with_insensitive(Prefix))
0647 return false;
0648
0649 *this = substr(Prefix.size());
0650 return true;
0651 }
0652
0653
0654
0655 bool consume_back(StringRef Suffix) {
0656 if (!ends_with(Suffix))
0657 return false;
0658
0659 *this = substr(0, size() - Suffix.size());
0660 return true;
0661 }
0662
0663
0664
0665 bool consume_back_insensitive(StringRef Suffix) {
0666 if (!ends_with_insensitive(Suffix))
0667 return false;
0668
0669 *this = substr(0, size() - Suffix.size());
0670 return true;
0671 }
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684 [[nodiscard]] StringRef slice(size_t Start, size_t End) const {
0685 Start = std::min(Start, size());
0686 End = std::clamp(End, Start, size());
0687 return StringRef(data() + Start, End - Start);
0688 }
0689
0690
0691
0692
0693
0694
0695
0696
0697
0698
0699
0700 [[nodiscard]] std::pair<StringRef, StringRef> split(char Separator) const {
0701 return split(StringRef(&Separator, 1));
0702 }
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713
0714 [[nodiscard]] std::pair<StringRef, StringRef>
0715 split(StringRef Separator) const {
0716 size_t Idx = find(Separator);
0717 if (Idx == npos)
0718 return std::make_pair(*this, StringRef());
0719 return std::make_pair(slice(0, Idx), substr(Idx + Separator.size()));
0720 }
0721
0722
0723
0724
0725
0726
0727
0728
0729
0730
0731
0732 [[nodiscard]] std::pair<StringRef, StringRef>
0733 rsplit(StringRef Separator) const {
0734 size_t Idx = rfind(Separator);
0735 if (Idx == npos)
0736 return std::make_pair(*this, StringRef());
0737 return std::make_pair(slice(0, Idx), substr(Idx + Separator.size()));
0738 }
0739
0740
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754 void split(SmallVectorImpl<StringRef> &A,
0755 StringRef Separator, int MaxSplit = -1,
0756 bool KeepEmpty = true) const;
0757
0758
0759
0760
0761
0762
0763
0764
0765
0766
0767
0768
0769
0770
0771
0772 void split(SmallVectorImpl<StringRef> &A, char Separator, int MaxSplit = -1,
0773 bool KeepEmpty = true) const;
0774
0775
0776
0777
0778
0779
0780
0781
0782
0783
0784
0785 [[nodiscard]] std::pair<StringRef, StringRef> rsplit(char Separator) const {
0786 return rsplit(StringRef(&Separator, 1));
0787 }
0788
0789
0790
0791 [[nodiscard]] StringRef ltrim(char Char) const {
0792 return drop_front(std::min(size(), find_first_not_of(Char)));
0793 }
0794
0795
0796
0797 [[nodiscard]] StringRef ltrim(StringRef Chars = " \t\n\v\f\r") const {
0798 return drop_front(std::min(size(), find_first_not_of(Chars)));
0799 }
0800
0801
0802
0803 [[nodiscard]] StringRef rtrim(char Char) const {
0804 return drop_back(size() - std::min(size(), find_last_not_of(Char) + 1));
0805 }
0806
0807
0808
0809 [[nodiscard]] StringRef rtrim(StringRef Chars = " \t\n\v\f\r") const {
0810 return drop_back(size() - std::min(size(), find_last_not_of(Chars) + 1));
0811 }
0812
0813
0814
0815 [[nodiscard]] StringRef trim(char Char) const {
0816 return ltrim(Char).rtrim(Char);
0817 }
0818
0819
0820
0821 [[nodiscard]] StringRef trim(StringRef Chars = " \t\n\v\f\r") const {
0822 return ltrim(Chars).rtrim(Chars);
0823 }
0824
0825
0826
0827
0828
0829
0830
0831 [[nodiscard]] StringRef detectEOL() const {
0832 size_t Pos = find('\r');
0833 if (Pos == npos) {
0834
0835 return "\n";
0836 }
0837 if (Pos + 1 < size() && data()[Pos + 1] == '\n')
0838 return "\r\n";
0839 if (Pos > 0 && data()[Pos - 1] == '\n')
0840 return "\n\r";
0841 return "\r";
0842 }
0843
0844 };
0845
0846
0847
0848
0849
0850
0851
0852
0853 class StringLiteral : public StringRef {
0854 private:
0855 constexpr StringLiteral(const char *Str, size_t N) : StringRef(Str, N) {
0856 }
0857
0858 public:
0859 template <size_t N>
0860 constexpr StringLiteral(const char (&Str)[N])
0861 #if defined(__clang__) && __has_attribute(enable_if)
0862 #pragma clang diagnostic push
0863 #pragma clang diagnostic ignored "-Wgcc-compat"
0864 __attribute((enable_if(__builtin_strlen(Str) == N - 1,
0865 "invalid string literal")))
0866 #pragma clang diagnostic pop
0867 #endif
0868 : StringRef(Str, N - 1) {
0869 }
0870
0871
0872 template <size_t N>
0873 static constexpr StringLiteral withInnerNUL(const char (&Str)[N]) {
0874 return StringLiteral(Str, N - 1);
0875 }
0876 };
0877
0878
0879
0880
0881 inline bool operator==(StringRef LHS, StringRef RHS) {
0882 if (LHS.size() != RHS.size())
0883 return false;
0884 if (LHS.empty())
0885 return true;
0886 return ::memcmp(LHS.data(), RHS.data(), LHS.size()) == 0;
0887 }
0888
0889 inline bool operator!=(StringRef LHS, StringRef RHS) { return !(LHS == RHS); }
0890
0891 inline bool operator<(StringRef LHS, StringRef RHS) {
0892 return LHS.compare(RHS) < 0;
0893 }
0894
0895 inline bool operator<=(StringRef LHS, StringRef RHS) {
0896 return LHS.compare(RHS) <= 0;
0897 }
0898
0899 inline bool operator>(StringRef LHS, StringRef RHS) {
0900 return LHS.compare(RHS) > 0;
0901 }
0902
0903 inline bool operator>=(StringRef LHS, StringRef RHS) {
0904 return LHS.compare(RHS) >= 0;
0905 }
0906
0907 inline std::string &operator+=(std::string &buffer, StringRef string) {
0908 return buffer.append(string.data(), string.size());
0909 }
0910
0911
0912
0913
0914 [[nodiscard]] hash_code hash_value(StringRef S);
0915
0916
0917 template <> struct DenseMapInfo<StringRef, void> {
0918 static inline StringRef getEmptyKey() {
0919 return StringRef(
0920 reinterpret_cast<const char *>(~static_cast<uintptr_t>(0)), 0);
0921 }
0922
0923 static inline StringRef getTombstoneKey() {
0924 return StringRef(
0925 reinterpret_cast<const char *>(~static_cast<uintptr_t>(1)), 0);
0926 }
0927
0928 static unsigned getHashValue(StringRef Val);
0929
0930 static bool isEqual(StringRef LHS, StringRef RHS) {
0931 if (RHS.data() == getEmptyKey().data())
0932 return LHS.data() == getEmptyKey().data();
0933 if (RHS.data() == getTombstoneKey().data())
0934 return LHS.data() == getTombstoneKey().data();
0935 return LHS == RHS;
0936 }
0937 };
0938
0939 }
0940
0941 #endif