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