arg.cc
Go to the documentation of this file.
00001 //
00002 // POSIX spec:
00003 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
00004 //
00005 #include "absl/strings/internal/str_format/arg.h"
00006 
00007 #include <cassert>
00008 #include <cerrno>
00009 #include <cstdlib>
00010 #include <string>
00011 #include <type_traits>
00012 
00013 #include "absl/base/port.h"
00014 #include "absl/strings/internal/str_format/float_conversion.h"
00015 
00016 namespace absl {
00017 namespace str_format_internal {
00018 namespace {
00019 
00020 const char kDigit[2][32] = { "0123456789abcdef", "0123456789ABCDEF" };
00021 
00022 // Reduce *capacity by s.size(), clipped to a 0 minimum.
00023 void ReducePadding(string_view s, size_t *capacity) {
00024   *capacity = Excess(s.size(), *capacity);
00025 }
00026 
00027 // Reduce *capacity by n, clipped to a 0 minimum.
00028 void ReducePadding(size_t n, size_t *capacity) {
00029   *capacity = Excess(n, *capacity);
00030 }
00031 
00032 template <typename T>
00033 struct MakeUnsigned : std::make_unsigned<T> {};
00034 template <>
00035 struct MakeUnsigned<absl::uint128> {
00036   using type = absl::uint128;
00037 };
00038 
00039 template <typename T>
00040 struct IsSigned : std::is_signed<T> {};
00041 template <>
00042 struct IsSigned<absl::uint128> : std::false_type {};
00043 
00044 class ConvertedIntInfo {
00045  public:
00046   template <typename T>
00047   ConvertedIntInfo(T v, ConversionChar conv) {
00048     using Unsigned = typename MakeUnsigned<T>::type;
00049     auto u = static_cast<Unsigned>(v);
00050     if (IsNeg(v)) {
00051       is_neg_ = true;
00052       u = Unsigned{} - u;
00053     } else {
00054       is_neg_ = false;
00055     }
00056     UnsignedToStringRight(u, conv);
00057   }
00058 
00059   string_view digits() const {
00060     return {end() - size_, static_cast<size_t>(size_)};
00061   }
00062   bool is_neg() const { return is_neg_; }
00063 
00064  private:
00065   template <typename T, bool IsSigned>
00066   struct IsNegImpl {
00067     static bool Eval(T v) { return v < 0; }
00068   };
00069   template <typename T>
00070   struct IsNegImpl<T, false> {
00071     static bool Eval(T) {
00072       return false;
00073     }
00074   };
00075 
00076   template <typename T>
00077   bool IsNeg(T v) {
00078     return IsNegImpl<T, IsSigned<T>::value>::Eval(v);
00079   }
00080 
00081   template <typename T>
00082   void UnsignedToStringRight(T u, ConversionChar conv) {
00083     char *p = end();
00084     switch (conv.radix()) {
00085       default:
00086       case 10:
00087         for (; u; u /= 10)
00088           *--p = static_cast<char>('0' + static_cast<size_t>(u % 10));
00089         break;
00090       case 8:
00091         for (; u; u /= 8)
00092           *--p = static_cast<char>('0' + static_cast<size_t>(u % 8));
00093         break;
00094       case 16: {
00095         const char *digits = kDigit[conv.upper() ? 1 : 0];
00096         for (; u; u /= 16) *--p = digits[static_cast<size_t>(u % 16)];
00097         break;
00098       }
00099     }
00100     size_ = static_cast<int>(end() - p);
00101   }
00102 
00103   const char *end() const { return storage_ + sizeof(storage_); }
00104   char *end() { return storage_ + sizeof(storage_); }
00105 
00106   bool is_neg_;
00107   int size_;
00108   // Max size: 128 bit value as octal -> 43 digits
00109   char storage_[128 / 3 + 1];
00110 };
00111 
00112 // Note: 'o' conversions do not have a base indicator, it's just that
00113 // the '#' flag is specified to modify the precision for 'o' conversions.
00114 string_view BaseIndicator(const ConvertedIntInfo &info,
00115                           const ConversionSpec conv) {
00116   bool alt = conv.flags().alt;
00117   int radix = conv.conv().radix();
00118   if (conv.conv().id() == ConversionChar::p)
00119     alt = true;  // always show 0x for %p.
00120   // From the POSIX description of '#' flag:
00121   //   "For x or X conversion specifiers, a non-zero result shall have
00122   //   0x (or 0X) prefixed to it."
00123   if (alt && radix == 16 && !info.digits().empty()) {
00124     if (conv.conv().upper()) return "0X";
00125     return "0x";
00126   }
00127   return {};
00128 }
00129 
00130 string_view SignColumn(bool neg, const ConversionSpec conv) {
00131   if (conv.conv().is_signed()) {
00132     if (neg) return "-";
00133     if (conv.flags().show_pos) return "+";
00134     if (conv.flags().sign_col) return " ";
00135   }
00136   return {};
00137 }
00138 
00139 bool ConvertCharImpl(unsigned char v, const ConversionSpec conv,
00140                      FormatSinkImpl *sink) {
00141   size_t fill = 0;
00142   if (conv.width() >= 0) fill = conv.width();
00143   ReducePadding(1, &fill);
00144   if (!conv.flags().left) sink->Append(fill, ' ');
00145   sink->Append(1, v);
00146   if (conv.flags().left) sink->Append(fill, ' ');
00147   return true;
00148 }
00149 
00150 bool ConvertIntImplInner(const ConvertedIntInfo &info,
00151                          const ConversionSpec conv, FormatSinkImpl *sink) {
00152   // Print as a sequence of Substrings:
00153   //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
00154   size_t fill = 0;
00155   if (conv.width() >= 0) fill = conv.width();
00156 
00157   string_view formatted = info.digits();
00158   ReducePadding(formatted, &fill);
00159 
00160   string_view sign = SignColumn(info.is_neg(), conv);
00161   ReducePadding(sign, &fill);
00162 
00163   string_view base_indicator = BaseIndicator(info, conv);
00164   ReducePadding(base_indicator, &fill);
00165 
00166   int precision = conv.precision();
00167   bool precision_specified = precision >= 0;
00168   if (!precision_specified)
00169     precision = 1;
00170 
00171   if (conv.flags().alt && conv.conv().id() == ConversionChar::o) {
00172     // From POSIX description of the '#' (alt) flag:
00173     //   "For o conversion, it increases the precision (if necessary) to
00174     //   force the first digit of the result to be zero."
00175     if (formatted.empty() || *formatted.begin() != '0') {
00176       int needed = static_cast<int>(formatted.size()) + 1;
00177       precision = std::max(precision, needed);
00178     }
00179   }
00180 
00181   size_t num_zeroes = Excess(formatted.size(), precision);
00182   ReducePadding(num_zeroes, &fill);
00183 
00184   size_t num_left_spaces = !conv.flags().left ? fill : 0;
00185   size_t num_right_spaces = conv.flags().left ? fill : 0;
00186 
00187   // From POSIX description of the '0' (zero) flag:
00188   //   "For d, i, o, u, x, and X conversion specifiers, if a precision
00189   //   is specified, the '0' flag is ignored."
00190   if (!precision_specified && conv.flags().zero) {
00191     num_zeroes += num_left_spaces;
00192     num_left_spaces = 0;
00193   }
00194 
00195   sink->Append(num_left_spaces, ' ');
00196   sink->Append(sign);
00197   sink->Append(base_indicator);
00198   sink->Append(num_zeroes, '0');
00199   sink->Append(formatted);
00200   sink->Append(num_right_spaces, ' ');
00201   return true;
00202 }
00203 
00204 template <typename T>
00205 bool ConvertIntImplInner(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
00206   ConvertedIntInfo info(v, conv.conv());
00207   if (conv.flags().basic && conv.conv().id() != ConversionChar::p) {
00208     if (info.is_neg()) sink->Append(1, '-');
00209     if (info.digits().empty()) {
00210       sink->Append(1, '0');
00211     } else {
00212       sink->Append(info.digits());
00213     }
00214     return true;
00215   }
00216   return ConvertIntImplInner(info, conv, sink);
00217 }
00218 
00219 template <typename T>
00220 bool ConvertIntArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
00221   if (conv.conv().is_float()) {
00222     return FormatConvertImpl(static_cast<double>(v), conv, sink).value;
00223   }
00224   if (conv.conv().id() == ConversionChar::c)
00225     return ConvertCharImpl(static_cast<unsigned char>(v), conv, sink);
00226   if (!conv.conv().is_integral())
00227     return false;
00228   if (!conv.conv().is_signed() && IsSigned<T>::value) {
00229     using U = typename MakeUnsigned<T>::type;
00230     return FormatConvertImpl(static_cast<U>(v), conv, sink).value;
00231   }
00232   return ConvertIntImplInner(v, conv, sink);
00233 }
00234 
00235 template <typename T>
00236 bool ConvertFloatArg(T v, const ConversionSpec conv, FormatSinkImpl *sink) {
00237   return conv.conv().is_float() && ConvertFloatImpl(v, conv, sink);
00238 }
00239 
00240 inline bool ConvertStringArg(string_view v, const ConversionSpec conv,
00241                              FormatSinkImpl *sink) {
00242   if (conv.conv().id() != ConversionChar::s)
00243     return false;
00244   if (conv.flags().basic) {
00245     sink->Append(v);
00246     return true;
00247   }
00248   return sink->PutPaddedString(v, conv.width(), conv.precision(),
00249                                conv.flags().left);
00250 }
00251 
00252 }  // namespace
00253 
00254 // ==================== Strings ====================
00255 ConvertResult<Conv::s> FormatConvertImpl(const std::string &v,
00256                                          const ConversionSpec conv,
00257                                          FormatSinkImpl *sink) {
00258   return {ConvertStringArg(v, conv, sink)};
00259 }
00260 
00261 ConvertResult<Conv::s> FormatConvertImpl(string_view v,
00262                                          const ConversionSpec conv,
00263                                          FormatSinkImpl *sink) {
00264   return {ConvertStringArg(v, conv, sink)};
00265 }
00266 
00267 ConvertResult<Conv::s | Conv::p> FormatConvertImpl(const char *v,
00268                                                    const ConversionSpec conv,
00269                                                    FormatSinkImpl *sink) {
00270   if (conv.conv().id() == ConversionChar::p)
00271     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
00272   size_t len;
00273   if (v == nullptr) {
00274     len = 0;
00275   } else if (conv.precision() < 0) {
00276     len = std::strlen(v);
00277   } else {
00278     // If precision is set, we look for the null terminator on the valid range.
00279     len = std::find(v, v + conv.precision(), '\0') - v;
00280   }
00281   return {ConvertStringArg(string_view(v, len), conv, sink)};
00282 }
00283 
00284 // ==================== Raw pointers ====================
00285 ConvertResult<Conv::p> FormatConvertImpl(VoidPtr v, const ConversionSpec conv,
00286                                          FormatSinkImpl *sink) {
00287   if (conv.conv().id() != ConversionChar::p)
00288     return {false};
00289   if (!v.value) {
00290     sink->Append("(nil)");
00291     return {true};
00292   }
00293   return {ConvertIntImplInner(v.value, conv, sink)};
00294 }
00295 
00296 // ==================== Floats ====================
00297 FloatingConvertResult FormatConvertImpl(float v, const ConversionSpec conv,
00298                                         FormatSinkImpl *sink) {
00299   return {ConvertFloatArg(v, conv, sink)};
00300 }
00301 FloatingConvertResult FormatConvertImpl(double v, const ConversionSpec conv,
00302                                         FormatSinkImpl *sink) {
00303   return {ConvertFloatArg(v, conv, sink)};
00304 }
00305 FloatingConvertResult FormatConvertImpl(long double v,
00306                                         const ConversionSpec conv,
00307                                         FormatSinkImpl *sink) {
00308   return {ConvertFloatArg(v, conv, sink)};
00309 }
00310 
00311 // ==================== Chars ====================
00312 IntegralConvertResult FormatConvertImpl(char v, const ConversionSpec conv,
00313                                         FormatSinkImpl *sink) {
00314   return {ConvertIntArg(v, conv, sink)};
00315 }
00316 IntegralConvertResult FormatConvertImpl(signed char v,
00317                                         const ConversionSpec conv,
00318                                         FormatSinkImpl *sink) {
00319   return {ConvertIntArg(v, conv, sink)};
00320 }
00321 IntegralConvertResult FormatConvertImpl(unsigned char v,
00322                                         const ConversionSpec conv,
00323                                         FormatSinkImpl *sink) {
00324   return {ConvertIntArg(v, conv, sink)};
00325 }
00326 
00327 // ==================== Ints ====================
00328 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
00329                                         const ConversionSpec conv,
00330                                         FormatSinkImpl *sink) {
00331   return {ConvertIntArg(v, conv, sink)};
00332 }
00333 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
00334                                         const ConversionSpec conv,
00335                                         FormatSinkImpl *sink) {
00336   return {ConvertIntArg(v, conv, sink)};
00337 }
00338 IntegralConvertResult FormatConvertImpl(int v, const ConversionSpec conv,
00339                                         FormatSinkImpl *sink) {
00340   return {ConvertIntArg(v, conv, sink)};
00341 }
00342 IntegralConvertResult FormatConvertImpl(unsigned v, const ConversionSpec conv,
00343                                         FormatSinkImpl *sink) {
00344   return {ConvertIntArg(v, conv, sink)};
00345 }
00346 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
00347                                         const ConversionSpec conv,
00348                                         FormatSinkImpl *sink) {
00349   return {ConvertIntArg(v, conv, sink)};
00350 }
00351 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
00352                                         const ConversionSpec conv,
00353                                         FormatSinkImpl *sink) {
00354   return {ConvertIntArg(v, conv, sink)};
00355 }
00356 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
00357                                         const ConversionSpec conv,
00358                                         FormatSinkImpl *sink) {
00359   return {ConvertIntArg(v, conv, sink)};
00360 }
00361 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
00362                                         const ConversionSpec conv,
00363                                         FormatSinkImpl *sink) {
00364   return {ConvertIntArg(v, conv, sink)};
00365 }
00366 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
00367                                         const ConversionSpec conv,
00368                                         FormatSinkImpl *sink) {
00369   return {ConvertIntArg(v, conv, sink)};
00370 }
00371 
00372 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
00373 
00374 
00375 }  // namespace str_format_internal
00376 
00377 }  // namespace absl


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:14