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