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