• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
26 namespace 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.
35 template <typename TChar>
36 class 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 
79 using StringPiece = BasicStringPiece<char>;
80 using StringPiece16 = BasicStringPiece<char16_t>;
81 
82 //
83 // BasicStringPiece implementation.
84 //
85 
86 template <typename TChar>
87 constexpr const size_t BasicStringPiece<TChar>::npos;
88 
89 template <typename TChar>
BasicStringPiece()90 inline BasicStringPiece<TChar>::BasicStringPiece() : data_(nullptr), length_(0) {}
91 
92 template <typename TChar>
BasicStringPiece(const BasicStringPiece<TChar> & str)93 inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str)
94     : data_(str.data_), length_(str.length_) {}
95 
96 template <typename TChar>
BasicStringPiece(const std::basic_string<TChar> & str)97 inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str)
98     : data_(str.data()), length_(str.length()) {}
99 
100 template <>
BasicStringPiece(const char * str)101 inline BasicStringPiece<char>::BasicStringPiece(const char* str)
102     : data_(str), length_(str != nullptr ? strlen(str) : 0) {}
103 
104 template <>
BasicStringPiece(const char16_t * str)105 inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str)
106     : data_(str), length_(str != nullptr ? strlen16(str) : 0) {}
107 
108 template <typename TChar>
BasicStringPiece(const TChar * str,size_t len)109 inline BasicStringPiece<TChar>::BasicStringPiece(const TChar* str, size_t len)
110     : data_(str), length_(len) {}
111 
112 template <typename TChar>
113 inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::operator=(
114     const BasicStringPiece<TChar>& rhs) {
115   data_ = rhs.data_;
116   length_ = rhs.length_;
117   return *this;
118 }
119 
120 template <typename TChar>
assign(const TChar * str,size_t len)121 inline BasicStringPiece<TChar>& BasicStringPiece<TChar>::assign(const TChar* str, size_t len) {
122   data_ = str;
123   length_ = len;
124   return *this;
125 }
126 
127 template <typename TChar>
substr(size_t start,size_t len)128 inline 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 
139 template <typename TChar>
substr(BasicStringPiece<TChar>::const_iterator begin,BasicStringPiece<TChar>::const_iterator end)140 inline 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 
146 template <typename TChar>
data()147 inline const TChar* BasicStringPiece<TChar>::data() const {
148   return data_;
149 }
150 
151 template <typename TChar>
length()152 inline size_t BasicStringPiece<TChar>::length() const {
153   return length_;
154 }
155 
156 template <typename TChar>
size()157 inline size_t BasicStringPiece<TChar>::size() const {
158   return length_;
159 }
160 
161 template <typename TChar>
empty()162 inline bool BasicStringPiece<TChar>::empty() const {
163   return length_ == 0;
164 }
165 
166 template <typename TChar>
to_string()167 inline std::basic_string<TChar> BasicStringPiece<TChar>::to_string() const {
168   return std::basic_string<TChar>(data_, length_);
169 }
170 
171 template <>
contains(const BasicStringPiece<char> & rhs)172 inline 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 
182 template <>
compare(const BasicStringPiece<char> & rhs)183 inline 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 
199 inline ::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 
212 template <>
contains(const BasicStringPiece<char16_t> & rhs)213 inline 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 
223 template <>
compare(const BasicStringPiece<char16_t> & rhs)224 inline 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 
231 template <typename TChar>
232 inline bool BasicStringPiece<TChar>::operator<(const BasicStringPiece<TChar>& rhs) const {
233   return compare(rhs) < 0;
234 }
235 
236 template <typename TChar>
237 inline bool BasicStringPiece<TChar>::operator>(const BasicStringPiece<TChar>& rhs) const {
238   return compare(rhs) > 0;
239 }
240 
241 template <typename TChar>
242 inline bool BasicStringPiece<TChar>::operator==(const BasicStringPiece<TChar>& rhs) const {
243   return compare(rhs) == 0;
244 }
245 
246 template <typename TChar>
247 inline bool BasicStringPiece<TChar>::operator!=(const BasicStringPiece<TChar>& rhs) const {
248   return compare(rhs) != 0;
249 }
250 
251 template <typename TChar>
begin()252 inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const {
253   return data_;
254 }
255 
256 template <typename TChar>
end()257 inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::end() const {
258   return data_ + length_;
259 }
260 
261 template <typename TChar>
262 inline bool operator==(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
263   return BasicStringPiece<TChar>(lhs) == rhs;
264 }
265 
266 template <typename TChar>
267 inline bool operator!=(const TChar* lhs, const BasicStringPiece<TChar>& rhs) {
268   return BasicStringPiece<TChar>(lhs) != rhs;
269 }
270 
271 inline ::std::ostream& operator<<(::std::ostream& out, const BasicStringPiece<char>& str) {
272   return out.write(str.data(), str.size());
273 }
274 
275 template <typename TChar>
276 inline ::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 
281 template <typename TChar>
282 inline bool operator==(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
283   return rhs == lhs;
284 }
285 
286 template <typename TChar>
287 inline bool operator!=(const ::std::basic_string<TChar>& lhs, const BasicStringPiece<TChar>& rhs) {
288   return rhs != lhs;
289 }
290 
291 }  // namespace android
292 
293 inline ::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 
305 namespace std {
306 
307 template <typename TChar>
308 struct 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