1 //===-- Standalone implementation std::string_view --------------*- C++ -*-===// 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 9 #ifndef LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H 10 #define LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H 11 12 #include <stddef.h> 13 14 namespace __llvm_libc { 15 namespace cpp { 16 17 // This is very simple alternate of the std::string_view class. There is no 18 // bounds check performed in any of the methods. The callers are expected to 19 // do the checks before invoking the methods. 20 // 21 // This class will be extended as needed in future. 22 class StringView { 23 private: 24 const char *Data; 25 size_t Len; 26 27 static size_t min(size_t A, size_t B) { return A <= B ? A : B; } 28 29 static int compareMemory(const char *Lhs, const char *Rhs, size_t Length) { 30 for (size_t I = 0; I < Length; ++I) 31 if (int Diff = (int)Lhs[I] - (int)Rhs[I]) 32 return Diff; 33 return 0; 34 } 35 36 public: 37 // special value equal to the maximum value representable by the type 38 // size_type. 39 static constexpr size_t npos = -1; 40 41 StringView() : Data(nullptr), Len(0) {} 42 43 // Assumes Str is a null-terminated string. The length of the string does 44 // not include the terminating null character. 45 explicit StringView(const char *Str) : Data(Str), Len(0) { 46 if (Str == nullptr) 47 return; 48 for (const char *D = Data; *D != '\0'; ++D, ++Len) 49 ; 50 if (Len == 0) 51 Data = nullptr; 52 } 53 54 explicit StringView(const char *Str, size_t N) 55 : Data(N ? Str : nullptr), Len(Str == nullptr ? 0 : N) {} 56 57 // Ctor for raw literal. 58 template <size_t N> 59 StringView(const char (&Str)[N]) : StringView(Str, N - 1) {} 60 61 const char *data() const { return Data; } 62 63 // Returns the size of the StringView. 64 size_t size() const { return Len; } 65 66 // Returns whether the StringView is empty. 67 bool empty() const { return Len == 0; } 68 69 // Returns an iterator to the first character of the view. 70 const char *begin() const { return Data; } 71 72 // Returns an iterator to the character following the last character of the 73 // view. 74 const char *end() const { return Data + Len; } 75 76 // Returns a const reference to the character at specified location pos. 77 // No bounds checking is performed: the behavior is undefined if pos >= 78 // size(). 79 const char &operator[](size_t Index) const { return Data[Index]; } 80 81 /// compare - Compare two strings; the result is -1, 0, or 1 if this string 82 /// is lexicographically less than, equal to, or greater than the \p Other. 83 int compare(StringView Other) const { 84 // Check the prefix for a mismatch. 85 if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len))) 86 return Res < 0 ? -1 : 1; 87 // Otherwise the prefixes match, so we only need to check the lengths. 88 if (Len == Other.Len) 89 return 0; 90 return Len < Other.Len ? -1 : 1; 91 } 92 93 // An equivalent method is not available in std::string_view. 94 bool equals(StringView Other) const { 95 return (Len == Other.Len && 96 compareMemory(Data, Other.Data, Other.Len) == 0); 97 } 98 99 inline bool operator==(StringView Other) const { return equals(Other); } 100 inline bool operator!=(StringView Other) const { return !(*this == Other); } 101 inline bool operator<(StringView Other) const { return compare(Other) == -1; } 102 inline bool operator<=(StringView Other) const { return compare(Other) != 1; } 103 inline bool operator>(StringView Other) const { return compare(Other) == 1; } 104 inline bool operator>=(StringView Other) const { 105 return compare(Other) != -1; 106 } 107 108 // Moves the start of the view forward by n characters. 109 // The behavior is undefined if n > size(). 110 void remove_prefix(size_t N) { 111 Len -= N; 112 Data += N; 113 } 114 115 // Moves the end of the view back by n characters. 116 // The behavior is undefined if n > size(). 117 void remove_suffix(size_t N) { Len -= N; } 118 119 // An equivalent method is not available in std::string_view. 120 StringView trim(const char C) const { 121 StringView Copy = *this; 122 while (Copy.starts_with(C)) 123 Copy = Copy.drop_front(); 124 while (Copy.ends_with(C)) 125 Copy = Copy.drop_back(); 126 return Copy; 127 } 128 129 // Check if this string starts with the given Prefix. 130 bool starts_with(StringView Prefix) const { 131 return Len >= Prefix.Len && 132 compareMemory(Data, Prefix.Data, Prefix.Len) == 0; 133 } 134 135 // Check if this string starts with the given Prefix. 136 bool starts_with(const char Prefix) const { 137 return !empty() && front() == Prefix; 138 } 139 140 // Check if this string ends with the given Prefix. 141 bool ends_with(const char Suffix) const { 142 return !empty() && back() == Suffix; 143 } 144 145 // Check if this string ends with the given Suffix. 146 bool ends_with(StringView Suffix) const { 147 return Len >= Suffix.Len && 148 compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; 149 } 150 151 // Return a reference to the substring from [Start, Start + N). 152 // 153 // Start The index of the starting character in the substring; if the index is 154 // npos or greater than the length of the string then the empty substring will 155 // be returned. 156 // 157 // N The number of characters to included in the substring. If N exceeds the 158 // number of characters remaining in the string, the string suffix (starting 159 // with Start) will be returned. 160 StringView substr(size_t Start, size_t N = npos) const { 161 Start = min(Start, Len); 162 return StringView(Data + Start, min(N, Len - Start)); 163 } 164 165 // Search for the first character matching the character 166 // 167 // Returns The index of the first character satisfying the character starting 168 // from From, or npos if not found. 169 size_t find_first_of(const char c, size_t From = 0) const noexcept { 170 StringView S = drop_front(From); 171 while (!S.empty()) { 172 if (S.front() == c) 173 return size() - S.size(); 174 S = S.drop_front(); 175 } 176 return npos; 177 } 178 179 // Search for the last character matching the character 180 // 181 // Return the index of the last character equal to the |c| before End. 182 size_t find_last_of(const char c, size_t End = npos) const { 183 End = End > size() ? size() : End + 1; 184 StringView S = drop_back(size() - End); 185 while (!S.empty()) { 186 if (S.back() == c) 187 return S.size() - 1; 188 S = S.drop_back(); 189 } 190 return npos; 191 } 192 193 // Search for the first character satisfying the predicate Function 194 // 195 // Returns The index of the first character satisfying Function starting from 196 // From, or npos if not found. 197 template <typename F> size_t find_if(F Function, size_t From = 0) const { 198 StringView S = drop_front(From); 199 while (!S.empty()) { 200 if (Function(S.front())) 201 return size() - S.size(); 202 S = S.drop_front(); 203 } 204 return npos; 205 } 206 207 // Search for the first character not satisfying the predicate Function 208 // Returns The index of the first character not satisfying Function starting 209 // from From, or npos if not found. 210 template <typename F> size_t find_if_not(F Function, size_t From = 0) const { 211 return find_if([Function](char c) { return !Function(c); }, From); 212 } 213 214 // front - Get the first character in the string. 215 char front() const { return Data[0]; } 216 217 // back - Get the last character in the string. 218 char back() const { return Data[Len - 1]; } 219 220 // Return a StringView equal to 'this' but with the first N elements 221 // dropped. 222 StringView drop_front(size_t N = 1) const { return substr(N); } 223 224 // Return a StringView equal to 'this' but with the last N elements 225 // dropped. 226 StringView drop_back(size_t N = 1) const { return substr(0, size() - N); } 227 228 // Return a StringView equal to 'this' but with only the first N 229 // elements remaining. If N is greater than the length of the 230 // string, the entire string is returned. 231 StringView take_front(size_t N = 1) const { 232 if (N >= size()) 233 return *this; 234 return drop_back(size() - N); 235 } 236 237 // Return a StringView equal to 'this' but with only the last N 238 // elements remaining. If N is greater than the length of the 239 // string, the entire string is returned. 240 StringView take_back(size_t N = 1) const { 241 if (N >= size()) 242 return *this; 243 return drop_front(size() - N); 244 } 245 246 // Return the longest prefix of 'this' such that every character 247 // in the prefix satisfies the given predicate. 248 template <typename F> StringView take_while(F Function) const { 249 return substr(0, find_if_not(Function)); 250 } 251 252 // Return the longest prefix of 'this' such that no character in 253 // the prefix satisfies the given predicate. 254 template <typename F> StringView take_until(F Function) const { 255 return substr(0, find_if(Function)); 256 } 257 258 // Return a StringView equal to 'this', but with all characters satisfying 259 // the given predicate dropped from the beginning of the string. 260 template <typename F> StringView drop_while(F Function) const { 261 return substr(find_if_not(Function)); 262 } 263 264 // Return a StringView equal to 'this', but with all characters not 265 // satisfying the given predicate dropped from the beginning of the string. 266 template <typename F> StringView drop_until(F Function) const { 267 return substr(find_if(Function)); 268 } 269 270 // Returns true if this StringView has the given prefix and removes that 271 // prefix. 272 bool consume_front(StringView Prefix) { 273 if (!starts_with(Prefix)) 274 return false; 275 276 *this = drop_front(Prefix.size()); 277 return true; 278 } 279 280 // Returns true if this StringView has the given suffix and removes that 281 // suffix. 282 bool consume_back(StringView Suffix) { 283 if (!ends_with(Suffix)) 284 return false; 285 286 *this = drop_back(Suffix.size()); 287 return true; 288 } 289 }; 290 291 } // namespace cpp 292 } // namespace __llvm_libc 293 294 #endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H 295