| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 | //// 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/config.h"#include "absl/base/port.h"#include "absl/meta/type_traits.h"#include "absl/strings/internal/str_format/output.h"#include "absl/strings/string_view.h"namespace absl {ABSL_NAMESPACE_BEGINenum class FormatConversionChar : uint8_t;enum class FormatConversionCharSet : uint64_t;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 width, int precision, bool left);  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();  }};// clang-format off#define ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(X_VAL, X_SEP) \  /* text */ \  X_VAL(c) 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 on// This type should not be referenced, it exists only to provide labels// internally that match the values declared in FormatConversionChar in// str_format.h. This is meant to allow internal libraries to use the same// declared interface type as the public interface// (absl::StrFormatConversionChar) while keeping the definition in a public// header.// Internal libraries should use the form// `FormatConversionCharInternal::c`, `FormatConversionCharInternal::kNone` for// comparisons.  Use in switch statements is not recommended due to a bug in how// gcc 4.9 -Wswitch handles declared but undefined enums.struct FormatConversionCharInternal {  FormatConversionCharInternal() = delete; private:  // clang-format off  enum class Enum : uint8_t {    c, s,                    // text    d, i, o, u, x, X,        // int    f, F, e, E, g, G, a, A,  // float    n, p,                    // misc    kNone  };  // clang-format on public:#define ABSL_INTERNAL_X_VAL(id)              \  static constexpr FormatConversionChar id = \      static_cast<FormatConversionChar>(Enum::id);  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )#undef ABSL_INTERNAL_X_VAL  static constexpr FormatConversionChar kNone =      static_cast<FormatConversionChar>(Enum::kNone);};// clang-format oninline FormatConversionChar FormatConversionCharFromChar(char c) {  switch (c) {#define ABSL_INTERNAL_X_VAL(id) \  case #id[0]:                  \    return FormatConversionCharInternal::id;    ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL, )#undef ABSL_INTERNAL_X_VAL  }  return FormatConversionCharInternal::kNone;}inline bool FormatConversionCharIsUpper(FormatConversionChar c) {  if (c == FormatConversionCharInternal::X ||      c == FormatConversionCharInternal::F ||      c == FormatConversionCharInternal::E ||      c == FormatConversionCharInternal::G ||      c == FormatConversionCharInternal::A) {    return true;  } else {    return false;  }}inline bool FormatConversionCharIsFloat(FormatConversionChar c) {  if (c == FormatConversionCharInternal::a ||      c == FormatConversionCharInternal::e ||      c == FormatConversionCharInternal::f ||      c == FormatConversionCharInternal::g ||      c == FormatConversionCharInternal::A ||      c == FormatConversionCharInternal::E ||      c == FormatConversionCharInternal::F ||      c == FormatConversionCharInternal::G) {    return true;  } else {    return false;  }}inline char FormatConversionCharToChar(FormatConversionChar c) {  if (c == FormatConversionCharInternal::kNone) {    return '\0';#define ABSL_INTERNAL_X_VAL(e)                       \  } else if (c == FormatConversionCharInternal::e) { \    return #e[0];#define ABSL_INTERNAL_X_SEP  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_X_VAL,                                         ABSL_INTERNAL_X_SEP)  } else {    return '\0';  }#undef ABSL_INTERNAL_X_VAL#undef ABSL_INTERNAL_X_SEP}// The associated char.inline std::ostream& operator<<(std::ostream& os, FormatConversionChar v) {  char c = FormatConversionCharToChar(v);  if (!c) c = '?';  return os << c;}struct FormatConversionSpecImplFriend;class FormatConversionSpecImpl { public:  // Width and precison are not specified, no flags are set.  bool is_basic() const { return flags_.basic; }  bool has_left_flag() const { return flags_.left; }  bool has_show_pos_flag() const { return flags_.show_pos; }  bool has_sign_col_flag() const { return flags_.sign_col; }  bool has_alt_flag() const { return flags_.alt; }  bool has_zero_flag() const { return flags_.zero; }  FormatConversionChar conversion_char() 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(FormatConversionSpecImpl, 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_; }  template <typename T>  T Wrap() {    return T(*this);  } private:  friend struct str_format_internal::FormatConversionSpecImplFriend;  FormatConversionChar conv_ = FormatConversionCharInternal::kNone;  Flags flags_;  int width_;  int precision_;};struct FormatConversionSpecImplFriend final {  static void SetFlags(Flags f, FormatConversionSpecImpl* conv) {    conv->flags_ = f;  }  static void SetConversionChar(FormatConversionChar c,                                FormatConversionSpecImpl* conv) {    conv->conv_ = c;  }  static void SetWidth(int w, FormatConversionSpecImpl* conv) {    conv->width_ = w;  }  static void SetPrecision(int p, FormatConversionSpecImpl* conv) {    conv->precision_ = p;  }  static std::string FlagsToString(const FormatConversionSpecImpl& spec) {    return spec.flags_.ToString();  }};// 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 FormatConversionCharSet FormatConversionCharSetUnion(    FormatConversionCharSet a) {  return a;}template <typename... CharSet>constexpr FormatConversionCharSet FormatConversionCharSetUnion(    FormatConversionCharSet a, CharSet... rest) {  return static_cast<FormatConversionCharSet>(      static_cast<uint64_t>(a) |      static_cast<uint64_t>(FormatConversionCharSetUnion(rest...)));}constexpr uint64_t FormatConversionCharToConvInt(FormatConversionChar c) {  return uint64_t{1} << (1 + static_cast<uint8_t>(c));}constexpr uint64_t FormatConversionCharToConvInt(char conv) {  return#define ABSL_INTERNAL_CHAR_SET_CASE(c)                                 \  conv == #c[0]                                                        \      ? FormatConversionCharToConvInt(FormatConversionCharInternal::c) \      :      ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )#undef ABSL_INTERNAL_CHAR_SET_CASE                  conv == '*'          ? 1          : 0;}constexpr FormatConversionCharSet FormatConversionCharToConvValue(char conv) {  return static_cast<FormatConversionCharSet>(      FormatConversionCharToConvInt(conv));}struct FormatConversionCharSetInternal {#define ABSL_INTERNAL_CHAR_SET_CASE(c)         \  static constexpr FormatConversionCharSet c = \      FormatConversionCharToConvValue(#c[0]);  ABSL_INTERNAL_CONVERSION_CHARS_EXPAND_(ABSL_INTERNAL_CHAR_SET_CASE, )#undef ABSL_INTERNAL_CHAR_SET_CASE  // Used for width/precision '*' specification.  static constexpr FormatConversionCharSet kStar =      FormatConversionCharToConvValue('*');  static constexpr FormatConversionCharSet kIntegral =      FormatConversionCharSetUnion(d, i, u, o, x, X);  static constexpr FormatConversionCharSet kFloating =      FormatConversionCharSetUnion(a, e, f, g, A, E, F, G);  static constexpr FormatConversionCharSet kNumeric =      FormatConversionCharSetUnion(kIntegral, kFloating);  static constexpr FormatConversionCharSet kPointer = 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 FormatConversionCharSet operator|(FormatConversionCharSet a,                                            FormatConversionCharSet b) {  return FormatConversionCharSetUnion(a, b);}// Overloaded conversion functions to support absl::ParsedFormat.// Get a conversion with a single character in it.constexpr FormatConversionCharSet ToFormatConversionCharSet(char c) {  return static_cast<FormatConversionCharSet>(      FormatConversionCharToConvValue(c));}// Get a conversion with a single character in it.constexpr FormatConversionCharSet ToFormatConversionCharSet(    FormatConversionCharSet c) {  return c;}template <typename T>void ToFormatConversionCharSet(T) = delete;// Checks whether `c` exists in `set`.constexpr bool Contains(FormatConversionCharSet set, char c) {  return (static_cast<uint64_t>(set) &          static_cast<uint64_t>(FormatConversionCharToConvValue(c))) != 0;}// Checks whether all the characters in `c` are contained in `set`constexpr bool Contains(FormatConversionCharSet set,                        FormatConversionCharSet c) {  return (static_cast<uint64_t>(set) & static_cast<uint64_t>(c)) ==         static_cast<uint64_t>(c);}// Checks whether all the characters in `c` are contained in `set`constexpr bool Contains(FormatConversionCharSet set, FormatConversionChar c) {  return (static_cast<uint64_t>(set) & FormatConversionCharToConvInt(c)) != 0;}// 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_internalABSL_NAMESPACE_END}  // namespace absl#endif  // ABSL_STRINGS_INTERNAL_STR_FORMAT_EXTENSION_H_
 |