Home | History | Annotate | Download | only in base
      1 /*
      2  * Copyright (C) 2010 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 ART_LIBARTBASE_BASE_STRINGPIECE_H_
     18 #define ART_LIBARTBASE_BASE_STRINGPIECE_H_
     19 
     20 #include <string.h>
     21 #include <string>
     22 
     23 #include <android-base/logging.h>
     24 
     25 namespace art {
     26 
     27 // A string-like object that points to a sized piece of memory.
     28 //
     29 // Functions or methods may use const StringPiece& parameters to accept either
     30 // a "const char*" or a "string" value that will be implicitly converted to
     31 // a StringPiece.  The implicit conversion means that it is often appropriate
     32 // to include this .h file in other files rather than forward-declaring
     33 // StringPiece as would be appropriate for most other Google classes.
     34 class StringPiece {
     35  public:
     36   // standard STL container boilerplate
     37   typedef char value_type;
     38   typedef const char* pointer;
     39   typedef const char& reference;
     40   typedef const char& const_reference;
     41   typedef size_t size_type;
     42   typedef ptrdiff_t difference_type;
     43   static constexpr size_type npos = size_type(-1);
     44   typedef const char* const_iterator;
     45   typedef const char* iterator;
     46   typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
     47   typedef std::reverse_iterator<iterator> reverse_iterator;
     48 
     49   // We provide non-explicit singleton constructors so users can pass
     50   // in a "const char*" or a "string" wherever a "StringPiece" is
     51   // expected.
     52   StringPiece() : ptr_(nullptr), length_(0) { }
     53   StringPiece(const char* str)  // NOLINT implicit constructor desired
     54     : ptr_(str), length_((str == nullptr) ? 0 : strlen(str)) { }
     55   StringPiece(const std::string& str)  // NOLINT implicit constructor desired
     56     : ptr_(str.data()), length_(str.size()) { }
     57   StringPiece(const char* offset, size_t len) : ptr_(offset), length_(len) { }
     58 
     59   // data() may return a pointer to a buffer with embedded NULs, and the
     60   // returned buffer may or may not be null terminated.  Therefore it is
     61   // typically a mistake to pass data() to a routine that expects a NUL
     62   // terminated string.
     63   const char* data() const { return ptr_; }
     64   size_type size() const { return length_; }
     65   size_type length() const { return length_; }
     66   bool empty() const { return length_ == 0; }
     67 
     68   void clear() {
     69     ptr_ = nullptr;
     70     length_ = 0;
     71   }
     72   void set(const char* data_in, size_type len) {
     73     ptr_ = data_in;
     74     length_ = len;
     75   }
     76   void set(const char* str) {
     77     ptr_ = str;
     78     if (str != nullptr) {
     79       length_ = strlen(str);
     80     } else {
     81       length_ = 0;
     82     }
     83   }
     84   void set(const void* data_in, size_type len) {
     85     ptr_ = reinterpret_cast<const char*>(data_in);
     86     length_ = len;
     87   }
     88 
     89   char operator[](size_type i) const {
     90     DCHECK_LT(i, length_);
     91     return ptr_[i];
     92   }
     93 
     94   void remove_prefix(size_type n) {
     95     ptr_ += n;
     96     length_ -= n;
     97   }
     98 
     99   void remove_suffix(size_type n) {
    100     length_ -= n;
    101   }
    102 
    103   int compare(const StringPiece& x) const {
    104     int r = memcmp(ptr_, x.ptr_, std::min(length_, x.length_));
    105     if (r == 0) {
    106       if (length_ < x.length_) r = -1;
    107       else if (length_ > x.length_) r = +1;
    108     }
    109     return r;
    110   }
    111 
    112   std::string as_string() const {
    113     return std::string(data(), size());
    114   }
    115   // We also define ToString() here, since many other string-like
    116   // interfaces name the routine that converts to a C++ string
    117   // "ToString", and it's confusing to have the method that does that
    118   // for a StringPiece be called "as_string()".  We also leave the
    119   // "as_string()" method defined here for existing code.
    120   std::string ToString() const {
    121     return std::string(data(), size());
    122   }
    123 
    124   void CopyToString(std::string* target) const {
    125     target->assign(ptr_, length_);
    126   }
    127 
    128   void AppendToString(std::string* target) const;
    129 
    130   // Does "this" start with "x"
    131   bool starts_with(const StringPiece& x) const {
    132     return ((length_ >= x.length_) &&
    133             (memcmp(ptr_, x.ptr_, x.length_) == 0));
    134   }
    135 
    136   // Does "this" end with "x"
    137   bool ends_with(const StringPiece& x) const {
    138     return ((length_ >= x.length_) &&
    139             (memcmp(ptr_ + (length_-x.length_), x.ptr_, x.length_) == 0));
    140   }
    141 
    142   iterator begin() const { return ptr_; }
    143   iterator end() const { return ptr_ + length_; }
    144   const_reverse_iterator rbegin() const {
    145     return const_reverse_iterator(ptr_ + length_);
    146   }
    147   const_reverse_iterator rend() const {
    148     return const_reverse_iterator(ptr_);
    149   }
    150 
    151   size_type copy(char* buf, size_type n, size_type pos = 0) const {
    152     size_type ret = std::min(length_ - pos, n);
    153     memcpy(buf, ptr_ + pos, ret);
    154     return ret;
    155   }
    156 
    157   size_type find(const StringPiece& s, size_type pos = 0) const {
    158     if (length_ == 0 || pos > static_cast<size_type>(length_)) {
    159       return npos;
    160     }
    161     const char* result = std::search(ptr_ + pos, ptr_ + length_, s.ptr_, s.ptr_ + s.length_);
    162     const size_type xpos = result - ptr_;
    163     return xpos + s.length_ <= length_ ? xpos : npos;
    164   }
    165 
    166   size_type find(char c, size_type pos = 0) const {
    167     if (length_ == 0 || pos >= length_) {
    168       return npos;
    169     }
    170     const char* result = std::find(ptr_ + pos, ptr_ + length_, c);
    171     return result != ptr_ + length_ ? result - ptr_ : npos;
    172   }
    173 
    174   size_type rfind(const StringPiece& s, size_type pos = npos) const {
    175     if (length_ < s.length_) return npos;
    176     const size_t ulen = length_;
    177     if (s.length_ == 0) return std::min(ulen, pos);
    178 
    179     const char* last = ptr_ + std::min(ulen - s.length_, pos) + s.length_;
    180     const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
    181     return result != last ? result - ptr_ : npos;
    182   }
    183 
    184   size_type rfind(char c, size_type pos = npos) const {
    185     if (length_ == 0) return npos;
    186     for (int i = std::min(pos, static_cast<size_type>(length_ - 1));
    187          i >= 0; --i) {
    188       if (ptr_[i] == c) {
    189         return i;
    190       }
    191     }
    192     return npos;
    193   }
    194 
    195   StringPiece substr(size_type pos, size_type n = npos) const {
    196     if (pos > static_cast<size_type>(length_)) pos = length_;
    197     if (n > length_ - pos) n = length_ - pos;
    198     return StringPiece(ptr_ + pos, n);
    199   }
    200 
    201   int Compare(const StringPiece& rhs) const {
    202     const int r = memcmp(data(), rhs.data(), std::min(size(), rhs.size()));
    203     if (r != 0) {
    204       return r;
    205     }
    206     if (size() < rhs.size()) {
    207       return -1;
    208     } else if (size() > rhs.size()) {
    209       return 1;
    210     }
    211     return 0;
    212   }
    213 
    214  private:
    215   // Pointer to char data, not necessarily zero terminated.
    216   const char* ptr_;
    217   // Length of data.
    218   size_type length_;
    219 };
    220 
    221 // This large function is defined inline so that in a fairly common case where
    222 // one of the arguments is a literal, the compiler can elide a lot of the
    223 // following comparisons.
    224 inline bool operator==(const StringPiece& x, const StringPiece& y) {
    225   StringPiece::size_type len = x.size();
    226   if (len != y.size()) {
    227     return false;
    228   }
    229 
    230   const char* p1 = x.data();
    231   const char* p2 = y.data();
    232   if (p1 == p2) {
    233     return true;
    234   }
    235   if (len == 0) {
    236     return true;
    237   }
    238 
    239   // Test last byte in case strings share large common prefix
    240   if (p1[len-1] != p2[len-1]) return false;
    241   if (len == 1) return true;
    242 
    243   // At this point we can, but don't have to, ignore the last byte.  We use
    244   // this observation to fold the odd-length case into the even-length case.
    245   len &= ~1;
    246 
    247   return memcmp(p1, p2, len) == 0;
    248 }
    249 
    250 inline bool operator==(const StringPiece& x, const char* y) {
    251   if (y == nullptr) {
    252     return x.size() == 0;
    253   } else {
    254     return strncmp(x.data(), y, x.size()) == 0 && y[x.size()] == '\0';
    255   }
    256 }
    257 
    258 inline bool operator!=(const StringPiece& x, const StringPiece& y) {
    259   return !(x == y);
    260 }
    261 
    262 inline bool operator!=(const StringPiece& x, const char* y) {
    263   return !(x == y);
    264 }
    265 
    266 inline bool operator<(const StringPiece& x, const StringPiece& y) {
    267   return x.Compare(y) < 0;
    268 }
    269 
    270 inline bool operator>(const StringPiece& x, const StringPiece& y) {
    271   return y < x;
    272 }
    273 
    274 inline bool operator<=(const StringPiece& x, const StringPiece& y) {
    275   return !(x > y);
    276 }
    277 
    278 inline bool operator>=(const StringPiece& x, const StringPiece& y) {
    279   return !(x < y);
    280 }
    281 
    282 inline std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
    283   o.write(piece.data(), piece.size());
    284   return o;
    285 }
    286 
    287 }  // namespace art
    288 
    289 #endif  // ART_LIBARTBASE_BASE_STRINGPIECE_H_
    290