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 StringView remove_prefix(size_t N) const { 111 if (N >= Len) 112 return StringView(); 113 return StringView(Data + N, Len - N); 114 } 115 116 // Moves the end of the view back by n characters. 117 // The behavior is undefined if n > size(). 118 StringView remove_suffix(size_t N) const { 119 if (N >= Len) 120 return StringView(); 121 return StringView(Data, Len - N); 122 } 123 124 // An equivalent method is not available in std::string_view. 125 StringView trim(const char C) const { 126 StringView Copy = *this; 127 while (Copy.starts_with(C)) 128 Copy = Copy.drop_front(); 129 while (Copy.ends_with(C)) 130 Copy = Copy.drop_back(); 131 return Copy; 132 } 133 134 // Check if this string starts with the given Prefix. 135 bool starts_with(StringView Prefix) const { 136 return Len >= Prefix.Len && 137 compareMemory(Data, Prefix.Data, Prefix.Len) == 0; 138 } 139 140 // Check if this string starts with the given Prefix. 141 bool starts_with(const char Prefix) const { 142 return !empty() && front() == Prefix; 143 } 144 145 // Check if this string ends with the given Prefix. 146 bool ends_with(const char Suffix) const { 147 return !empty() && back() == Suffix; 148 } 149 150 // Check if this string ends with the given Suffix. 151 bool ends_with(StringView Suffix) const { 152 return Len >= Suffix.Len && 153 compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; 154 } 155 156 // Return a reference to the substring from [Start, Start + N). 157 // 158 // Start The index of the starting character in the substring; if the index is 159 // npos or greater than the length of the string then the empty substring will 160 // be returned. 161 // 162 // N The number of characters to included in the substring. If N exceeds the 163 // number of characters remaining in the string, the string suffix (starting 164 // with Start) will be returned. 165 StringView substr(size_t Start, size_t N = npos) const { 166 Start = min(Start, Len); 167 return StringView(Data + Start, min(N, Len - Start)); 168 } 169 170 // Search for the first character matching the character 171 // 172 // Returns The index of the first character satisfying the character starting 173 // from From, or npos if not found. 174 size_t find_first_of(const char c, size_t From = 0) const noexcept { 175 StringView S = drop_front(From); 176 while (!S.empty()) { 177 if (S.front() == c) 178 return size() - S.size(); 179 S = S.drop_front(); 180 } 181 return npos; 182 } 183 184 // Search for the first character satisfying the predicate Function 185 // 186 // Returns The index of the first character satisfying Function starting from 187 // From, or npos if not found. 188 template <typename F> size_t find_if(F Function, size_t From = 0) const { 189 StringView S = drop_front(From); 190 while (!S.empty()) { 191 if (Function(S.front())) 192 return size() - S.size(); 193 S = S.drop_front(); 194 } 195 return npos; 196 } 197 198 // Search for the first character not satisfying the predicate Function 199 // Returns The index of the first character not satisfying Function starting 200 // from From, or npos if not found. 201 template <typename F> size_t find_if_not(F Function, size_t From = 0) const { 202 return find_if([Function](char c) { return !Function(c); }, From); 203 } 204 205 // front - Get the first character in the string. 206 char front() const { return Data[0]; } 207 208 // back - Get the last character in the string. 209 char back() const { return Data[Len - 1]; } 210 211 // Return a StringView equal to 'this' but with the first N elements 212 // dropped. 213 StringView drop_front(size_t N = 1) const { return substr(N); } 214 215 // Return a StringView equal to 'this' but with the last N elements 216 // dropped. 217 StringView drop_back(size_t N = 1) const { return substr(0, size() - N); } 218 219 // Return a StringView equal to 'this' but with only the first N 220 // elements remaining. If N is greater than the length of the 221 // string, the entire string is returned. 222 StringView take_front(size_t N = 1) const { 223 if (N >= size()) 224 return *this; 225 return drop_back(size() - N); 226 } 227 228 // Return a StringView equal to 'this' but with only the last N 229 // elements remaining. If N is greater than the length of the 230 // string, the entire string is returned. 231 StringView take_back(size_t N = 1) const { 232 if (N >= size()) 233 return *this; 234 return drop_front(size() - N); 235 } 236 237 // Return the longest prefix of 'this' such that every character 238 // in the prefix satisfies the given predicate. 239 template <typename F> StringView take_while(F Function) const { 240 return substr(0, find_if_not(Function)); 241 } 242 243 // Return the longest prefix of 'this' such that no character in 244 // the prefix satisfies the given predicate. 245 template <typename F> StringView take_until(F Function) const { 246 return substr(0, find_if(Function)); 247 } 248 249 // Return a StringView equal to 'this', but with all characters satisfying 250 // the given predicate dropped from the beginning of the string. 251 template <typename F> StringView drop_while(F Function) const { 252 return substr(find_if_not(Function)); 253 } 254 255 // Return a StringView equal to 'this', but with all characters not 256 // satisfying the given predicate dropped from the beginning of the string. 257 template <typename F> StringView drop_until(F Function) const { 258 return substr(find_if(Function)); 259 } 260 261 // Returns true if this StringView has the given prefix and removes that 262 // prefix. 263 bool consume_front(StringView Prefix) { 264 if (!starts_with(Prefix)) 265 return false; 266 267 *this = drop_front(Prefix.size()); 268 return true; 269 } 270 271 // Returns true if this StringView has the given suffix and removes that 272 // suffix. 273 bool consume_back(StringView Suffix) { 274 if (!ends_with(Suffix)) 275 return false; 276 277 *this = drop_back(Suffix.size()); 278 return true; 279 } 280 }; 281 282 } // namespace cpp 283 } // namespace __llvm_libc 284 285 #endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H 286