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