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_STRING_VIEW_H 10 #define LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H 11 12 #include "limits.h" 13 #include "src/__support/common.h" 14 #include "src/__support/macros/config.h" 15 16 #include <stddef.h> 17 18 namespace LIBC_NAMESPACE_DECL { 19 namespace cpp { 20 21 // This is very simple alternate of the std::string_view class. There is no 22 // bounds check performed in any of the methods. The callers are expected to 23 // do the checks before invoking the methods. 24 // 25 // This class will be extended as needed in future. 26 class string_view { 27 private: 28 const char *Data; 29 size_t Len; 30 min(size_t A,size_t B)31 LIBC_INLINE static size_t min(size_t A, size_t B) { return A <= B ? A : B; } 32 compareMemory(const char * Lhs,const char * Rhs,size_t Length)33 LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs, 34 size_t Length) { 35 for (size_t i = 0; i < Length; ++i) 36 if (int Diff = (int)Lhs[i] - (int)Rhs[i]) 37 return Diff; 38 return 0; 39 } 40 length(const char * Str)41 LIBC_INLINE static constexpr size_t length(const char *Str) { 42 for (const char *End = Str;; ++End) 43 if (*End == '\0') 44 return static_cast<size_t>(End - Str); 45 } 46 equals(string_view Other)47 LIBC_INLINE bool equals(string_view Other) const { 48 return (Len == Other.Len && 49 compareMemory(Data, Other.Data, Other.Len) == 0); 50 } 51 52 public: 53 using value_type = char; 54 using size_type = size_t; 55 using difference_type = ptrdiff_t; 56 using pointer = char *; 57 using const_pointer = const char *; 58 using reference = char &; 59 using const_reference = const char &; 60 using const_iterator = char *; 61 using iterator = const_iterator; 62 63 // special value equal to the maximum value representable by the type 64 // size_type. 65 LIBC_INLINE_VAR static constexpr size_t npos = 66 cpp::numeric_limits<size_t>::max(); 67 string_view()68 LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {} 69 70 // Assumes Str is a null-terminated string. The length of the string does 71 // not include the terminating null character. 72 // Preconditions: [Str, Str + length(Str)) is a valid range. string_view(const char * Str)73 LIBC_INLINE constexpr string_view(const char *Str) 74 : Data(Str), Len(length(Str)) {} 75 76 // Preconditions: [Str, Str + N) is a valid range. string_view(const char * Str,size_t N)77 LIBC_INLINE constexpr string_view(const char *Str, size_t N) 78 : Data(Str), Len(N) {} 79 data()80 LIBC_INLINE constexpr const char *data() const { return Data; } 81 82 // Returns the size of the string_view. size()83 LIBC_INLINE constexpr size_t size() const { return Len; } 84 85 // Returns whether the string_view is empty. empty()86 LIBC_INLINE constexpr bool empty() const { return Len == 0; } 87 88 // Returns an iterator to the first character of the view. begin()89 LIBC_INLINE const char *begin() const { return Data; } 90 91 // Returns an iterator to the character following the last character of the 92 // view. end()93 LIBC_INLINE const char *end() const { return Data + Len; } 94 95 // Returns a const reference to the character at specified location pos. 96 // No bounds checking is performed: the behavior is undefined if pos >= 97 // size(). 98 LIBC_INLINE constexpr const char &operator[](size_t Index) const { 99 return Data[Index]; 100 } 101 102 /// compare - Compare two strings; the result is -1, 0, or 1 if this string 103 /// is lexicographically less than, equal to, or greater than the \p Other. compare(string_view Other)104 LIBC_INLINE int compare(string_view Other) const { 105 // Check the prefix for a mismatch. 106 if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len))) 107 return Res < 0 ? -1 : 1; 108 // Otherwise the prefixes match, so we only need to check the lengths. 109 if (Len == Other.Len) 110 return 0; 111 return Len < Other.Len ? -1 : 1; 112 } 113 114 LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); } 115 LIBC_INLINE bool operator!=(string_view Other) const { 116 return !(*this == Other); 117 } 118 LIBC_INLINE bool operator<(string_view Other) const { 119 return compare(Other) == -1; 120 } 121 LIBC_INLINE bool operator<=(string_view Other) const { 122 return compare(Other) != 1; 123 } 124 LIBC_INLINE bool operator>(string_view Other) const { 125 return compare(Other) == 1; 126 } 127 LIBC_INLINE bool operator>=(string_view Other) const { 128 return compare(Other) != -1; 129 } 130 131 // Moves the start of the view forward by n characters. 132 // The behavior is undefined if n > size(). remove_prefix(size_t N)133 LIBC_INLINE void remove_prefix(size_t N) { 134 Len -= N; 135 Data += N; 136 } 137 138 // Moves the end of the view back by n characters. 139 // The behavior is undefined if n > size(). remove_suffix(size_t N)140 LIBC_INLINE void remove_suffix(size_t N) { Len -= N; } 141 142 // Check if this string starts with the given Prefix. starts_with(string_view Prefix)143 LIBC_INLINE bool starts_with(string_view Prefix) const { 144 return Len >= Prefix.Len && 145 compareMemory(Data, Prefix.Data, Prefix.Len) == 0; 146 } 147 148 // Check if this string starts with the given Prefix. starts_with(const char Prefix)149 LIBC_INLINE bool starts_with(const char Prefix) const { 150 return !empty() && front() == Prefix; 151 } 152 153 // Check if this string ends with the given Prefix. ends_with(const char Suffix)154 LIBC_INLINE bool ends_with(const char Suffix) const { 155 return !empty() && back() == Suffix; 156 } 157 158 // Check if this string ends with the given Suffix. ends_with(string_view Suffix)159 LIBC_INLINE bool ends_with(string_view Suffix) const { 160 return Len >= Suffix.Len && 161 compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0; 162 } 163 164 // Return a reference to the substring from [Start, Start + N). 165 // 166 // Start The index of the starting character in the substring; if the index is 167 // npos or greater than the length of the string then the empty substring will 168 // be returned. 169 // 170 // N The number of characters to included in the substring. If N exceeds the 171 // number of characters remaining in the string, the string suffix (starting 172 // with Start) will be returned. 173 LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const { 174 Start = min(Start, Len); 175 return string_view(Data + Start, min(N, Len - Start)); 176 } 177 178 // front - Get the first character in the string. front()179 LIBC_INLINE char front() const { return Data[0]; } 180 181 // back - Get the last character in the string. back()182 LIBC_INLINE char back() const { return Data[Len - 1]; } 183 184 // Finds the first occurence of c in this view, starting at position From. 185 LIBC_INLINE constexpr size_t find_first_of(const char c, 186 size_t From = 0) const { 187 for (size_t Pos = From; Pos < size(); ++Pos) 188 if ((*this)[Pos] == c) 189 return Pos; 190 return npos; 191 } 192 193 // Finds the last occurence of c in this view, ending at position End. 194 LIBC_INLINE constexpr size_t find_last_of(const char c, 195 size_t End = npos) const { 196 End = End >= size() ? size() : End + 1; 197 for (; End > 0; --End) 198 if ((*this)[End - 1] == c) 199 return End - 1; 200 return npos; 201 } 202 203 // Finds the first character not equal to c in this view, starting at position 204 // From. 205 LIBC_INLINE constexpr size_t find_first_not_of(const char c, 206 size_t From = 0) const { 207 for (size_t Pos = From; Pos < size(); ++Pos) 208 if ((*this)[Pos] != c) 209 return Pos; 210 return npos; 211 } 212 213 // Check if this view contains the given character. contains(char c)214 LIBC_INLINE constexpr bool contains(char c) const { 215 return find_first_of(c) != npos; 216 } 217 }; 218 219 } // namespace cpp 220 } // namespace LIBC_NAMESPACE_DECL 221 222 #endif // LLVM_LIBC_SRC___SUPPORT_CPP_STRING_VIEW_H 223