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