| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 | //// Copyright 2017 The Abseil Authors.//// Licensed under the Apache License, Version 2.0 (the "License");// you may not use this file except in compliance with the License.// You may obtain a copy of the License at////      https://www.apache.org/licenses/LICENSE-2.0//// Unless required by applicable law or agreed to in writing, software// distributed under the License is distributed on an "AS IS" BASIS,// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.// See the License for the specific language governing permissions and// limitations under the License.//#ifndef ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_#define ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_#include <limits.h>#include <cstddef>#include <cstring>#include <ostream>#include "absl/base/port.h"#include "absl/strings/internal/str_format/output.h"#include "absl/strings/string_view.h"class Cord;namespace absl {namespace str_format_internal {class FormatRawSinkImpl { public:  // Implicitly convert from any type that provides the hook function as  // described above.  template <typename T, decltype(str_format_internal::InvokeFlush(                            std::declval<T*>(), string_view()))* = nullptr>  FormatRawSinkImpl(T* raw)  // NOLINT      : sink_(raw), write_(&FormatRawSinkImpl::Flush<T>) {}  void Write(string_view s) { write_(sink_, s); }  template <typename T>  static FormatRawSinkImpl Extract(T s) {    return s.sink_;  } private:  template <typename T>  static void Flush(void* r, string_view s) {    str_format_internal::InvokeFlush(static_cast<T*>(r), s);  }  void* sink_;  void (*write_)(void*, string_view);};// An abstraction to which conversions write their string data.class FormatSinkImpl { public:  explicit FormatSinkImpl(FormatRawSinkImpl raw) : raw_(raw) {}  ~FormatSinkImpl() { Flush(); }  void Flush() {    raw_.Write(string_view(buf_, pos_ - buf_));    pos_ = buf_;  }  void Append(size_t n, char c) {    if (n == 0) return;    size_ += n;    auto raw_append = [&](size_t count) {      memset(pos_, c, count);      pos_ += count;    };    while (n > Avail()) {      n -= Avail();      if (Avail() > 0) {        raw_append(Avail());      }      Flush();    }    raw_append(n);  }  void Append(string_view v) {    size_t n = v.size();    if (n == 0) return;    size_ += n;    if (n >= Avail()) {      Flush();      raw_.Write(v);      return;    }    memcpy(pos_, v.data(), n);    pos_ += n;  }  size_t size() const { return size_; }  // Put 'v' to 'sink' with specified width, precision, and left flag.  bool PutPaddedString(string_view v, int w, int p, bool l);  template <typename T>  T Wrap() {    return T(this);  }  template <typename T>  static FormatSinkImpl* Extract(T* s) {    return s->sink_;  } private:  size_t Avail() const { return buf_ + sizeof(buf_) - pos_; }  FormatRawSinkImpl raw_;  size_t size_ = 0;  char* pos_ = buf_;  char buf_[1024];};struct Flags {  bool basic : 1;     // fastest conversion: no flags, width, or precision  bool left : 1;      // "-"  bool show_pos : 1;  // "+"  bool sign_col : 1;  // " "  bool alt : 1;       // "#"  bool zero : 1;      // "0"  std::string ToString() const;  friend std::ostream& operator<<(std::ostream& os, const Flags& v) {    return os << v.ToString();  }};struct LengthMod { public:  enum Id : uint8_t {    h, hh, l, ll, L, j, z, t, q, none  };  static const size_t kNumValues = none + 1;  LengthMod() : id_(none) {}  // Index into the opaque array of LengthMod enums.  // Requires: i < kNumValues  static LengthMod FromIndex(size_t i) {    return LengthMod(kSpecs[i].value);  }  static LengthMod FromId(Id id) { return LengthMod(id); }  // The length modifier std::string associated with a specified LengthMod.  string_view name() const {    const Spec& spec = kSpecs[id_];    return {spec.name, spec.name_length};  }  Id id() const { return id_; }  friend bool operator==(const LengthMod& a, const LengthMod& b) {    return a.id() == b.id();  }  friend bool operator!=(const LengthMod& a, const LengthMod& b) {    return !(a == b);  }  friend std::ostream& operator<<(std::ostream& os, const LengthMod& v) {    return os << v.name();  } private:  struct Spec {    Id value;    const char *name;    size_t name_length;  };  static const Spec kSpecs[];  explicit LengthMod(Id id) : id_(id) {}  Id id_;};// clang-format off#define ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \  /* text */ \  X_VAL(c) X_SEP X_VAL(C) X_SEP X_VAL(s) X_SEP X_VAL(S) X_SEP \  /* ints */ \  X_VAL(d) X_SEP X_VAL(i) X_SEP X_VAL(o) X_SEP \  X_VAL(u) X_SEP X_VAL(x) X_SEP X_VAL(X) X_SEP \  /* floats */ \  X_VAL(f) X_SEP X_VAL(F) X_SEP X_VAL(e) X_SEP X_VAL(E) X_SEP \  X_VAL(g) X_SEP X_VAL(G) X_SEP X_VAL(a) X_SEP X_VAL(A) X_SEP \  /* misc */ \  X_VAL(n) X_SEP X_VAL(p)// clang-format onstruct ConversionChar { public:  enum Id : uint8_t {    c, C, s, S,              // text    d, i, o, u, x, X,        // int    f, F, e, E, g, G, a, A,  // float    n, p,                    // misc    none  };  static const size_t kNumValues = none + 1;  ConversionChar() : id_(none) {} public:  // Index into the opaque array of ConversionChar enums.  // Requires: i < kNumValues  static ConversionChar FromIndex(size_t i) {    return ConversionChar(kSpecs[i].value);  }  static ConversionChar FromChar(char c) {    ConversionChar::Id out_id = ConversionChar::none;    switch (c) {#define X_VAL(id)                \  case #id[0]:                   \    out_id = ConversionChar::id; \    break;      ABSL_CONVERSION_CHARS_EXPAND_(X_VAL, )#undef X_VAL      default:        break;    }    return ConversionChar(out_id);  }  static ConversionChar FromId(Id id) { return ConversionChar(id); }  Id id() const { return id_; }  int radix() const {    switch (id()) {      case x: case X: case a: case A: case p: return 16;      case o: return 8;      default: return 10;    }  }  bool upper() const {    switch (id()) {      case X: case F: case E: case G: case A: return true;      default: return false;    }  }  bool is_signed() const {    switch (id()) {      case d: case i: return true;      default: return false;    }  }  bool is_integral() const {    switch (id()) {      case d: case i: case u: case o: case x: case X:        return true;      default: return false;    }  }  bool is_float() const {    switch (id()) {      case a: case e: case f: case g: case A: case E: case F: case G:        return true;      default: return false;    }  }  bool IsValid() const { return id() != none; }  // The associated char.  char Char() const { return kSpecs[id_].name; }  friend bool operator==(const ConversionChar& a, const ConversionChar& b) {    return a.id() == b.id();  }  friend bool operator!=(const ConversionChar& a, const ConversionChar& b) {    return !(a == b);  }  friend std::ostream& operator<<(std::ostream& os, const ConversionChar& v) {    char c = v.Char();    if (!c) c = '?';    return os << c;  } private:  struct Spec {    Id value;    char name;  };  static const Spec kSpecs[];  explicit ConversionChar(Id id) : id_(id) {}  Id id_;};class ConversionSpec { public:  Flags flags() const { return flags_; }  LengthMod length_mod() const { return length_mod_; }  ConversionChar conv() const {    // Keep this field first in the struct . It generates better code when    // accessing it when ConversionSpec is passed by value in registers.    static_assert(offsetof(ConversionSpec, conv_) == 0, "");    return conv_;  }  // Returns the specified width. If width is unspecfied, it returns a negative  // value.  int width() const { return width_; }  // Returns the specified precision. If precision is unspecfied, it returns a  // negative value.  int precision() const { return precision_; }  void set_flags(Flags f) { flags_ = f; }  void set_length_mod(LengthMod lm) { length_mod_ = lm; }  void set_conv(ConversionChar c) { conv_ = c; }  void set_width(int w) { width_ = w; }  void set_precision(int p) { precision_ = p; }  void set_left(bool b) { flags_.left = b; } private:  ConversionChar conv_;  Flags flags_;  LengthMod length_mod_;  int width_;  int precision_;};constexpr uint64_t ConversionCharToConvValue(char conv) {  return#define CONV_SET_CASE(c) \  conv == #c[0] ? (uint64_t{1} << (1 + ConversionChar::Id::c)):      ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )#undef CONV_SET_CASE                  conv == '*'          ? 1          : 0;}enum class Conv : uint64_t {#define CONV_SET_CASE(c) c = ConversionCharToConvValue(#c[0]),  ABSL_CONVERSION_CHARS_EXPAND_(CONV_SET_CASE, )#undef CONV_SET_CASE  // Used for width/precision '*' specification.  star = ConversionCharToConvValue('*'),  // Some predefined values:  integral = d | i | u | o | x | X,  floating = a | e | f | g | A | E | F | G,  numeric = integral | floating,  string = s,  pointer = p};// Type safe OR operator.// We need this for two reasons://  1. operator| on enums makes them decay to integers and the result is an//     integer. We need the result to stay as an enum.//  2. We use "enum class" which would not work even if we accepted the decay.constexpr Conv operator|(Conv a, Conv b) {  return Conv(static_cast<uint64_t>(a) | static_cast<uint64_t>(b));}// Get a conversion with a single character in it.constexpr Conv ConversionCharToConv(char c) {  return Conv(ConversionCharToConvValue(c));}// Checks whether `c` exists in `set`.constexpr bool Contains(Conv set, char c) {  return (static_cast<uint64_t>(set) & ConversionCharToConvValue(c)) != 0;}// Checks whether all the characters in `c` are contained in `set`constexpr bool Contains(Conv set, Conv c) {  return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==         static_cast<uint64_t>(c);}// Return type of the AbslFormatConvert() functions.// The Conv template parameter is used to inform the framework of what// conversion characters are supported by that AbslFormatConvert routine.template <Conv C>struct ConvertResult {  static constexpr Conv kConv = C;  bool value;};template <Conv C>constexpr Conv ConvertResult<C>::kConv;// Return capacity - used, clipped to a minimum of 0.inline size_t Excess(size_t used, size_t capacity) {  return used < capacity ? capacity - used : 0;}}  // namespace str_format_internal}  // namespace absl#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
 |