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