| // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 
 | // Use of this source code is governed by a BSD-style license that can be | 
 | // found in the LICENSE file. | 
 | // | 
 | // A string-like object that points to a sized piece of memory. | 
 | // | 
 | // You can use StringPiece as a function or method parameter.  A StringPiece | 
 | // parameter can receive a double-quoted string literal argument, a "const | 
 | // char*" argument, a string argument, or a StringPiece argument with no data | 
 | // copying.  Systematic use of StringPiece for arguments reduces data | 
 | // copies and strlen() calls. | 
 | // | 
 | // Prefer passing StringPieces by value: | 
 | //   void MyFunction(StringPiece arg); | 
 | // If circumstances require, you may also pass by const reference: | 
 | //   void MyFunction(const StringPiece& arg);  // not preferred | 
 | // Both of these have the same lifetime semantics.  Passing by value | 
 | // generates slightly smaller code.  For more discussion, Googlers can see | 
 | // the thread go/stringpiecebyvalue on c-users. | 
 |  | 
 | #ifndef BASE_STRINGS_STRING_PIECE_H_ | 
 | #define BASE_STRINGS_STRING_PIECE_H_ | 
 |  | 
 | #include <stddef.h> | 
 |  | 
 | #include <algorithm> | 
 | #include <iosfwd> | 
 | #include <limits> | 
 | #include <string> | 
 | #include <type_traits> | 
 |  | 
 | #include "polyfills/base/base_export.h" | 
 | #include "polyfills/base/check.h" | 
 | #include "polyfills/base/check_op.h" | 
 | #include "base/compiler_specific.h" | 
 | #include "base/strings/string_piece_forward.h" | 
 | #include "build/build_config.h" | 
 |  | 
 | namespace gurl_base { | 
 |  | 
 | // internal -------------------------------------------------------------------- | 
 |  | 
 | // Many of the StringPiece functions use different implementations for the | 
 | // 8-bit and 16-bit versions, and we don't want lots of template expansions in | 
 | // this (very common) header that will slow down compilation. | 
 | // | 
 | // So here we define overloaded functions called by the StringPiece template. | 
 | // For those that share an implementation, the two versions will expand to a | 
 | // template internal to the .cc file. | 
 | namespace internal { | 
 |  | 
 | BASE_EXPORT size_t find(StringPiece self, StringPiece s, size_t pos); | 
 | BASE_EXPORT size_t find(StringPiece16 self, StringPiece16 s, size_t pos); | 
 |  | 
 | BASE_EXPORT size_t rfind(StringPiece self, StringPiece s, size_t pos); | 
 | BASE_EXPORT size_t rfind(StringPiece16 self, StringPiece16 s, size_t pos); | 
 |  | 
 | BASE_EXPORT size_t find_first_of(StringPiece self, StringPiece s, size_t pos); | 
 | BASE_EXPORT size_t find_first_of(StringPiece16 self, | 
 |                                  StringPiece16 s, | 
 |                                  size_t pos); | 
 |  | 
 | BASE_EXPORT size_t find_first_not_of(StringPiece self, | 
 |                                      StringPiece s, | 
 |                                      size_t pos); | 
 | BASE_EXPORT size_t find_first_not_of(StringPiece16 self, | 
 |                                      StringPiece16 s, | 
 |                                      size_t pos); | 
 |  | 
 | BASE_EXPORT size_t find_last_of(StringPiece self, StringPiece s, size_t pos); | 
 | BASE_EXPORT size_t find_last_of(StringPiece16 self, | 
 |                                 StringPiece16 s, | 
 |                                 size_t pos); | 
 |  | 
 | BASE_EXPORT size_t find_last_not_of(StringPiece self, | 
 |                                     StringPiece s, | 
 |                                     size_t pos); | 
 | BASE_EXPORT size_t find_last_not_of(StringPiece16 self, | 
 |                                     StringPiece16 s, | 
 |                                     size_t pos); | 
 |  | 
 | BASE_EXPORT size_t find(WStringPiece self, WStringPiece s, size_t pos); | 
 | BASE_EXPORT size_t rfind(WStringPiece self, WStringPiece s, size_t pos); | 
 | BASE_EXPORT size_t find_first_of(WStringPiece self, WStringPiece s, size_t pos); | 
 | BASE_EXPORT size_t find_first_not_of(WStringPiece self, | 
 |                                      WStringPiece s, | 
 |                                      size_t pos); | 
 | BASE_EXPORT size_t find_last_of(WStringPiece self, WStringPiece s, size_t pos); | 
 | BASE_EXPORT size_t find_last_not_of(WStringPiece self, | 
 |                                     WStringPiece s, | 
 |                                     size_t pos); | 
 |  | 
 | }  // namespace internal | 
 |  | 
 | // BasicStringPiece ------------------------------------------------------------ | 
 |  | 
 | // Mirrors the C++17 version of std::basic_string_view<> as closely as possible, | 
 | // except where noted below. | 
 | template <typename CharT, typename Traits> | 
 | class GSL_POINTER BasicStringPiece { | 
 |  public: | 
 |   using traits_type = Traits; | 
 |   using value_type = CharT; | 
 |   using pointer = CharT*; | 
 |   using const_pointer = const CharT*; | 
 |   using reference = CharT&; | 
 |   using const_reference = const CharT&; | 
 |   using const_iterator = const CharT*; | 
 |   using iterator = const_iterator; | 
 |   using const_reverse_iterator = std::reverse_iterator<const_iterator>; | 
 |   using reverse_iterator = const_reverse_iterator; | 
 |   using size_type = size_t; | 
 |   using difference_type = ptrdiff_t; | 
 |  | 
 |   constexpr BasicStringPiece() noexcept : ptr_(nullptr), length_(0) {} | 
 |   constexpr BasicStringPiece(const BasicStringPiece& other) noexcept = default; | 
 |   constexpr BasicStringPiece& operator=(const BasicStringPiece& view) noexcept = | 
 |       default; | 
 |   constexpr BasicStringPiece(const CharT* s, size_type count) | 
 |       : ptr_(s), length_(count) {} | 
 |   constexpr BasicStringPiece(const CharT* s) | 
 |       : ptr_(s), length_(s ? traits_type::length(s) : 0) { | 
 |     // Intentional STL deviation: Null-check instead of UB. | 
 |     GURL_CHECK(s); | 
 |   } | 
 |   // Explicitly disallow construction from nullptr. Note that this does not | 
 |   // catch construction from runtime strings that might be null. | 
 |   // Note: The following is just a more elaborate way of spelling | 
 |   // `BasicStringPiece(nullptr_t) = delete`, but unfortunately the terse form is | 
 |   // not supported by the PNaCl toolchain. | 
 |   template <class T, class = std::enable_if_t<std::is_null_pointer<T>::value>> | 
 |   BasicStringPiece(T) { | 
 |     static_assert(sizeof(T) == 0,  // Always false. | 
 |                   "StringPiece does not support construction from nullptr, use " | 
 |                   "the default constructor instead."); | 
 |   } | 
 |  | 
 |   // These are necessary because std::basic_string provides construction from | 
 |   // (an object convertible to) a std::basic_string_view, as well as an explicit | 
 |   // cast operator to a std::basic_string_view, but (obviously) not from/to a | 
 |   // BasicStringPiece. | 
 |   BasicStringPiece(const std::basic_string<CharT>& str) | 
 |       : ptr_(str.data()), length_(str.size()) {} | 
 |   explicit operator std::basic_string<CharT>() const { | 
 |     return std::basic_string<CharT>(data(), size()); | 
 |   } | 
 |  | 
 |   constexpr const_iterator begin() const noexcept { return ptr_; } | 
 |   constexpr const_iterator cbegin() const noexcept { return ptr_; } | 
 |   constexpr const_iterator end() const noexcept { return ptr_ + length_; } | 
 |   constexpr const_iterator cend() const noexcept { return ptr_ + length_; } | 
 |   constexpr const_reverse_iterator rbegin() const noexcept { | 
 |     return const_reverse_iterator(ptr_ + length_); | 
 |   } | 
 |   constexpr const_reverse_iterator crbegin() const noexcept { | 
 |     return const_reverse_iterator(ptr_ + length_); | 
 |   } | 
 |   constexpr const_reverse_iterator rend() const noexcept { | 
 |     return const_reverse_iterator(ptr_); | 
 |   } | 
 |   constexpr const_reverse_iterator crend() const noexcept { | 
 |     return const_reverse_iterator(ptr_); | 
 |   } | 
 |  | 
 |   constexpr const_reference operator[](size_type pos) const { | 
 |     // Intentional STL deviation: Bounds-check instead of UB. | 
 |     return at(pos); | 
 |   } | 
 |   constexpr const_reference at(size_type pos) const { | 
 |     GURL_CHECK_LT(pos, size()); | 
 |     return data()[pos]; | 
 |   } | 
 |  | 
 |   constexpr const_reference front() const { return operator[](0); } | 
 |  | 
 |   constexpr const_reference back() const { return operator[](size() - 1); } | 
 |  | 
 |   constexpr const_pointer data() const noexcept { return ptr_; } | 
 |  | 
 |   constexpr size_type size() const noexcept { return length_; } | 
 |   constexpr size_type length() const noexcept { return length_; } | 
 |  | 
 |   constexpr size_type max_size() const { | 
 |     return std::numeric_limits<size_type>::max() / sizeof(CharT); | 
 |   } | 
 |  | 
 |   [[nodiscard]] constexpr bool empty() const noexcept { return size() == 0; } | 
 |  | 
 |   constexpr void remove_prefix(size_type n) { | 
 |     // Intentional STL deviation: Bounds-check instead of UB. | 
 |     GURL_CHECK_LE(n, size()); | 
 |     ptr_ += n; | 
 |     length_ -= n; | 
 |   } | 
 |  | 
 |   constexpr void remove_suffix(size_type n) { | 
 |     // Intentional STL deviation: Bounds-check instead of UB. | 
 |     GURL_CHECK_LE(n, size()); | 
 |     length_ -= n; | 
 |   } | 
 |  | 
 |   constexpr void swap(BasicStringPiece& v) noexcept { | 
 |     // Note: Cannot use std::swap() since it is not constexpr until C++20. | 
 |     const const_pointer ptr = ptr_; | 
 |     ptr_ = v.ptr_; | 
 |     v.ptr_ = ptr; | 
 |     const size_type length = length_; | 
 |     length_ = v.length_; | 
 |     v.length_ = length; | 
 |   } | 
 |  | 
 |   constexpr size_type copy(CharT* dest, | 
 |                            size_type count, | 
 |                            size_type pos = 0) const { | 
 |     GURL_CHECK_LE(pos, size()); | 
 |     const size_type rcount = std::min(count, size() - pos); | 
 |     traits_type::copy(dest, data() + pos, rcount); | 
 |     return rcount; | 
 |   } | 
 |  | 
 |   constexpr BasicStringPiece substr(size_type pos = 0, | 
 |                                     size_type count = npos) const { | 
 |     GURL_CHECK_LE(pos, size()); | 
 |     const size_type rcount = std::min(count, size() - pos); | 
 |     return {data() + pos, rcount}; | 
 |   } | 
 |  | 
 |   constexpr int compare(BasicStringPiece v) const noexcept { | 
 |     const size_type rlen = std::min(size(), v.size()); | 
 |     const int result = traits_type::compare(data(), v.data(), rlen); | 
 |     if (result != 0) | 
 |       return result; | 
 |     if (size() == v.size()) | 
 |       return 0; | 
 |     return size() < v.size() ? -1 : 1; | 
 |   } | 
 |   constexpr int compare(size_type pos1, | 
 |                         size_type count1, | 
 |                         BasicStringPiece v) const { | 
 |     return substr(pos1, count1).compare(v); | 
 |   } | 
 |   constexpr int compare(size_type pos1, | 
 |                         size_type count1, | 
 |                         BasicStringPiece v, | 
 |                         size_type pos2, | 
 |                         size_type count2) const { | 
 |     return substr(pos1, count1).compare(v.substr(pos2, count2)); | 
 |   } | 
 |   constexpr int compare(const CharT* s) const { | 
 |     return compare(BasicStringPiece(s)); | 
 |   } | 
 |   constexpr int compare(size_type pos1, | 
 |                         size_type count1, | 
 |                         const CharT* s) const { | 
 |     return substr(pos1, count1).compare(BasicStringPiece(s)); | 
 |   } | 
 |   constexpr int compare(size_type pos1, | 
 |                         size_type count1, | 
 |                         const CharT* s, | 
 |                         size_type count2) const { | 
 |     return substr(pos1, count1).compare(BasicStringPiece(s, count2)); | 
 |   } | 
 |  | 
 |   constexpr size_type find(BasicStringPiece v, | 
 |                            size_type pos = 0) const noexcept { | 
 |     if (is_constant_evaluated()) { | 
 |       if (v.size() > size()) | 
 |         return npos; | 
 |       for (size_type p = pos; p <= size() - v.size(); ++p) { | 
 |         if (!compare(p, v.size(), v)) | 
 |           return p; | 
 |       } | 
 |       return npos; | 
 |     } | 
 |  | 
 |     return internal::find(*this, v, pos); | 
 |   } | 
 |   constexpr size_type find(CharT ch, size_type pos = 0) const noexcept { | 
 |     if (pos >= size()) | 
 |       return npos; | 
 |  | 
 |     const const_pointer result = | 
 |         traits_type::find(data() + pos, size() - pos, ch); | 
 |     return result ? static_cast<size_type>(result - data()) : npos; | 
 |   } | 
 |   constexpr size_type find(const CharT* s, | 
 |                            size_type pos, | 
 |                            size_type count) const { | 
 |     return find(BasicStringPiece(s, count), pos); | 
 |   } | 
 |   constexpr size_type find(const CharT* s, size_type pos = 0) const { | 
 |     return find(BasicStringPiece(s), pos); | 
 |   } | 
 |  | 
 |   constexpr size_type rfind(BasicStringPiece v, | 
 |                             size_type pos = npos) const noexcept { | 
 |     if (is_constant_evaluated()) { | 
 |       if (v.size() > size()) | 
 |         return npos; | 
 |       for (size_type p = std::min(size() - v.size(), pos);; --p) { | 
 |         if (!compare(p, v.size(), v)) | 
 |           return p; | 
 |         if (!p) | 
 |           break; | 
 |       } | 
 |       return npos; | 
 |     } | 
 |  | 
 |     return internal::rfind(*this, v, pos); | 
 |   } | 
 |   constexpr size_type rfind(CharT c, size_type pos = npos) const noexcept { | 
 |     if (empty()) | 
 |       return npos; | 
 |  | 
 |     for (size_t i = std::min(pos, size() - 1);; --i) { | 
 |       if (data()[i] == c) | 
 |         return i; | 
 |  | 
 |       if (i == 0) | 
 |         break; | 
 |     } | 
 |     return npos; | 
 |   } | 
 |   constexpr size_type rfind(const CharT* s, | 
 |                             size_type pos, | 
 |                             size_type count) const { | 
 |     return rfind(BasicStringPiece(s, count), pos); | 
 |   } | 
 |   constexpr size_type rfind(const CharT* s, size_type pos = npos) const { | 
 |     return rfind(BasicStringPiece(s), pos); | 
 |   } | 
 |  | 
 |   constexpr size_type find_first_of(BasicStringPiece v, | 
 |                                     size_type pos = 0) const noexcept { | 
 |     if (is_constant_evaluated()) { | 
 |       if (empty() || v.empty()) | 
 |         return npos; | 
 |       for (size_type p = pos; p < size(); ++p) { | 
 |         if (v.find(data()[p]) != npos) | 
 |           return p; | 
 |       } | 
 |       return npos; | 
 |     } | 
 |  | 
 |     return internal::find_first_of(*this, v, pos); | 
 |   } | 
 |   constexpr size_type find_first_of(CharT c, size_type pos = 0) const noexcept { | 
 |     return find(c, pos); | 
 |   } | 
 |   constexpr size_type find_first_of(const CharT* s, | 
 |                                     size_type pos, | 
 |                                     size_type count) const { | 
 |     return find_first_of(BasicStringPiece(s, count), pos); | 
 |   } | 
 |   constexpr size_type find_first_of(const CharT* s, size_type pos = 0) const { | 
 |     return find_first_of(BasicStringPiece(s), pos); | 
 |   } | 
 |  | 
 |   constexpr size_type find_last_of(BasicStringPiece v, | 
 |                                    size_type pos = npos) const noexcept { | 
 |     if (is_constant_evaluated()) { | 
 |       if (empty() || v.empty()) | 
 |         return npos; | 
 |       for (size_type p = std::min(pos, size() - 1);; --p) { | 
 |         if (v.find(data()[p]) != npos) | 
 |           return p; | 
 |         if (!p) | 
 |           break; | 
 |       } | 
 |       return npos; | 
 |     } | 
 |  | 
 |     return internal::find_last_of(*this, v, pos); | 
 |   } | 
 |   constexpr size_type find_last_of(CharT c, | 
 |                                    size_type pos = npos) const noexcept { | 
 |     return rfind(c, pos); | 
 |   } | 
 |   constexpr size_type find_last_of(const CharT* s, | 
 |                                    size_type pos, | 
 |                                    size_type count) const { | 
 |     return find_last_of(BasicStringPiece(s, count), pos); | 
 |   } | 
 |   constexpr size_type find_last_of(const CharT* s, size_type pos = npos) const { | 
 |     return find_last_of(BasicStringPiece(s), pos); | 
 |   } | 
 |  | 
 |   constexpr size_type find_first_not_of(BasicStringPiece v, | 
 |                                         size_type pos = 0) const noexcept { | 
 |     if (is_constant_evaluated()) { | 
 |       if (empty()) | 
 |         return npos; | 
 |       for (size_type p = pos; p < size(); ++p) { | 
 |         if (v.find(data()[p]) == npos) | 
 |           return p; | 
 |       } | 
 |       return npos; | 
 |     } | 
 |  | 
 |     return internal::find_first_not_of(*this, v, pos); | 
 |   } | 
 |   constexpr size_type find_first_not_of(CharT c, | 
 |                                         size_type pos = 0) const noexcept { | 
 |     if (empty()) | 
 |       return npos; | 
 |  | 
 |     for (; pos < size(); ++pos) { | 
 |       if (data()[pos] != c) | 
 |         return pos; | 
 |     } | 
 |     return npos; | 
 |   } | 
 |   constexpr size_type find_first_not_of(const CharT* s, | 
 |                                         size_type pos, | 
 |                                         size_type count) const { | 
 |     return find_first_not_of(BasicStringPiece(s, count), pos); | 
 |   } | 
 |   constexpr size_type find_first_not_of(const CharT* s, | 
 |                                         size_type pos = 0) const { | 
 |     return find_first_not_of(BasicStringPiece(s), pos); | 
 |   } | 
 |  | 
 |   constexpr size_type find_last_not_of(BasicStringPiece v, | 
 |                                        size_type pos = npos) const noexcept { | 
 |     if (is_constant_evaluated()) { | 
 |       if (empty()) | 
 |         return npos; | 
 |       for (size_type p = std::min(pos, size() - 1);; --p) { | 
 |         if (v.find(data()[p]) == npos) | 
 |           return p; | 
 |         if (!p) | 
 |           break; | 
 |       } | 
 |       return npos; | 
 |     } | 
 |  | 
 |     return internal::find_last_not_of(*this, v, pos); | 
 |   } | 
 |   constexpr size_type find_last_not_of(CharT c, | 
 |                                        size_type pos = npos) const noexcept { | 
 |     if (empty()) | 
 |       return npos; | 
 |  | 
 |     for (size_t i = std::min(pos, size() - 1);; --i) { | 
 |       if (data()[i] != c) | 
 |         return i; | 
 |       if (i == 0) | 
 |         break; | 
 |     } | 
 |     return npos; | 
 |   } | 
 |   constexpr size_type find_last_not_of(const CharT* s, | 
 |                                        size_type pos, | 
 |                                        size_type count) const { | 
 |     return find_last_not_of(BasicStringPiece(s, count), pos); | 
 |   } | 
 |   constexpr size_type find_last_not_of(const CharT* s, | 
 |                                        size_type pos = npos) const { | 
 |     return find_last_not_of(BasicStringPiece(s), pos); | 
 |   } | 
 |  | 
 |   static constexpr size_type npos = size_type(-1); | 
 |  | 
 |  protected: | 
 |   const_pointer ptr_; | 
 |   size_type length_; | 
 | }; | 
 |  | 
 | // static | 
 | template <typename CharT, typename Traits> | 
 | const typename BasicStringPiece<CharT, Traits>::size_type | 
 |     BasicStringPiece<CharT, Traits>::npos; | 
 |  | 
 | // MSVC doesn't like complex extern templates and DLLs. | 
 | #if !defined(COMPILER_MSVC) | 
 | extern template class BASE_EXPORT BasicStringPiece<char>; | 
 | extern template class BASE_EXPORT BasicStringPiece<char16_t>; | 
 | #endif | 
 |  | 
 | template <typename CharT, typename Traits> | 
 | constexpr bool operator==(BasicStringPiece<CharT, Traits> lhs, | 
 |                           BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; | 
 | } | 
 | // Here and below we make use of std::common_type_t to emulate | 
 | // std::type_identity (part of C++20). This creates a non-deduced context, so | 
 | // that we can compare StringPieces with types that implicitly convert to | 
 | // StringPieces. See https://wg21.link/n3766 for details. | 
 | // Furthermore, we require dummy template parameters for these overloads to work | 
 | // around a name mangling issue on Windows. | 
 | template <typename CharT, typename Traits, int = 1> | 
 | constexpr bool operator==( | 
 |     BasicStringPiece<CharT, Traits> lhs, | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> rhs) noexcept { | 
 |   return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; | 
 | } | 
 | template <typename CharT, typename Traits, int = 2> | 
 | constexpr bool operator==( | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> lhs, | 
 |     BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return lhs.size() == rhs.size() && lhs.compare(rhs) == 0; | 
 | } | 
 |  | 
 | template <typename CharT, typename Traits> | 
 | constexpr bool operator!=(BasicStringPiece<CharT, Traits> lhs, | 
 |                           BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return !(lhs == rhs); | 
 | } | 
 | template <typename CharT, typename Traits, int = 1> | 
 | constexpr bool operator!=( | 
 |     BasicStringPiece<CharT, Traits> lhs, | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> rhs) noexcept { | 
 |   return !(lhs == rhs); | 
 | } | 
 | template <typename CharT, typename Traits, int = 2> | 
 | constexpr bool operator!=( | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> lhs, | 
 |     BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return !(lhs == rhs); | 
 | } | 
 |  | 
 | template <typename CharT, typename Traits> | 
 | constexpr bool operator<(BasicStringPiece<CharT, Traits> lhs, | 
 |                          BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return lhs.compare(rhs) < 0; | 
 | } | 
 | template <typename CharT, typename Traits, int = 1> | 
 | constexpr bool operator<( | 
 |     BasicStringPiece<CharT, Traits> lhs, | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> rhs) noexcept { | 
 |   return lhs.compare(rhs) < 0; | 
 | } | 
 |  | 
 | template <typename CharT, typename Traits, int = 2> | 
 | constexpr bool operator<( | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> lhs, | 
 |     BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return lhs.compare(rhs) < 0; | 
 | } | 
 |  | 
 | template <typename CharT, typename Traits> | 
 | constexpr bool operator>(BasicStringPiece<CharT, Traits> lhs, | 
 |                          BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return rhs < lhs; | 
 | } | 
 | template <typename CharT, typename Traits, int = 1> | 
 | constexpr bool operator>( | 
 |     BasicStringPiece<CharT, Traits> lhs, | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> rhs) noexcept { | 
 |   return rhs < lhs; | 
 | } | 
 | template <typename CharT, typename Traits, int = 2> | 
 | constexpr bool operator>( | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> lhs, | 
 |     BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return rhs < lhs; | 
 | } | 
 |  | 
 | template <typename CharT, typename Traits> | 
 | constexpr bool operator<=(BasicStringPiece<CharT, Traits> lhs, | 
 |                           BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return !(rhs < lhs); | 
 | } | 
 | template <typename CharT, typename Traits, int = 1> | 
 | constexpr bool operator<=( | 
 |     BasicStringPiece<CharT, Traits> lhs, | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> rhs) noexcept { | 
 |   return !(rhs < lhs); | 
 | } | 
 | template <typename CharT, typename Traits, int = 2> | 
 | constexpr bool operator<=( | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> lhs, | 
 |     BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return !(rhs < lhs); | 
 | } | 
 |  | 
 | template <typename CharT, typename Traits> | 
 | constexpr bool operator>=(BasicStringPiece<CharT, Traits> lhs, | 
 |                           BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return !(lhs < rhs); | 
 | } | 
 | template <typename CharT, typename Traits, int = 1> | 
 | constexpr bool operator>=( | 
 |     BasicStringPiece<CharT, Traits> lhs, | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> rhs) noexcept { | 
 |   return !(lhs < rhs); | 
 | } | 
 | template <typename CharT, typename Traits, int = 2> | 
 | constexpr bool operator>=( | 
 |     std::common_type_t<BasicStringPiece<CharT, Traits>> lhs, | 
 |     BasicStringPiece<CharT, Traits> rhs) noexcept { | 
 |   return !(lhs < rhs); | 
 | } | 
 |  | 
 | BASE_EXPORT std::ostream& operator<<(std::ostream& o, StringPiece piece); | 
 | // Not in the STL: convenience functions to output non-UTF-8 strings to an | 
 | // 8-bit-width stream. | 
 | BASE_EXPORT std::ostream& operator<<(std::ostream& o, StringPiece16 piece); | 
 | BASE_EXPORT std::ostream& operator<<(std::ostream& o, WStringPiece piece); | 
 |  | 
 | // Intentionally omitted (since Chromium does not use character literals): | 
 | // operator""sv. | 
 |  | 
 | // Stand-ins for the STL's std::hash<> specializations. | 
 | template <typename StringPieceType> | 
 | struct StringPieceHashImpl { | 
 |   // This is a custom hash function. We don't use the ones already defined for | 
 |   // string and std::u16string directly because it would require the string | 
 |   // constructors to be called, which we don't want. | 
 |   std::size_t operator()(StringPieceType sp) const { | 
 |     std::size_t result = 0; | 
 |     for (auto c : sp) | 
 |       result = (result * 131) + c; | 
 |     return result; | 
 |   } | 
 | }; | 
 | using StringPieceHash = StringPieceHashImpl<StringPiece>; | 
 | using StringPiece16Hash = StringPieceHashImpl<StringPiece16>; | 
 | using WStringPieceHash = StringPieceHashImpl<WStringPiece>; | 
 |  | 
 | }  // namespace base | 
 |  | 
 | #endif  // BASE_STRINGS_STRING_PIECE_H_ |