| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 | 
							- //
 
- // 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)};
 
- }
 
- ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
 
- }  // namespace str_format_internal
 
- }  // namespace absl
 
 
  |