Home | History | Annotate | Download | only in androidfw
      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