Home | History | Annotate | Download | only in strings
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 // Copied from strings/stringpiece.cc with modifications
      5 
      6 #include "base/strings/string_piece.h"
      7 
      8 #include <algorithm>
      9 #include <ostream>
     10 
     11 namespace base {
     12 
     13 // MSVC doesn't like complex extern templates and DLLs.
     14 #if !defined(COMPILER_MSVC)
     15 namespace internal {
     16 template class StringPieceDetail<std::string>;
     17 template class StringPieceDetail<string16>;
     18 }  // namespace internal
     19 
     20 template class BasicStringPiece<string16>;
     21 #endif
     22 
     23 bool operator==(const StringPiece& x, const StringPiece& y) {
     24   if (x.size() != y.size())
     25     return false;
     26 
     27   return StringPiece::wordmemcmp(x.data(), y.data(), x.size()) == 0;
     28 }
     29 
     30 std::ostream& operator<<(std::ostream& o, const StringPiece& piece) {
     31   o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
     32   return o;
     33 }
     34 
     35 namespace internal {
     36 void CopyToString(const StringPiece& self, std::string* target) {
     37   target->assign(!self.empty() ? self.data() : "", self.size());
     38 }
     39 
     40 void AppendToString(const StringPiece& self, std::string* target) {
     41   if (!self.empty())
     42     target->append(self.data(), self.size());
     43 }
     44 
     45 StringPiece::size_type copy(const StringPiece& self,
     46                             char* buf,
     47                             StringPiece::size_type n,
     48                             StringPiece::size_type pos) {
     49   StringPiece::size_type ret = std::min(self.size() - pos, n);
     50   memcpy(buf, self.data() + pos, ret);
     51   return ret;
     52 }
     53 
     54 StringPiece::size_type find(const StringPiece& self,
     55                             const StringPiece& s,
     56                             StringPiece::size_type pos) {
     57   if (pos > self.size())
     58     return StringPiece::npos;
     59 
     60   StringPiece::const_iterator result =
     61       std::search(self.begin() + pos, self.end(), s.begin(), s.end());
     62   const StringPiece::size_type xpos =
     63     static_cast<size_t>(result - self.begin());
     64   return xpos + s.size() <= self.size() ? xpos : StringPiece::npos;
     65 }
     66 
     67 StringPiece::size_type find(const StringPiece& self,
     68                             char c,
     69                             StringPiece::size_type pos) {
     70   if (pos >= self.size())
     71     return StringPiece::npos;
     72 
     73   StringPiece::const_iterator result =
     74       std::find(self.begin() + pos, self.end(), c);
     75   return result != self.end() ?
     76       static_cast<size_t>(result - self.begin()) : StringPiece::npos;
     77 }
     78 
     79 StringPiece::size_type rfind(const StringPiece& self,
     80                              const StringPiece& s,
     81                              StringPiece::size_type pos) {
     82   if (self.size() < s.size())
     83     return StringPiece::npos;
     84 
     85   if (s.empty())
     86     return std::min(self.size(), pos);
     87 
     88   StringPiece::const_iterator last =
     89       self.begin() + std::min(self.size() - s.size(), pos) + s.size();
     90   StringPiece::const_iterator result =
     91       std::find_end(self.begin(), last, s.begin(), s.end());
     92   return result != last ?
     93       static_cast<size_t>(result - self.begin()) : StringPiece::npos;
     94 }
     95 
     96 StringPiece::size_type rfind(const StringPiece& self,
     97                              char c,
     98                              StringPiece::size_type pos) {
     99   if (self.size() == 0)
    100     return StringPiece::npos;
    101 
    102   for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
    103     if (self.data()[i] == c)
    104       return i;
    105     if (i == 0)
    106       break;
    107   }
    108   return StringPiece::npos;
    109 }
    110 
    111 // For each character in characters_wanted, sets the index corresponding
    112 // to the ASCII code of that character to 1 in table.  This is used by
    113 // the find_.*_of methods below to tell whether or not a character is in
    114 // the lookup table in constant time.
    115 // The argument `table' must be an array that is large enough to hold all
    116 // the possible values of an unsigned char.  Thus it should be be declared
    117 // as follows:
    118 //   bool table[UCHAR_MAX + 1]
    119 static inline void BuildLookupTable(const StringPiece& characters_wanted,
    120                                     bool* table) {
    121   const StringPiece::size_type length = characters_wanted.length();
    122   const char* const data = characters_wanted.data();
    123   for (StringPiece::size_type i = 0; i < length; ++i) {
    124     table[static_cast<unsigned char>(data[i])] = true;
    125   }
    126 }
    127 
    128 StringPiece::size_type find_first_of(const StringPiece& self,
    129                                      const StringPiece& s,
    130                                      StringPiece::size_type pos) {
    131   if (self.size() == 0 || s.size() == 0)
    132     return StringPiece::npos;
    133 
    134   // Avoid the cost of BuildLookupTable() for a single-character search.
    135   if (s.size() == 1)
    136     return find(self, s.data()[0], pos);
    137 
    138   bool lookup[UCHAR_MAX + 1] = { false };
    139   BuildLookupTable(s, lookup);
    140   for (StringPiece::size_type i = pos; i < self.size(); ++i) {
    141     if (lookup[static_cast<unsigned char>(self.data()[i])]) {
    142       return i;
    143     }
    144   }
    145   return StringPiece::npos;
    146 }
    147 
    148 StringPiece::size_type find_first_not_of(const StringPiece& self,
    149                                          const StringPiece& s,
    150                                          StringPiece::size_type pos) {
    151   if (self.size() == 0)
    152     return StringPiece::npos;
    153 
    154   if (s.size() == 0)
    155     return 0;
    156 
    157   // Avoid the cost of BuildLookupTable() for a single-character search.
    158   if (s.size() == 1)
    159     return find_first_not_of(self, s.data()[0], pos);
    160 
    161   bool lookup[UCHAR_MAX + 1] = { false };
    162   BuildLookupTable(s, lookup);
    163   for (StringPiece::size_type i = pos; i < self.size(); ++i) {
    164     if (!lookup[static_cast<unsigned char>(self.data()[i])]) {
    165       return i;
    166     }
    167   }
    168   return StringPiece::npos;
    169 }
    170 
    171 StringPiece::size_type find_first_not_of(const StringPiece& self,
    172                                          char c,
    173                                          StringPiece::size_type pos) {
    174   if (self.size() == 0)
    175     return StringPiece::npos;
    176 
    177   for (; pos < self.size(); ++pos) {
    178     if (self.data()[pos] != c) {
    179       return pos;
    180     }
    181   }
    182   return StringPiece::npos;
    183 }
    184 
    185 StringPiece::size_type find_last_of(const StringPiece& self,
    186                                     const StringPiece& s,
    187                                     StringPiece::size_type pos) {
    188   if (self.size() == 0 || s.size() == 0)
    189     return StringPiece::npos;
    190 
    191   // Avoid the cost of BuildLookupTable() for a single-character search.
    192   if (s.size() == 1)
    193     return rfind(self, s.data()[0], pos);
    194 
    195   bool lookup[UCHAR_MAX + 1] = { false };
    196   BuildLookupTable(s, lookup);
    197   for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
    198     if (lookup[static_cast<unsigned char>(self.data()[i])])
    199       return i;
    200     if (i == 0)
    201       break;
    202   }
    203   return StringPiece::npos;
    204 }
    205 
    206 StringPiece::size_type find_last_not_of(const StringPiece& self,
    207                                         const StringPiece& s,
    208                                         StringPiece::size_type pos) {
    209   if (self.size() == 0)
    210     return StringPiece::npos;
    211 
    212   StringPiece::size_type i = std::min(pos, self.size() - 1);
    213   if (s.size() == 0)
    214     return i;
    215 
    216   // Avoid the cost of BuildLookupTable() for a single-character search.
    217   if (s.size() == 1)
    218     return find_last_not_of(self, s.data()[0], pos);
    219 
    220   bool lookup[UCHAR_MAX + 1] = { false };
    221   BuildLookupTable(s, lookup);
    222   for (; ; --i) {
    223     if (!lookup[static_cast<unsigned char>(self.data()[i])])
    224       return i;
    225     if (i == 0)
    226       break;
    227   }
    228   return StringPiece::npos;
    229 }
    230 
    231 StringPiece::size_type find_last_not_of(const StringPiece& self,
    232                                         char c,
    233                                         StringPiece::size_type pos) {
    234   if (self.size() == 0)
    235     return StringPiece::npos;
    236 
    237   for (StringPiece::size_type i = std::min(pos, self.size() - 1); ; --i) {
    238     if (self.data()[i] != c)
    239       return i;
    240     if (i == 0)
    241       break;
    242   }
    243   return StringPiece::npos;
    244 }
    245 
    246 StringPiece substr(const StringPiece& self,
    247                    StringPiece::size_type pos,
    248                    StringPiece::size_type n) {
    249   if (pos > self.size()) pos = self.size();
    250   if (n > self.size() - pos) n = self.size() - pos;
    251   return StringPiece(self.data() + pos, n);
    252 }
    253 
    254 }  // namespace internal
    255 }  // namespace base
    256