tor-browser

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

extension.h (14341B)


      1 //
      2 // Copyright 2017 The Abseil Authors.
      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 //      https://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 #ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
     17 #define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
     18 
     19 
     20 #include <cstddef>
     21 #include <cstdint>
     22 #include <cstring>
     23 #include <ostream>
     24 #include <string>
     25 
     26 #include "absl/base/config.h"
     27 #include "absl/strings/internal/str_format/output.h"
     28 #include "absl/strings/string_view.h"
     29 
     30 namespace absl {
     31 ABSL_NAMESPACE_BEGIN
     32 
     33 enum class FormatConversionChar : uint8_t;
     34 enum class FormatConversionCharSet : uint64_t;
     35 enum class LengthMod : std::uint8_t { h, hh, l, ll, L, j, z, t, q, none };
     36 
     37 namespace str_format_internal {
     38 
     39 class FormatRawSinkImpl {
     40 public:
     41  // Implicitly convert from any type that provides the hook function as
     42  // described above.
     43  template <typename T, decltype(str_format_internal::InvokeFlush(
     44                            std::declval<T*>(), string_view()))* = nullptr>
     45  FormatRawSinkImpl(T* raw)  // NOLINT
     46      : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}
     47 
     48  void Write(string_view s) { write_(sink_, s); }
     49 
     50  template <typename T>
     51  static FormatRawSinkImpl Extract(T s) {
     52    return s.sink_;
     53  }
     54 
     55 private:
     56  template <typename T>
     57  static void Flush(void* r, string_view s) {
     58    str_format_internal::InvokeFlush(static_cast<T*>(r), s);
     59  }
     60 
     61  void* sink_;
     62  void (*write_)(void*, string_view);
     63 };
     64 
     65 // An abstraction to which conversions write their string data.
     66 class FormatSinkImpl {
     67 public:
     68  explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}
     69 
     70  ~FormatSinkImpl() { Flush(); }
     71 
     72  void Flush() {
     73    raw_.Write(string_view(buf_, static_cast<size_t>(pos_ - buf_)));
     74    pos_ = buf_;
     75  }
     76 
     77  void Append(size_t n, char c) {
     78    if (n == 0) return;
     79    size_ += n;
     80    auto raw_append = [&](size_t count) {
     81      memset(pos_, c, count);
     82      pos_ += count;
     83    };
     84    while (n > Avail()) {
     85      n -= Avail();
     86      if (Avail() > 0) {
     87        raw_append(Avail());
     88      }
     89      Flush();
     90    }
     91    raw_append(n);
     92  }
     93 
     94  void Append(string_view v) {
     95    size_t n = v.size();
     96    if (n == 0) return;
     97    size_ += n;
     98    if (n >= Avail()) {
     99      Flush();
    100      raw_.Write(v);
    101      return;
    102    }
    103    memcpy(pos_, v.data(), n);
    104    pos_ += n;
    105  }
    106 
    107  size_t size() const { return size_; }
    108 
    109  // Put 'v' to 'sink' with specified width, precision, and left flag.
    110  bool PutPaddedString(string_view v, int width, int precision, bool left);
    111 
    112  template <typename T>
    113  T Wrap() {
    114    return T(this);
    115  }
    116 
    117  template <typename T>
    118  static FormatSinkImpl* Extract(T* s) {
    119    return s->sink_;
    120  }
    121 
    122 private:
    123  size_t Avail() const {
    124    return static_cast<size_t>(buf_ + sizeof(buf_) - pos_);
    125  }
    126 
    127  FormatRawSinkImpl raw_;
    128  size_t size_ = 0;
    129  char* pos_ = buf_;
    130  char buf_[1024];
    131 };
    132 
    133 enum class Flags : uint8_t {
    134  kBasic = 0,
    135  kLeft = 1 << 0,
    136  kShowPos = 1 << 1,
    137  kSignCol = 1 << 2,
    138  kAlt = 1 << 3,
    139  kZero = 1 << 4,
    140  // This is not a real flag. It just exists to turn off kBasic when no other
    141  // flags are set. This is for when width/precision are specified, or a length
    142  // modifier affects the behavior ("%lc").
    143  kNonBasic = 1 << 5,
    144 };
    145 
    146 constexpr Flags operator|(Flags a, Flags b) {
    147  return static_cast<Flags>(static_cast<uint8_t>(a) | static_cast<uint8_t>(b));
    148 }
    149 
    150 constexpr bool FlagsContains(Flags haystack, Flags needle) {
    151  return (static_cast<uint8_t>(haystack) & static_cast<uint8_t>(needle)) ==
    152         static_cast<uint8_t>(needle);
    153 }
    154 
    155 std::string FlagsToString(Flags v);
    156 
    157 inline std::ostream& operator<<(std::ostream& os, Flags v) {
    158  return os << FlagsToString(v);
    159 }
    160 
    161 // clang-format off
    162 #define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \
    163  /* text */ \
    164  X_VAL(c) X_SEP X_VAL(s) X_SEP \
    165  /* ints */ \
    166  X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \
    167  X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \
    168  /* floats */ \
    169  X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \
    170  X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \
    171  /* misc */ \
    172  X_VAL(n) X_SEP X_VAL(p) X_SEP X_VAL(v)
    173 // clang-format on
    174 
    175 // This type should not be referenced, it exists only to provide labels
    176 // internally that match the values declared in FormatConversionChar in
    177 // str_format.h. This is meant to allow internal libraries to use the same
    178 // declared interface type as the public interface
    179 // (absl::StrFormatConversionChar) while keeping the definition in a public
    180 // header.
    181 // Internal libraries should use the form
    182 // `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for
    183 // comparisons.  Use in switch statements is not recommended due to a bug in how
    184 // gcc 4.9 -Wswitch handles declared but undefined enums.
    185 struct FormatConversionCharInternal {
    186  FormatConversionCharInternal() = delete;
    187 
    188 private:
    189  // clang-format off
    190  enum class Enum : uint8_t {
    191    c, s,                    // text
    192    d, i, o, u, x, X,        // int
    193    f, F, e, E, g, G, a, A,  // float
    194    n, p, v,                    // misc
    195    kNone
    196  };
    197  // clang-format on
    198 public:
    199 #define ABSL_INTERNAL_X_VAL(id)              \
    200  static constexpr FormatConversionChar id = \
    201      static_cast<FormatConversionChar>(Enum::id);
    202  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
    203 #undef ABSL_INTERNAL_X_VAL
    204  static constexpr FormatConversionChar kNone =
    205      static_cast<FormatConversionChar>(Enum::kNone);
    206 };
    207 // clang-format on
    208 
    209 inline FormatConversionChar FormatConversionCharFromChar(char c) {
    210  switch (c) {
    211 #define ABSL_INTERNAL_X_VAL(id) \
    212  case #id[0]:                  \
    213    return FormatConversionCharInternal::id;
    214    ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )
    215 #undef ABSL_INTERNAL_X_VAL
    216  }
    217  return FormatConversionCharInternal::kNone;
    218 }
    219 
    220 inline bool FormatConversionCharIsUpper(FormatConversionChar c) {
    221  if (c == FormatConversionCharInternal::X ||
    222      c == FormatConversionCharInternal::F ||
    223      c == FormatConversionCharInternal::E ||
    224      c == FormatConversionCharInternal::G ||
    225      c == FormatConversionCharInternal::A) {
    226    return true;
    227  } else {
    228    return false;
    229  }
    230 }
    231 
    232 inline bool FormatConversionCharIsFloat(FormatConversionChar c) {
    233  if (c == FormatConversionCharInternal::a ||
    234      c == FormatConversionCharInternal::e ||
    235      c == FormatConversionCharInternal::f ||
    236      c == FormatConversionCharInternal::g ||
    237      c == FormatConversionCharInternal::A ||
    238      c == FormatConversionCharInternal::E ||
    239      c == FormatConversionCharInternal::F ||
    240      c == FormatConversionCharInternal::G) {
    241    return true;
    242  } else {
    243    return false;
    244  }
    245 }
    246 
    247 inline char FormatConversionCharToChar(FormatConversionChar c) {
    248  if (c == FormatConversionCharInternal::kNone) {
    249    return '\0';
    250 
    251 #define ABSL_INTERNAL_X_VAL(e)                       \
    252  } else if (c == FormatConversionCharInternal::e) { \
    253    return #e[0];
    254 #define ABSL_INTERNAL_X_SEP
    255  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,
    256                                         ABSL_INTERNAL_X_SEP)
    257  } else {
    258    return '\0';
    259  }
    260 
    261 #undef ABSL_INTERNAL_X_VAL
    262 #undef ABSL_INTERNAL_X_SEP
    263 }
    264 
    265 // The associated char.
    266 inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {
    267  char c = FormatConversionCharToChar(v);
    268  if (!c) c = '?';
    269  return os << c;
    270 }
    271 
    272 struct FormatConversionSpecImplFriend;
    273 
    274 class FormatConversionSpecImpl {
    275 public:
    276  // Width and precision are not specified, no flags are set.
    277  bool is_basic() const { return flags_ == Flags::kBasic; }
    278  bool has_left_flag() const { return FlagsContains(flags_, Flags::kLeft); }
    279  bool has_show_pos_flag() const {
    280    return FlagsContains(flags_, Flags::kShowPos);
    281  }
    282  bool has_sign_col_flag() const {
    283    return FlagsContains(flags_, Flags::kSignCol);
    284  }
    285  bool has_alt_flag() const { return FlagsContains(flags_, Flags::kAlt); }
    286  bool has_zero_flag() const { return FlagsContains(flags_, Flags::kZero); }
    287 
    288  LengthMod length_mod() const { return length_mod_; }
    289 
    290  FormatConversionChar conversion_char() const {
    291    // Keep this field first in the struct . It generates better code when
    292    // accessing it when ConversionSpec is passed by value in registers.
    293    static_assert(offsetof(FormatConversionSpecImpl, conv_) == 0, "");
    294    return conv_;
    295  }
    296 
    297  void set_conversion_char(FormatConversionChar c) { conv_ = c; }
    298 
    299  // Returns the specified width. If width is unspecfied, it returns a negative
    300  // value.
    301  int width() const { return width_; }
    302  // Returns the specified precision. If precision is unspecfied, it returns a
    303  // negative value.
    304  int precision() const { return precision_; }
    305 
    306  template <typename T>
    307  T Wrap() {
    308    return T(*this);
    309  }
    310 
    311 private:
    312  friend struct str_format_internal::FormatConversionSpecImplFriend;
    313  FormatConversionChar conv_ = FormatConversionCharInternal::kNone;
    314  Flags flags_;
    315  LengthMod length_mod_ = LengthMod::none;
    316  int width_;
    317  int precision_;
    318 };
    319 
    320 struct FormatConversionSpecImplFriend final {
    321  static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {
    322    conv->flags_ = f;
    323  }
    324  static void SetLengthMod(LengthMod l, FormatConversionSpecImpl* conv) {
    325    conv->length_mod_ = l;
    326  }
    327  static void SetConversionChar(FormatConversionChar c,
    328                                FormatConversionSpecImpl* conv) {
    329    conv->conv_ = c;
    330  }
    331  static void SetWidth(int w, FormatConversionSpecImpl* conv) {
    332    conv->width_ = w;
    333  }
    334  static void SetPrecision(int p, FormatConversionSpecImpl* conv) {
    335    conv->precision_ = p;
    336  }
    337  static std::string FlagsToString(const FormatConversionSpecImpl& spec) {
    338    return str_format_internal::FlagsToString(spec.flags_);
    339  }
    340 };
    341 
    342 // Type safe OR operator.
    343 // We need this for two reasons:
    344 //  1. operator| on enums makes them decay to integers and the result is an
    345 //     integer. We need the result to stay as an enum.
    346 //  2. We use "enum class" which would not work even if we accepted the decay.
    347 constexpr FormatConversionCharSet FormatConversionCharSetUnion(
    348    FormatConversionCharSet a) {
    349  return a;
    350 }
    351 
    352 template <typename... CharSet>
    353 constexpr FormatConversionCharSet FormatConversionCharSetUnion(
    354    FormatConversionCharSet a, CharSet... rest) {
    355  return static_cast<FormatConversionCharSet>(
    356      static_cast<uint64_t>(a) |
    357      static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));
    358 }
    359 
    360 constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {
    361  return uint64_t{1} << (1 + static_cast<uint8_t>(c));
    362 }
    363 
    364 constexpr uint64_t FormatConversionCharToConvInt(char conv) {
    365  return
    366 #define ABSL_INTERNAL_CHAR_SET_CASE(c)                                 \
    367  conv == #c[0]                                                        \
    368      ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \
    369      :
    370      ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
    371 #undef ABSL_INTERNAL_CHAR_SET_CASE
    372                  conv == '*'
    373          ? 1
    374          : 0;
    375 }
    376 
    377 constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {
    378  return static_cast<FormatConversionCharSet>(
    379      FormatConversionCharToConvInt(conv));
    380 }
    381 
    382 struct FormatConversionCharSetInternal {
    383 #define ABSL_INTERNAL_CHAR_SET_CASE(c)         \
    384  static constexpr FormatConversionCharSet c = \
    385      FormatConversionCharToConvValue(#c[0]);
    386  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )
    387 #undef ABSL_INTERNAL_CHAR_SET_CASE
    388 
    389  // Used for width/precision '*' specification.
    390  static constexpr FormatConversionCharSet kStar =
    391      FormatConversionCharToConvValue('*');
    392 
    393  static constexpr FormatConversionCharSet kIntegral =
    394      FormatConversionCharSetUnion(d, i, u, o, x, X);
    395  static constexpr FormatConversionCharSet kFloating =
    396      FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);
    397  static constexpr FormatConversionCharSet kNumeric =
    398      FormatConversionCharSetUnion(kIntegral, kFloating);
    399  static constexpr FormatConversionCharSet kPointer = p;
    400 };
    401 
    402 // Type safe OR operator.
    403 // We need this for two reasons:
    404 //  1. operator| on enums makes them decay to integers and the result is an
    405 //     integer. We need the result to stay as an enum.
    406 //  2. We use "enum class" which would not work even if we accepted the decay.
    407 constexpr FormatConversionCharSet operator|(FormatConversionCharSet a,
    408                                            FormatConversionCharSet b) {
    409  return FormatConversionCharSetUnion(a, b);
    410 }
    411 
    412 // Overloaded conversion functions to support absl::ParsedFormat.
    413 // Get a conversion with a single character in it.
    414 constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {
    415  return static_cast<FormatConversionCharSet>(
    416      FormatConversionCharToConvValue(c));
    417 }
    418 
    419 // Get a conversion with a single character in it.
    420 constexpr FormatConversionCharSet ToFormatConversionCharSet(
    421    FormatConversionCharSet c) {
    422  return c;
    423 }
    424 
    425 template <typename T>
    426 void ToFormatConversionCharSet(T) = delete;
    427 
    428 // Checks whether `c` exists in `set`.
    429 constexpr bool Contains(FormatConversionCharSet set, char c) {
    430  return (static_cast<uint64_t>(set) &
    431          static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;
    432 }
    433 
    434 // Checks whether all the characters in `c` are contained in `set`
    435 constexpr bool Contains(FormatConversionCharSet set,
    436                        FormatConversionCharSet c) {
    437  return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==
    438         static_cast<uint64_t>(c);
    439 }
    440 
    441 // Checks whether all the characters in `c` are contained in `set`
    442 constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {
    443  return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;
    444 }
    445 
    446 // Return capacity - used, clipped to a minimum of 0.
    447 inline size_t Excess(size_t used, size_t capacity) {
    448  return used < capacity ? capacity - used : 0;
    449 }
    450 
    451 }  // namespace str_format_internal
    452 
    453 ABSL_NAMESPACE_END
    454 }  // namespace absl
    455 
    456 #endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_