| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 | //// POSIX spec://   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html//#include "absl/strings/internal/str_format/arg.h"#include <cassert>#include <cerrno>#include <cstdlib>#include <string>#include <type_traits>#include "absl/base/port.h"#include "absl/strings/internal/str_format/float_conversion.h"namespace absl {namespace str_format_internal {namespace {const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };// Reduce *capacity by s.size(), clipped to a 0 minimum.void ReducePadding(string_view s, size_t *capacity) {  *capacity = Excess(s.size(), *capacity);}// Reduce *capacity by n, clipped to a 0 minimum.void ReducePadding(size_t n, size_t *capacity) {  *capacity = Excess(n, *capacity);}template <typename T>struct MakeUnsigned : std::make_unsigned<T> {};template <>struct MakeUnsigned<absl::uint128> {  using type = absl::uint128;};template <typename T>struct IsSigned : std::is_signed<T> {};template <>struct IsSigned<absl::uint128> : std::false_type {};class ConvertedIntInfo { public:  template <typename T>  ConvertedIntInfo(T v, ConversionChar conv) {    using Unsigned = typename MakeUnsigned<T>::type;    auto u = static_cast<Unsigned>(v);    if (IsNeg(v)) {      is_neg_ = true;      u = Unsigned{} - u;    } else {      is_neg_ = false;    }    UnsignedToStringRight(u, conv);  }  string_view digits() const {    return {end() - size_, static_cast<size_t>(size_)};  }  bool is_neg() const { return is_neg_; } private:  template <typename T, bool IsSigned>  struct IsNegImpl {    static bool Eval(T v) { return v < 0; }  };  template <typename T>  struct IsNegImpl<T, false> {    static bool Eval(T) {      return false;    }  };  template <typename T>  bool IsNeg(T v) {    return IsNegImpl<T, IsSigned<T>::value>::Eval(v);  }  template <typename T>  void UnsignedToStringRight(T u, ConversionChar conv) {    char *p = end();    switch (conv.radix()) {      default:      case 10:        for (; u; u /= 10)          *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));        break;      case 8:        for (; u; u /= 8)          *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));        break;      case 16: {        const char *digits = kDigit[conv.upper() ? 1 : 0];        for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];        break;      }    }    size_ = static_cast<int>(end() - p);  }  const char *end() const { return storage_ + sizeof(storage_); }  char *end() { return storage_ + sizeof(storage_); }  bool is_neg_;  int size_;  // Max size: 128 bit value as octal -> 43 digits  char storage_[128 / 3 + 1];};// Note: 'o' conversions do not have a base indicator, it's just that// the '#' flag is specified to modify the precision for 'o' conversions.string_view BaseIndicator(const ConvertedIntInfo &info,                          const ConversionSpec &conv) {  bool alt = conv.flags().alt;  int radix = conv.conv().radix();  if (conv.conv().id() == ConversionChar::p)    alt = true;  // always show 0x for %p.  // From the POSIX description of '#' flag:  //   "For x or X conversion specifiers, a non-zero result shall have  //   0x (or 0X) prefixed to it."  if (alt && radix == 16 && !info.digits().empty()) {    if (conv.conv().upper()) return "0X";    return "0x";  }  return {};}string_view SignColumn(bool neg, const ConversionSpec &conv) {  if (conv.conv().is_signed()) {    if (neg) return "-";    if (conv.flags().show_pos) return "+";    if (conv.flags().sign_col) return " ";  }  return {};}bool ConvertCharImpl(unsigned char v, const ConversionSpec &conv,                     FormatSinkImpl *sink) {  size_t fill = 0;  if (conv.width() >= 0) fill = conv.width();  ReducePadding(1, &fill);  if (!conv.flags().left) sink->Append(fill, ' ');  sink->Append(1, v);  if (conv.flags().left) sink->Append(fill, ' ');  return true;}bool ConvertIntImplInner(const ConvertedIntInfo &info,                         const ConversionSpec &conv, FormatSinkImpl *sink) {  // Print as a sequence of Substrings:  //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]  size_t fill = 0;  if (conv.width() >= 0) fill = conv.width();  string_view formatted = info.digits();  ReducePadding(formatted, &fill);  string_view sign = SignColumn(info.is_neg(), conv);  ReducePadding(sign, &fill);  string_view base_indicator = BaseIndicator(info, conv);  ReducePadding(base_indicator, &fill);  int precision = conv.precision();  bool precision_specified = precision >= 0;  if (!precision_specified)    precision = 1;  if (conv.flags().alt && conv.conv().id() == ConversionChar::o) {    // From POSIX description of the '#' (alt) flag:    //   "For o conversion, it increases the precision (if necessary) to    //   force the first digit of the result to be zero."    if (formatted.empty() || *formatted.begin() != '0') {      int needed = static_cast<int>(formatted.size()) + 1;      precision = std::max(precision, needed);    }  }  size_t num_zeroes = Excess(formatted.size(), precision);  ReducePadding(num_zeroes, &fill);  size_t num_left_spaces = !conv.flags().left ? fill : 0;  size_t num_right_spaces = conv.flags().left ? fill : 0;  // From POSIX description of the '0' (zero) flag:  //   "For d, i, o, u, x, and X conversion specifiers, if a precision  //   is specified, the '0' flag is ignored."  if (!precision_specified && conv.flags().zero) {    num_zeroes += num_left_spaces;    num_left_spaces = 0;  }  sink->Append(num_left_spaces, ' ');  sink->Append(sign);  sink->Append(base_indicator);  sink->Append(num_zeroes, '0');  sink->Append(formatted);  sink->Append(num_right_spaces, ' ');  return true;}template <typename T>bool ConvertIntImplInner(T v, const ConversionSpec &conv,                         FormatSinkImpl *sink) {  ConvertedIntInfo info(v, conv.conv());  if (conv.flags().basic && conv.conv().id() != ConversionChar::p) {    if (info.is_neg()) sink->Append(1, '-');    if (info.digits().empty()) {      sink->Append(1, '0');    } else {      sink->Append(info.digits());    }    return true;  }  return ConvertIntImplInner(info, conv, sink);}template <typename T>bool ConvertIntArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) {  if (conv.conv().is_float()) {    return FormatConvertImpl(static_cast<double>(v), conv, sink).value;  }  if (conv.conv().id() == ConversionChar::c)    return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);  if (!conv.conv().is_integral())    return false;  if (!conv.conv().is_signed() && IsSigned<T>::value) {    using U = typename MakeUnsigned<T>::type;    return FormatConvertImpl(static_cast<U>(v), conv, sink).value;  }  return ConvertIntImplInner(v, conv, sink);}template <typename T>bool ConvertFloatArg(T v, const ConversionSpec &conv, FormatSinkImpl *sink) {  return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink);}inline bool ConvertStringArg(string_view v, const ConversionSpec &conv,                             FormatSinkImpl *sink) {  if (conv.conv().id() != ConversionChar::s)    return false;  if (conv.flags().basic) {    sink->Append(v);    return true;  }  return sink->PutPaddedString(v, conv.width(), conv.precision(),                               conv.flags().left);}}  // namespace// ==================== Strings ====================ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,                                         const ConversionSpec &conv,                                         FormatSinkImpl *sink) {  return {ConvertStringArg(v, conv, sink)};}ConvertResult<Conv::s> FormatConvertImpl(string_view v,                                         const ConversionSpec &conv,                                         FormatSinkImpl *sink) {  return {ConvertStringArg(v, conv, sink)};}ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,                                                   const ConversionSpec &conv,                                                   FormatSinkImpl *sink) {  if (conv.conv().id() == ConversionChar::p)    return {FormatConvertImpl(VoidPtr(v), conv, sink).value};  size_t len;  if (v == nullptr) {    len = 0;  } else if (conv.precision() < 0) {    len = std::strlen(v);  } else {    // If precision is set, we look for the null terminator on the valid range.    len = std::find(v, v + conv.precision(), '\0') - v;  }  return {ConvertStringArg(string_view(v, len), conv, sink)};}// ==================== Raw pointers ====================ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec &conv,                                         FormatSinkImpl *sink) {  if (conv.conv().id() != ConversionChar::p)    return {false};  if (!v.value) {    sink->Append("(nil)");    return {true};  }  return {ConvertIntImplInner(v.value, conv, sink)};}// ==================== Floats ====================FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertFloatArg(v, conv, sink)};}FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertFloatArg(v, conv, sink)};}FloatingConvertResult FormatConvertImpl(long double v,                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertFloatArg(v, conv, sink)};}// ==================== Chars ====================IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(signed char v,                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(unsigned char v,                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}// ==================== Ints ====================IntegralConvertResult FormatConvertImpl(short v,  // NOLINT                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(long v,  // NOLINT                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}IntegralConvertResult FormatConvertImpl(absl::uint128 v,                                        const ConversionSpec &conv,                                        FormatSinkImpl *sink) {  return {ConvertIntArg(v, conv, sink)};}template struct FormatArgImpl::TypedVTable<str_format_internal::VoidPtr>;template struct FormatArgImpl::TypedVTable<bool>;template struct FormatArgImpl::TypedVTable<char>;template struct FormatArgImpl::TypedVTable<signed char>;template struct FormatArgImpl::TypedVTable<unsigned char>;template struct FormatArgImpl::TypedVTable<short>;           // NOLINTtemplate struct FormatArgImpl::TypedVTable<unsigned short>;  // NOLINTtemplate struct FormatArgImpl::TypedVTable<int>;template struct FormatArgImpl::TypedVTable<unsigned>;template struct FormatArgImpl::TypedVTable<long>;                // NOLINTtemplate struct FormatArgImpl::TypedVTable<unsigned long>;       // NOLINTtemplate struct FormatArgImpl::TypedVTable<long long>;           // NOLINTtemplate struct FormatArgImpl::TypedVTable<unsigned long long>;  // NOLINTtemplate struct FormatArgImpl::TypedVTable<absl::uint128>;template struct FormatArgImpl::TypedVTable<float>;template struct FormatArgImpl::TypedVTable<double>;template struct FormatArgImpl::TypedVTable<long double>;template struct FormatArgImpl::TypedVTable<const char *>;template struct FormatArgImpl::TypedVTable<std::string>;template struct FormatArgImpl::TypedVTable<string_view>;}  // namespace str_format_internal}  // namespace absl
 |