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