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