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