1/*
2 * Copyright (C) 2015 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 ANDROIDFW_STRING_PIECE_H
18#define ANDROIDFW_STRING_PIECE_H
19
20#include <ostream>
21#include <string>
22
23#include "utils/JenkinsHash.h"
24#include "utils/Unicode.h"
25
26namespace android {
27
28// Read only wrapper around basic C strings. Prevents excessive copying.
29// StringPiece does not own the data it is wrapping. The lifetime of the underlying
30// data must outlive this StringPiece.
31//
32// WARNING: When creating from std::basic_string<>, moving the original
33// std::basic_string<> will invalidate the data held in a BasicStringPiece<>.
34// BasicStringPiece<> should only be used transitively.
35template <typename TChar>
36class BasicStringPiece {
37 public:
38  using const_iterator = const TChar*;
39  using difference_type = size_t;
40
41  // End of string marker.
42  constexpr static const size_t npos = static_cast<size_t>(-1);
43
44  BasicStringPiece();
45  BasicStringPiece(const BasicStringPiece<TChar>& str);
46  BasicStringPiece(const std::basic_string<TChar>& str);  // NOLINT(implicit)
47  BasicStringPiece(const TChar* str);                     // NOLINT(implicit)
48  BasicStringPiece(const TChar* str, size_t len);
49
50  BasicStringPiece<TChar>& operator=(const BasicStringPiece<TChar>& rhs);
51  BasicStringPiece<TChar>& assign(const TChar* str, size_t len);
52
53  BasicStringPiece<TChar> substr(size_t start, size_t len = npos) const;
54  BasicStringPiece<TChar> substr(BasicStringPiece<TChar>::const_iterator begin,
55                                 BasicStringPiece<TChar>::const_iterator end) const;
56
57  const TChar* data() const;
58  size_t length() const;
59  size_t size() const;
60  bool empty() const;
61  std::basic_string<TChar> to_string() const;
62
63  bool contains(const BasicStringPiece<TChar>& rhs) const;
64  int compare(const BasicStringPiece<TChar>& rhs) const;
65  bool operator<(const BasicStringPiece<TChar>& rhs) const;
66  bool operator>(const BasicStringPiece<TChar>& rhs) const;
67  bool operator==(const BasicStringPiece<TChar>& rhs) const;
68  bool operator!=(const BasicStringPiece<TChar>& rhs) const;
69
70  const_iterator begin() const;
71  const_iterator end() const;
72
73 private:
74  const TChar* data_;
75  size_t length_;
76};
77
78using StringPiece = BasicStringPiece<char>;
79using StringPiece16 = BasicStringPiece<char16_t>;
80
81//
82// BasicStringPiece implementation.
83//
84
85template <typename TChar>
86constexpr const size_t BasicStringPiece<TChar>::npos;
87
88template <typename TChar>
89inline BasicStringPiece<TChar>::BasicStringPiece() : data_(nullptr), length_(0) {}
90
91template <typename TChar>
92inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str)
93    : data_(str.data_), length_(str.length_) {}
94
95template <typename TChar>
96inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str)
97    : data_(str.data()), length_(str.length()) {}
98
99template <>
100inline BasicStringPiece<char>::BasicStringPiece(const char* str)
101    : data_(str), length_(str != nullptr ? strlen(str) : 0) {}
102
103template <>
104inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str)
105    : data_(str), length_(str != nullptr ? strlen16(str) : 0) {}
106
107template <typename TChar>
108inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len)
109    : data_(str), length_(len) {}
110
111template <typename TChar>
112inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
113    const BasicStringPiece<TChar>& rhs) {
114  data_ = rhs.data_;
115  length_ = rhs.length_;
116  return *this;
117}
118
119template <typename TChar>
120inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
121  data_ = str;
122  length_ = len;
123  return *this;
124}
125
126template <typename TChar>
127inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(size_t start, size_t len) const {
128  if (len == npos) {
129    len = length_ - start;
130  }
131
132  if (start > length_ || start + len > length_) {
133    return BasicStringPiece<TChar>();
134  }
135  return BasicStringPiece<TChar>(data_ + start, len);
136}
137
138template <typename TChar>
139inline BasicStringPiece<TChar> BasicStringPiece<TChar>::substr(
140    BasicStringPiece<TChar>::const_iterator begin,
141    BasicStringPiece<TChar>::const_iterator end) const {
142  return BasicStringPiece<TChar>(begin, end - begin);
143}
144
145template <typename TChar>
146inline const TChar* BasicStringPiece<TChar>::data() const {
147  return data_;
148}
149
150template <typename TChar>
151inline size_t BasicStringPiece<TChar>::length() const {
152  return length_;
153}
154
155template <typename TChar>
156inline size_t BasicStringPiece<TChar>::size() const {
157  return length_;
158}
159
160template <typename TChar>
161inline bool BasicStringPiece<TChar>::empty() const {
162  return length_ == 0;
163}
164
165template <typename TChar>
166inline std::basic_string<TChar> BasicStringPiece<TChar>::to_string() const {
167  return std::basic_string<TChar>(data_, length_);
168}
169
170template <>
171inline bool BasicStringPiece<char>::contains(const BasicStringPiece<char>& rhs) const {
172  if (!data_ || !rhs.data_) {
173    return false;
174  }
175  if (rhs.length_ > length_) {
176    return false;
177  }
178  return strstr(data_, rhs.data_) != nullptr;
179}
180
181template <>
182inline int BasicStringPiece<char>::compare(const BasicStringPiece<char>& rhs) const {
183  const char nullStr = '\0';
184  const char* b1 = data_ != nullptr ? data_ : &nullStr;
185  const char* e1 = b1 + length_;
186  const char* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
187  const char* e2 = b2 + rhs.length_;
188
189  while (b1 < e1 && b2 < e2) {
190    const int d = static_cast<int>(*b1++) - static_cast<int>(*b2++);
191    if (d) {
192      return d;
193    }
194  }
195  return static_cast<int>(length_ - rhs.length_);
196}
197
198inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char16_t>& str) {
199  const ssize_t result_len = utf16_to_utf8_length(str.data(), str.size());
200  if (result_len < 0) {
201    // Empty string.
202    return out;
203  }
204
205  std::string result;
206  result.resize(static_cast<size_t>(result_len));
207  utf16_to_utf8(str.data(), str.length(), &*result.begin(), static_cast<size_t>(result_len) + 1);
208  return out << result;
209}
210
211template <>
212inline bool BasicStringPiece<char16_t>::contains(const BasicStringPiece<char16_t>& rhs) const {
213  if (!data_ || !rhs.data_) {
214    return false;
215  }
216  if (rhs.length_ > length_) {
217    return false;
218  }
219  return strstr16(data_, rhs.data_) != nullptr;
220}
221
222template <>
223inline int BasicStringPiece<char16_t>::compare(const BasicStringPiece<char16_t>& rhs) const {
224  const char16_t nullStr = u'\0';
225  const char16_t* b1 = data_ != nullptr ? data_ : &nullStr;
226  const char16_t* b2 = rhs.data_ != nullptr ? rhs.data_ : &nullStr;
227  return strzcmp16(b1, length_, b2, rhs.length_);
228}
229
230template <typename TChar>
231inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
232  return compare(rhs) < 0;
233}
234
235template <typename TChar>
236inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
237  return compare(rhs) > 0;
238}
239
240template <typename TChar>
241inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
242  return compare(rhs) == 0;
243}
244
245template <typename TChar>
246inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
247  return compare(rhs) != 0;
248}
249
250template <typename TChar>
251inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
252  return data_;
253}
254
255template <typename TChar>
256inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
257  return data_ + length_;
258}
259
260template <typename TChar>
261inline bool operator==(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
262  return BasicStringPiece<TChar>(lhs) == rhs;
263}
264
265template <typename TChar>
266inline bool operator!=(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
267  return BasicStringPiece<TChar>(lhs) != rhs;
268}
269
270inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
271  return out.write(str.data(), str.size());
272}
273
274template <typename TChar>
275inline ::std::basic_string<TChar>& operator+=(::std::basic_string<TChar>& lhs,
276                                              const BasicStringPiece<TChar>& rhs) {
277  return lhs.append(rhs.data(), rhs.size());
278}
279
280template <typename TChar>
281inline bool operator==(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
282  return rhs == lhs;
283}
284
285template <typename TChar>
286inline bool operator!=(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
287  return rhs != lhs;
288}
289
290}  // namespace android
291
292inline ::std::ostream& operator<<(::std::ostream& out, const std::u16string& str) {
293  ssize_t utf8_len = utf16_to_utf8_length(str.data(), str.size());
294  if (utf8_len < 0) {
295    return out << "???";
296  }
297
298  std::string utf8;
299  utf8.resize(static_cast<size_t>(utf8_len));
300  utf16_to_utf8(str.data(), str.size(), &*utf8.begin(), utf8_len + 1);
301  return out << utf8;
302}
303
304namespace std {
305
306template <typename TChar>
307struct hash<android::BasicStringPiece<TChar>> {
308  size_t operator()(const android::BasicStringPiece<TChar>& str) const {
309    uint32_t hashCode = android::JenkinsHashMixBytes(
310        0, reinterpret_cast<const uint8_t*>(str.data()), sizeof(TChar) * str.size());
311    return static_cast<size_t>(hashCode);
312  }
313};
314
315}  // namespace std
316
317#endif  // ANDROIDFW_STRING_PIECE_H
318