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