summaryrefslogtreecommitdiff
path: root/libc/src/__support/CPP/string_view.h
blob: aa31f15d97c66ee4efd076195ebb3184f721bc66 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
//===-- Standalone implementation std::string_view --------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H
#define LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H

#include "src/__support/common.h"

#include <stddef.h>

namespace __llvm_libc {
namespace cpp {

// This is very simple alternate of the std::string_view class. There is no
// bounds check performed in any of the methods. The callers are expected to
// do the checks before invoking the methods.
//
// This class will be extended as needed in future.
class string_view {
private:
  const char *Data;
  size_t Len;

  static size_t min(size_t A, size_t B) { return A <= B ? A : B; }

  LIBC_INLINE static int compareMemory(const char *Lhs, const char *Rhs,
                                       size_t Length) {
    for (size_t I = 0; I < Length; ++I)
      if (int Diff = (int)Lhs[I] - (int)Rhs[I])
        return Diff;
    return 0;
  }

  LIBC_INLINE static constexpr size_t length(const char *Str) {
    for (const char *End = Str;; ++End)
      if (*End == '\0')
        return End - Str;
  }

  LIBC_INLINE bool equals(string_view Other) const {
    return (Len == Other.Len &&
            compareMemory(Data, Other.Data, Other.Len) == 0);
  }

public:
  using value_type = char;
  using size_type = size_t;
  using difference_type = ptrdiff_t;
  using pointer = char *;
  using const_pointer = const char *;
  using reference = char &;
  using const_reference = const char &;
  using const_iterator = char *;
  using iterator = const_iterator;

  // special value equal to the maximum value representable by the type
  // size_type.
  inline static constexpr size_t npos = -1;

  LIBC_INLINE constexpr string_view() : Data(nullptr), Len(0) {}

  // Assumes Str is a null-terminated string. The length of the string does
  // not include the terminating null character.
  // Preconditions: [Str, Str + ​length(Str)) is a valid range.
  LIBC_INLINE constexpr string_view(const char *Str)
      : Data(Str), Len(length(Str)) {}

  // Preconditions: [Str, Str + N) is a valid range.
  LIBC_INLINE constexpr string_view(const char *Str, size_t N)
      : Data(Str), Len(N) {}

  LIBC_INLINE constexpr const char *data() const { return Data; }

  // Returns the size of the string_view.
  LIBC_INLINE constexpr size_t size() const { return Len; }

  // Returns whether the string_view is empty.
  LIBC_INLINE constexpr bool empty() const { return Len == 0; }

  // Returns an iterator to the first character of the view.
  LIBC_INLINE const char *begin() const { return Data; }

  // Returns an iterator to the character following the last character of the
  // view.
  LIBC_INLINE const char *end() const { return Data + Len; }

  // Returns a const reference to the character at specified location pos.
  // No bounds checking is performed: the behavior is undefined if pos >=
  // size().
  LIBC_INLINE constexpr const char &operator[](size_t Index) const {
    return Data[Index];
  }

  /// compare - Compare two strings; the result is -1, 0, or 1 if this string
  /// is lexicographically less than, equal to, or greater than the \p Other.
  LIBC_INLINE int compare(string_view Other) const {
    // Check the prefix for a mismatch.
    if (int Res = compareMemory(Data, Other.Data, min(Len, Other.Len)))
      return Res < 0 ? -1 : 1;
    // Otherwise the prefixes match, so we only need to check the lengths.
    if (Len == Other.Len)
      return 0;
    return Len < Other.Len ? -1 : 1;
  }

  LIBC_INLINE bool operator==(string_view Other) const { return equals(Other); }
  LIBC_INLINE bool operator!=(string_view Other) const {
    return !(*this == Other);
  }
  LIBC_INLINE bool operator<(string_view Other) const {
    return compare(Other) == -1;
  }
  LIBC_INLINE bool operator<=(string_view Other) const {
    return compare(Other) != 1;
  }
  LIBC_INLINE bool operator>(string_view Other) const {
    return compare(Other) == 1;
  }
  LIBC_INLINE bool operator>=(string_view Other) const {
    return compare(Other) != -1;
  }

  // Moves the start of the view forward by n characters.
  // The behavior is undefined if n > size().
  LIBC_INLINE void remove_prefix(size_t N) {
    Len -= N;
    Data += N;
  }

  // Moves the end of the view back by n characters.
  // The behavior is undefined if n > size().
  LIBC_INLINE void remove_suffix(size_t N) { Len -= N; }

  // Check if this string starts with the given Prefix.
  LIBC_INLINE bool starts_with(string_view Prefix) const {
    return Len >= Prefix.Len &&
           compareMemory(Data, Prefix.Data, Prefix.Len) == 0;
  }

  // Check if this string starts with the given Prefix.
  LIBC_INLINE bool starts_with(const char Prefix) const {
    return !empty() && front() == Prefix;
  }

  // Check if this string ends with the given Prefix.
  LIBC_INLINE bool ends_with(const char Suffix) const {
    return !empty() && back() == Suffix;
  }

  // Check if this string ends with the given Suffix.
  LIBC_INLINE bool ends_with(string_view Suffix) const {
    return Len >= Suffix.Len &&
           compareMemory(end() - Suffix.Len, Suffix.Data, Suffix.Len) == 0;
  }

  // Return a reference to the substring from [Start, Start + N).
  //
  // Start The index of the starting character in the substring; if the index is
  // npos or greater than the length of the string then the empty substring will
  // be returned.
  //
  // N The number of characters to included in the substring. If N exceeds the
  // number of characters remaining in the string, the string suffix (starting
  // with Start) will be returned.
  LIBC_INLINE string_view substr(size_t Start, size_t N = npos) const {
    Start = min(Start, Len);
    return string_view(Data + Start, min(N, Len - Start));
  }

  // front - Get the first character in the string.
  LIBC_INLINE char front() const { return Data[0]; }

  // back - Get the last character in the string.
  LIBC_INLINE char back() const { return Data[Len - 1]; }

  // Finds the first occurence of c in this view, starting at position From.
  LIBC_INLINE size_t find_first_of(const char c, size_t From = 0) const {
    for (size_t Pos = From; Pos < size(); ++Pos)
      if ((*this)[Pos] == c)
        return Pos;
    return npos;
  }

  // Finds the last occurence of c in this view, ending at position End.
  LIBC_INLINE size_t find_last_of(const char c, size_t End = npos) const {
    End = End >= size() ? size() : End + 1;
    for (; End > 0; --End)
      if ((*this)[End - 1] == c)
        return End - 1;
    return npos;
  }
};

} // namespace cpp
} // namespace __llvm_libc

#endif // LLVM_LIBC_SRC_SUPPORT_CPP_STRINGVIEW_H