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> 90 inline BasicStringPiece<TChar>::BasicStringPiece() : data_(nullptr), length_(0) {} 91 92 template <typename TChar> 93 inline BasicStringPiece<TChar>::BasicStringPiece(const BasicStringPiece<TChar>& str) 94 : data_(str.data_), length_(str.length_) {} 95 96 template <typename TChar> 97 inline BasicStringPiece<TChar>::BasicStringPiece(const std::basic_string<TChar>& str) 98 : data_(str.data()), length_(str.length()) {} 99 100 template <> 101 inline BasicStringPiece<char>::BasicStringPiece(const char* str) 102 : data_(str), length_(str != nullptr ? strlen(str) : 0) {} 103 104 template <> 105 inline BasicStringPiece<char16_t>::BasicStringPiece(const char16_t* str) 106 : data_(str), length_(str != nullptr ? strlen16(str) : 0) {} 107 108 template <typename TChar> 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> 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> 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> 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> 147 inline const TChar* BasicStringPiece<TChar>::data() const { 148 return data_; 149 } 150 151 template <typename TChar> 152 inline size_t BasicStringPiece<TChar>::length() const { 153 return length_; 154 } 155 156 template <typename TChar> 157 inline size_t BasicStringPiece<TChar>::size() const { 158 return length_; 159 } 160 161 template <typename TChar> 162 inline bool BasicStringPiece<TChar>::empty() const { 163 return length_ == 0; 164 } 165 166 template <typename TChar> 167 inline std::basic_string<TChar> BasicStringPiece<TChar>::to_string() const { 168 return std::basic_string<TChar>(data_, length_); 169 } 170 171 template <> 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 <> 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 <> 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 <> 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> 252 inline typename BasicStringPiece<TChar>::const_iterator BasicStringPiece<TChar>::begin() const { 253 return data_; 254 } 255 256 template <typename TChar> 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