tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

string_view.cc (7708B)


      1 // Copyright 2017 The Abseil Authors.
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 //      https://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "absl/strings/string_view.h"
     16 
     17 #ifndef ABSL_USES_STD_STRING_VIEW
     18 
     19 #include <algorithm>
     20 #include <climits>
     21 #include <cstring>
     22 #include <ostream>
     23 
     24 #include "absl/base/nullability.h"
     25 
     26 namespace absl {
     27 ABSL_NAMESPACE_BEGIN
     28 
     29 namespace {
     30 
     31 // This is significantly faster for case-sensitive matches with very
     32 // few possible matches.
     33 absl::Nullable<const char*> memmatch(absl::Nullable<const char*> phaystack,
     34                                     size_t haylen,
     35                                     absl::Nullable<const char*> pneedle,
     36                                     size_t neelen) {
     37  if (0 == neelen) {
     38    return phaystack;  // even if haylen is 0
     39  }
     40  if (haylen < neelen) return nullptr;
     41 
     42  const char* match;
     43  const char* hayend = phaystack + haylen - neelen + 1;
     44  // A static cast is used here as memchr returns a const void *, and pointer
     45  // arithmetic is not allowed on pointers to void.
     46  while (
     47      (match = static_cast<const char*>(memchr(
     48           phaystack, pneedle[0], static_cast<size_t>(hayend - phaystack))))) {
     49    if (memcmp(match, pneedle, neelen) == 0)
     50      return match;
     51    else
     52      phaystack = match + 1;
     53  }
     54  return nullptr;
     55 }
     56 
     57 void WritePadding(std::ostream& o, size_t pad) {
     58  char fill_buf[32];
     59  memset(fill_buf, o.fill(), sizeof(fill_buf));
     60  while (pad) {
     61    size_t n = std::min(pad, sizeof(fill_buf));
     62    o.write(fill_buf, static_cast<std::streamsize>(n));
     63    pad -= n;
     64  }
     65 }
     66 
     67 class LookupTable {
     68 public:
     69  // For each character in wanted, sets the index corresponding
     70  // to the ASCII code of that character. This is used by
     71  // the find_.*_of methods below to tell whether or not a character is in
     72  // the lookup table in constant time.
     73  explicit LookupTable(string_view wanted) {
     74    for (char c : wanted) {
     75      table_[Index(c)] = true;
     76    }
     77  }
     78  bool operator[](char c) const { return table_[Index(c)]; }
     79 
     80 private:
     81  static unsigned char Index(char c) { return static_cast<unsigned char>(c); }
     82  bool table_[UCHAR_MAX + 1] = {};
     83 };
     84 
     85 }  // namespace
     86 
     87 std::ostream& operator<<(std::ostream& o, string_view piece) {
     88  std::ostream::sentry sentry(o);
     89  if (sentry) {
     90    size_t lpad = 0;
     91    size_t rpad = 0;
     92    if (static_cast<size_t>(o.width()) > piece.size()) {
     93      size_t pad = static_cast<size_t>(o.width()) - piece.size();
     94      if ((o.flags() & o.adjustfield) == o.left) {
     95        rpad = pad;
     96      } else {
     97        lpad = pad;
     98      }
     99    }
    100    if (lpad) WritePadding(o, lpad);
    101    o.write(piece.data(), static_cast<std::streamsize>(piece.size()));
    102    if (rpad) WritePadding(o, rpad);
    103    o.width(0);
    104  }
    105  return o;
    106 }
    107 
    108 string_view::size_type string_view::find(string_view s,
    109                                         size_type pos) const noexcept {
    110  if (empty() || pos > length_) {
    111    if (empty() && pos == 0 && s.empty()) return 0;
    112    return npos;
    113  }
    114  const char* result = memmatch(ptr_ + pos, length_ - pos, s.ptr_, s.length_);
    115  return result ? static_cast<size_type>(result - ptr_) : npos;
    116 }
    117 
    118 string_view::size_type string_view::find(char c, size_type pos) const noexcept {
    119  if (empty() || pos >= length_) {
    120    return npos;
    121  }
    122  const char* result =
    123      static_cast<const char*>(memchr(ptr_ + pos, c, length_ - pos));
    124  return result != nullptr ? static_cast<size_type>(result - ptr_) : npos;
    125 }
    126 
    127 string_view::size_type string_view::rfind(string_view s,
    128                                          size_type pos) const noexcept {
    129  if (length_ < s.length_) return npos;
    130  if (s.empty()) return std::min(length_, pos);
    131  const char* last = ptr_ + std::min(length_ - s.length_, pos) + s.length_;
    132  const char* result = std::find_end(ptr_, last, s.ptr_, s.ptr_ + s.length_);
    133  return result != last ? static_cast<size_type>(result - ptr_) : npos;
    134 }
    135 
    136 // Search range is [0..pos] inclusive.  If pos == npos, search everything.
    137 string_view::size_type string_view::rfind(char c,
    138                                          size_type pos) const noexcept {
    139  // Note: memrchr() is not available on Windows.
    140  if (empty()) return npos;
    141  for (size_type i = std::min(pos, length_ - 1);; --i) {
    142    if (ptr_[i] == c) {
    143      return i;
    144    }
    145    if (i == 0) break;
    146  }
    147  return npos;
    148 }
    149 
    150 string_view::size_type string_view::find_first_of(
    151    string_view s, size_type pos) const noexcept {
    152  if (empty() || s.empty()) {
    153    return npos;
    154  }
    155  // Avoid the cost of LookupTable() for a single-character search.
    156  if (s.length_ == 1) return find_first_of(s.ptr_[0], pos);
    157  LookupTable tbl(s);
    158  for (size_type i = pos; i < length_; ++i) {
    159    if (tbl[ptr_[i]]) {
    160      return i;
    161    }
    162  }
    163  return npos;
    164 }
    165 
    166 string_view::size_type string_view::find_first_not_of(
    167    string_view s, size_type pos) const noexcept {
    168  if (empty()) return npos;
    169  // Avoid the cost of LookupTable() for a single-character search.
    170  if (s.length_ == 1) return find_first_not_of(s.ptr_[0], pos);
    171  LookupTable tbl(s);
    172  for (size_type i = pos; i < length_; ++i) {
    173    if (!tbl[ptr_[i]]) {
    174      return i;
    175    }
    176  }
    177  return npos;
    178 }
    179 
    180 string_view::size_type string_view::find_first_not_of(
    181    char c, size_type pos) const noexcept {
    182  if (empty()) return npos;
    183  for (; pos < length_; ++pos) {
    184    if (ptr_[pos] != c) {
    185      return pos;
    186    }
    187  }
    188  return npos;
    189 }
    190 
    191 string_view::size_type string_view::find_last_of(string_view s,
    192                                                 size_type pos) const noexcept {
    193  if (empty() || s.empty()) return npos;
    194  // Avoid the cost of LookupTable() for a single-character search.
    195  if (s.length_ == 1) return find_last_of(s.ptr_[0], pos);
    196  LookupTable tbl(s);
    197  for (size_type i = std::min(pos, length_ - 1);; --i) {
    198    if (tbl[ptr_[i]]) {
    199      return i;
    200    }
    201    if (i == 0) break;
    202  }
    203  return npos;
    204 }
    205 
    206 string_view::size_type string_view::find_last_not_of(
    207    string_view s, size_type pos) const noexcept {
    208  if (empty()) return npos;
    209  size_type i = std::min(pos, length_ - 1);
    210  if (s.empty()) return i;
    211  // Avoid the cost of LookupTable() for a single-character search.
    212  if (s.length_ == 1) return find_last_not_of(s.ptr_[0], pos);
    213  LookupTable tbl(s);
    214  for (;; --i) {
    215    if (!tbl[ptr_[i]]) {
    216      return i;
    217    }
    218    if (i == 0) break;
    219  }
    220  return npos;
    221 }
    222 
    223 string_view::size_type string_view::find_last_not_of(
    224    char c, size_type pos) const noexcept {
    225  if (empty()) return npos;
    226  size_type i = std::min(pos, length_ - 1);
    227  for (;; --i) {
    228    if (ptr_[i] != c) {
    229      return i;
    230    }
    231    if (i == 0) break;
    232  }
    233  return npos;
    234 }
    235 
    236 ABSL_NAMESPACE_END
    237 }  // namespace absl
    238 
    239 #else
    240 
    241 // https://github.com/abseil/abseil-cpp/issues/1465
    242 // CMake builds on Apple platforms error when libraries are empty.
    243 // Our CMake configuration can avoid this error on header-only libraries,
    244 // but since this library is conditionally empty, including a single
    245 // variable is an easy workaround.
    246 #ifdef __APPLE__
    247 namespace absl {
    248 ABSL_NAMESPACE_BEGIN
    249 namespace strings_internal {
    250 extern const char kAvoidEmptyStringViewLibraryWarning;
    251 const char kAvoidEmptyStringViewLibraryWarning = 0;
    252 }  // namespace strings_internal
    253 ABSL_NAMESPACE_END
    254 }  // namespace absl
    255 #endif  // __APPLE__
    256 
    257 #endif  // ABSL_USES_STD_STRING_VIEW