1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ART_RUNTIME_BASE_STRINGPIECE_H_
18#define ART_RUNTIME_BASE_STRINGPIECE_H_
19
20#include <string.h>
21#include <string>
22
23namespace art {
24
25// A string-like object that points to a sized piece of memory.
26//
27// Functions or methods may use const StringPiece& parameters to accept either
28// a "const char*" or a "string" value that will be implicitly converted to
29// a StringPiece.  The implicit conversion means that it is often appropriate
30// to include this .h file in other files rather than forward-declaring
31// StringPiece as would be appropriate for most other Google classes.
32class StringPiece {
33 public:
34  // standard STL container boilerplate
35  typedef char value_type;
36  typedef const char* pointer;
37  typedef const char& reference;
38  typedef const char& const_reference;
39  typedef size_t size_type;
40  typedef ptrdiff_t difference_type;
41  static constexpr size_type npos = size_type(-1);
42  typedef const char* const_iterator;
43  typedef const char* iterator;
44  typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
45  typedef std::reverse_iterator<iterator> reverse_iterator;
46
47  // We provide non-explicit singleton constructors so users can pass
48  // in a "const char*" or a "string" wherever a "StringPiece" is
49  // expected.
50  StringPiece() : ptr_(nullptr), length_(0) { }
51  StringPiece(const char* str)  // NOLINT implicit constructor desired
52    : ptr_(str), length_((str == nullptr) ? 0 : strlen(str)) { }
53  StringPiece(const std::string& str)  // NOLINT implicit constructor desired
54    : ptr_(str.data()), length_(str.size()) { }
55  StringPiece(const char* offset, size_t len) : ptr_(offset), length_(len) { }
56
57  // data() may return a pointer to a buffer with embedded NULs, and the
58  // returned buffer may or may not be null terminated.  Therefore it is
59  // typically a mistake to pass data() to a routine that expects a NUL
60  // terminated string.
61  const char* data() const { return ptr_; }
62  size_type size() const { return length_; }
63  size_type length() const { return length_; }
64  bool empty() const { return length_ == 0; }
65
66  void clear() {
67    ptr_ = nullptr;
68    length_ = 0;
69  }
70  void set(const char* data_in, size_type len) {
71    ptr_ = data_in;
72    length_ = len;
73  }
74  void set(const char* str) {
75    ptr_ = str;
76    if (str != nullptr) {
77      length_ = strlen(str);
78    } else {
79      length_ = 0;
80    }
81  }
82  void set(const void* data_in, size_type len) {
83    ptr_ = reinterpret_cast<const char*>(data_in);
84    length_ = len;
85  }
86
87#if defined(NDEBUG)
88  char operator[](size_type i) const {
89    return ptr_[i];
90  }
91#else
92  char operator[](size_type i) const;
93#endif
94
95  void remove_prefix(size_type n) {
96    ptr_ += n;
97    length_ -= n;
98  }
99
100  void remove_suffix(size_type n) {
101    length_ -= n;
102  }
103
104  int compare(const StringPiece& x) const;
105
106  std::string as_string() const {
107    return std::string(data(), size());
108  }
109  // We also define ToString() here, since many other string-like
110  // interfaces name the routine that converts to a C++ string
111  // "ToString", and it's confusing to have the method that does that
112  // for a StringPiece be called "as_string()".  We also leave the
113  // "as_string()" method defined here for existing code.
114  std::string ToString() const {
115    return std::string(data(), size());
116  }
117
118  void CopyToString(std::string* target) const;
119  void AppendToString(std::string* target) const;
120
121  // Does "this" start with "x"
122  bool starts_with(const StringPiece& x) const {
123    return ((length_ >= x.length_) &&
124            (memcmp(ptr_, x.ptr_, x.length_) == 0));
125  }
126
127  // Does "this" end with "x"
128  bool ends_with(const StringPiece& x) const {
129    return ((length_ >= x.length_) &&
130            (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
131  }
132
133  iterator begin() const { return ptr_; }
134  iterator end() const { return ptr_ + length_; }
135  const_reverse_iterator rbegin() const {
136    return const_reverse_iterator(ptr_ + length_);
137  }
138  const_reverse_iterator rend() const {
139    return const_reverse_iterator(ptr_);
140  }
141
142  size_type copy(char* buf, size_type n, size_type pos = 0) const;
143
144  size_type find(const StringPiece& s, size_type pos = 0) const;
145  size_type find(char c, size_type pos = 0) const;
146  size_type rfind(const StringPiece& s, size_type pos = npos) const;
147  size_type rfind(char c, size_type pos = npos) const;
148
149  StringPiece substr(size_type pos, size_type n = npos) const;
150
151  int Compare(const StringPiece& rhs) const {
152    const int r = memcmp(data(), rhs.data(), std::min(size(), rhs.size()));
153    if (r != 0) {
154      return r;
155    }
156    if (size() < rhs.size()) {
157      return -1;
158    } else if (size() > rhs.size()) {
159      return 1;
160    }
161    return 0;
162  }
163
164 private:
165  // Pointer to char data, not necessarily zero terminated.
166  const char* ptr_;
167  // Length of data.
168  size_type length_;
169};
170
171// This large function is defined inline so that in a fairly common case where
172// one of the arguments is a literal, the compiler can elide a lot of the
173// following comparisons.
174inline bool operator==(const StringPiece& x, const StringPiece& y) {
175  StringPiece::size_type len = x.size();
176  if (len != y.size()) {
177    return false;
178  }
179
180  const char* p1 = x.data();
181  const char* p2 = y.data();
182  if (p1 == p2) {
183    return true;
184  }
185  if (len == 0) {
186    return true;
187  }
188
189  // Test last byte in case strings share large common prefix
190  if (p1[len-1] != p2[len-1]) return false;
191  if (len == 1) return true;
192
193  // At this point we can, but don't have to, ignore the last byte.  We use
194  // this observation to fold the odd-length case into the even-length case.
195  len &= ~1;
196
197  return memcmp(p1, p2, len) == 0;
198}
199
200inline bool operator==(const StringPiece& x, const char* y) {
201  if (y == nullptr) {
202    return x.size() == 0;
203  } else {
204    return strncmp(x.data(), y, x.size()) == 0 && y[x.size()] == '\0';
205  }
206}
207
208inline bool operator!=(const StringPiece& x, const StringPiece& y) {
209  return !(x == y);
210}
211
212inline bool operator!=(const StringPiece& x, const char* y) {
213  return !(x == y);
214}
215
216inline bool operator<(const StringPiece& x, const StringPiece& y) {
217  return x.Compare(y) < 0;
218}
219
220inline bool operator>(const StringPiece& x, const StringPiece& y) {
221  return y < x;
222}
223
224inline bool operator<=(const StringPiece& x, const StringPiece& y) {
225  return !(x > y);
226}
227
228inline bool operator>=(const StringPiece& x, const StringPiece& y) {
229  return !(x < y);
230}
231
232extern std::ostream& operator<<(std::ostream& o, const StringPiece& piece);
233
234}  // namespace art
235
236#endif  // ART_RUNTIME_BASE_STRINGPIECE_H_
237