"Fossies" - the Fresh Open Source Software Archive

Member "abseil-cpp-20230802.1/absl/strings/internal/str_format/arg.cc" (18 Sep 2023, 19881 Bytes) of package /linux/misc/abseil-cpp-20230802.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "arg.cc" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 20230125.3_vs_20230802.0.

    1 // Copyright 2020 The Abseil Authors.
    2 //
    3 // Licensed under the Apache License, Version 2.0 (the "License");
    4 // you may not use this file except in compliance with the License.
    5 // You may obtain a copy of the License at
    6 //
    7 //      https://www.apache.org/licenses/LICENSE-2.0
    8 //
    9 // Unless required by applicable law or agreed to in writing, software
   10 // distributed under the License is distributed on an "AS IS" BASIS,
   11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   12 // See the License for the specific language governing permissions and
   13 // limitations under the License.
   14 
   15 //
   16 // POSIX spec:
   17 //   http://pubs.opengroup.org/onlinepubs/009695399/functions/fprintf.html
   18 //
   19 #include "absl/strings/internal/str_format/arg.h"
   20 
   21 #include <cassert>
   22 #include <cerrno>
   23 #include <cstdlib>
   24 #include <string>
   25 #include <type_traits>
   26 
   27 #include "absl/base/port.h"
   28 #include "absl/strings/internal/str_format/float_conversion.h"
   29 #include "absl/strings/numbers.h"
   30 
   31 namespace absl {
   32 ABSL_NAMESPACE_BEGIN
   33 namespace str_format_internal {
   34 namespace {
   35 
   36 // Reduce *capacity by s.size(), clipped to a 0 minimum.
   37 void ReducePadding(string_view s, size_t *capacity) {
   38   *capacity = Excess(s.size(), *capacity);
   39 }
   40 
   41 // Reduce *capacity by n, clipped to a 0 minimum.
   42 void ReducePadding(size_t n, size_t *capacity) {
   43   *capacity = Excess(n, *capacity);
   44 }
   45 
   46 template <typename T>
   47 struct MakeUnsigned : std::make_unsigned<T> {};
   48 template <>
   49 struct MakeUnsigned<absl::int128> {
   50   using type = absl::uint128;
   51 };
   52 template <>
   53 struct MakeUnsigned<absl::uint128> {
   54   using type = absl::uint128;
   55 };
   56 
   57 template <typename T>
   58 struct IsSigned : std::is_signed<T> {};
   59 template <>
   60 struct IsSigned<absl::int128> : std::true_type {};
   61 template <>
   62 struct IsSigned<absl::uint128> : std::false_type {};
   63 
   64 // Integral digit printer.
   65 // Call one of the PrintAs* routines after construction once.
   66 // Use with_neg_and_zero/without_neg_or_zero/is_negative to access the results.
   67 class IntDigits {
   68  public:
   69   // Print the unsigned integer as octal.
   70   // Supports unsigned integral types and uint128.
   71   template <typename T>
   72   void PrintAsOct(T v) {
   73     static_assert(!IsSigned<T>::value, "");
   74     char *p = storage_ + sizeof(storage_);
   75     do {
   76       *--p = static_cast<char>('0' + (static_cast<size_t>(v) & 7));
   77       v >>= 3;
   78     } while (v);
   79     start_ = p;
   80     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
   81   }
   82 
   83   // Print the signed or unsigned integer as decimal.
   84   // Supports all integral types.
   85   template <typename T>
   86   void PrintAsDec(T v) {
   87     static_assert(std::is_integral<T>::value, "");
   88     start_ = storage_;
   89     size_ = static_cast<size_t>(numbers_internal::FastIntToBuffer(v, storage_) -
   90                                 storage_);
   91   }
   92 
   93   void PrintAsDec(int128 v) {
   94     auto u = static_cast<uint128>(v);
   95     bool add_neg = false;
   96     if (v < 0) {
   97       add_neg = true;
   98       u = uint128{} - u;
   99     }
  100     PrintAsDec(u, add_neg);
  101   }
  102 
  103   void PrintAsDec(uint128 v, bool add_neg = false) {
  104     // This function can be sped up if needed. We can call FastIntToBuffer
  105     // twice, or fix FastIntToBuffer to support uint128.
  106     char *p = storage_ + sizeof(storage_);
  107     do {
  108       p -= 2;
  109       numbers_internal::PutTwoDigits(static_cast<uint32_t>(v % 100), p);
  110       v /= 100;
  111     } while (v);
  112     if (p[0] == '0') {
  113       // We printed one too many hexits.
  114       ++p;
  115     }
  116     if (add_neg) {
  117       *--p = '-';
  118     }
  119     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  120     start_ = p;
  121   }
  122 
  123   // Print the unsigned integer as hex using lowercase.
  124   // Supports unsigned integral types and uint128.
  125   template <typename T>
  126   void PrintAsHexLower(T v) {
  127     static_assert(!IsSigned<T>::value, "");
  128     char *p = storage_ + sizeof(storage_);
  129 
  130     do {
  131       p -= 2;
  132       constexpr const char* table = numbers_internal::kHexTable;
  133       std::memcpy(p, table + 2 * (static_cast<size_t>(v) & 0xFF), 2);
  134       if (sizeof(T) == 1) break;
  135       v >>= 8;
  136     } while (v);
  137     if (p[0] == '0') {
  138       // We printed one too many digits.
  139       ++p;
  140     }
  141     start_ = p;
  142     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  143   }
  144 
  145   // Print the unsigned integer as hex using uppercase.
  146   // Supports unsigned integral types and uint128.
  147   template <typename T>
  148   void PrintAsHexUpper(T v) {
  149     static_assert(!IsSigned<T>::value, "");
  150     char *p = storage_ + sizeof(storage_);
  151 
  152     // kHexTable is only lowercase, so do it manually for uppercase.
  153     do {
  154       *--p = "0123456789ABCDEF"[static_cast<size_t>(v) & 15];
  155       v >>= 4;
  156     } while (v);
  157     start_ = p;
  158     size_ = static_cast<size_t>(storage_ + sizeof(storage_) - p);
  159   }
  160 
  161   // The printed value including the '-' sign if available.
  162   // For inputs of value `0`, this will return "0"
  163   string_view with_neg_and_zero() const { return {start_, size_}; }
  164 
  165   // The printed value not including the '-' sign.
  166   // For inputs of value `0`, this will return "".
  167   string_view without_neg_or_zero() const {
  168     static_assert('-' < '0', "The check below verifies both.");
  169     size_t advance = start_[0] <= '0' ? 1 : 0;
  170     return {start_ + advance, size_ - advance};
  171   }
  172 
  173   bool is_negative() const { return start_[0] == '-'; }
  174 
  175  private:
  176   const char *start_;
  177   size_t size_;
  178   // Max size: 128 bit value as octal -> 43 digits, plus sign char
  179   char storage_[128 / 3 + 1 + 1];
  180 };
  181 
  182 // Note: 'o' conversions do not have a base indicator, it's just that
  183 // the '#' flag is specified to modify the precision for 'o' conversions.
  184 string_view BaseIndicator(const IntDigits &as_digits,
  185                           const FormatConversionSpecImpl conv) {
  186   // always show 0x for %p.
  187   bool alt = conv.has_alt_flag() ||
  188              conv.conversion_char() == FormatConversionCharInternal::p;
  189   bool hex = (conv.conversion_char() == FormatConversionCharInternal::x ||
  190               conv.conversion_char() == FormatConversionCharInternal::X ||
  191               conv.conversion_char() == FormatConversionCharInternal::p);
  192   // From the POSIX description of '#' flag:
  193   //   "For x or X conversion specifiers, a non-zero result shall have
  194   //   0x (or 0X) prefixed to it."
  195   if (alt && hex && !as_digits.without_neg_or_zero().empty()) {
  196     return conv.conversion_char() == FormatConversionCharInternal::X ? "0X"
  197                                                                      : "0x";
  198   }
  199   return {};
  200 }
  201 
  202 string_view SignColumn(bool neg, const FormatConversionSpecImpl conv) {
  203   if (conv.conversion_char() == FormatConversionCharInternal::d ||
  204       conv.conversion_char() == FormatConversionCharInternal::i) {
  205     if (neg) return "-";
  206     if (conv.has_show_pos_flag()) return "+";
  207     if (conv.has_sign_col_flag()) return " ";
  208   }
  209   return {};
  210 }
  211 
  212 bool ConvertCharImpl(char v,
  213                      const FormatConversionSpecImpl conv,
  214                      FormatSinkImpl* sink) {
  215   size_t fill = 0;
  216   if (conv.width() >= 0)
  217     fill = static_cast<size_t>(conv.width());
  218   ReducePadding(1, &fill);
  219   if (!conv.has_left_flag()) sink->Append(fill, ' ');
  220   sink->Append(1, v);
  221   if (conv.has_left_flag()) sink->Append(fill, ' ');
  222   return true;
  223 }
  224 
  225 bool ConvertIntImplInnerSlow(const IntDigits &as_digits,
  226                              const FormatConversionSpecImpl conv,
  227                              FormatSinkImpl *sink) {
  228   // Print as a sequence of Substrings:
  229   //   [left_spaces][sign][base_indicator][zeroes][formatted][right_spaces]
  230   size_t fill = 0;
  231   if (conv.width() >= 0)
  232     fill = static_cast<size_t>(conv.width());
  233 
  234   string_view formatted = as_digits.without_neg_or_zero();
  235   ReducePadding(formatted, &fill);
  236 
  237   string_view sign = SignColumn(as_digits.is_negative(), conv);
  238   ReducePadding(sign, &fill);
  239 
  240   string_view base_indicator = BaseIndicator(as_digits, conv);
  241   ReducePadding(base_indicator, &fill);
  242 
  243   bool precision_specified = conv.precision() >= 0;
  244   size_t precision =
  245       precision_specified ? static_cast<size_t>(conv.precision()) : size_t{1};
  246 
  247   if (conv.has_alt_flag() &&
  248       conv.conversion_char() == FormatConversionCharInternal::o) {
  249     // From POSIX description of the '#' (alt) flag:
  250     //   "For o conversion, it increases the precision (if necessary) to
  251     //   force the first digit of the result to be zero."
  252     if (formatted.empty() || *formatted.begin() != '0') {
  253       size_t needed = formatted.size() + 1;
  254       precision = std::max(precision, needed);
  255     }
  256   }
  257 
  258   size_t num_zeroes = Excess(formatted.size(), precision);
  259   ReducePadding(num_zeroes, &fill);
  260 
  261   size_t num_left_spaces = !conv.has_left_flag() ? fill : 0;
  262   size_t num_right_spaces = conv.has_left_flag() ? fill : 0;
  263 
  264   // From POSIX description of the '0' (zero) flag:
  265   //   "For d, i, o, u, x, and X conversion specifiers, if a precision
  266   //   is specified, the '0' flag is ignored."
  267   if (!precision_specified && conv.has_zero_flag()) {
  268     num_zeroes += num_left_spaces;
  269     num_left_spaces = 0;
  270   }
  271 
  272   sink->Append(num_left_spaces, ' ');
  273   sink->Append(sign);
  274   sink->Append(base_indicator);
  275   sink->Append(num_zeroes, '0');
  276   sink->Append(formatted);
  277   sink->Append(num_right_spaces, ' ');
  278   return true;
  279 }
  280 
  281 template <typename T>
  282 bool ConvertFloatArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  283   if (conv.conversion_char() == FormatConversionCharInternal::v) {
  284     conv.set_conversion_char(FormatConversionCharInternal::g);
  285   }
  286 
  287   return FormatConversionCharIsFloat(conv.conversion_char()) &&
  288          ConvertFloatImpl(v, conv, sink);
  289 }
  290 
  291 inline bool ConvertStringArg(string_view v, const FormatConversionSpecImpl conv,
  292                              FormatSinkImpl *sink) {
  293   if (conv.is_basic()) {
  294     sink->Append(v);
  295     return true;
  296   }
  297   return sink->PutPaddedString(v, conv.width(), conv.precision(),
  298                                conv.has_left_flag());
  299 }
  300 
  301 }  // namespace
  302 
  303 bool ConvertBoolArg(bool v, FormatSinkImpl *sink) {
  304   if (v) {
  305     sink->Append("true");
  306   } else {
  307     sink->Append("false");
  308   }
  309   return true;
  310 }
  311 
  312 template <typename T>
  313 bool ConvertIntArg(T v, FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  314   using U = typename MakeUnsigned<T>::type;
  315   IntDigits as_digits;
  316 
  317   // This odd casting is due to a bug in -Wswitch behavior in gcc49 which causes
  318   // it to complain about a switch/case type mismatch, even though both are
  319   // FormatConverionChar.  Likely this is because at this point
  320   // FormatConversionChar is declared, but not defined.
  321   switch (static_cast<uint8_t>(conv.conversion_char())) {
  322     case static_cast<uint8_t>(FormatConversionCharInternal::c):
  323       return ConvertCharImpl(static_cast<char>(v), conv, sink);
  324 
  325     case static_cast<uint8_t>(FormatConversionCharInternal::o):
  326       as_digits.PrintAsOct(static_cast<U>(v));
  327       break;
  328 
  329     case static_cast<uint8_t>(FormatConversionCharInternal::x):
  330       as_digits.PrintAsHexLower(static_cast<U>(v));
  331       break;
  332     case static_cast<uint8_t>(FormatConversionCharInternal::X):
  333       as_digits.PrintAsHexUpper(static_cast<U>(v));
  334       break;
  335 
  336     case static_cast<uint8_t>(FormatConversionCharInternal::u):
  337       as_digits.PrintAsDec(static_cast<U>(v));
  338       break;
  339 
  340     case static_cast<uint8_t>(FormatConversionCharInternal::d):
  341     case static_cast<uint8_t>(FormatConversionCharInternal::i):
  342     case static_cast<uint8_t>(FormatConversionCharInternal::v):
  343       as_digits.PrintAsDec(v);
  344       break;
  345 
  346     case static_cast<uint8_t>(FormatConversionCharInternal::a):
  347     case static_cast<uint8_t>(FormatConversionCharInternal::e):
  348     case static_cast<uint8_t>(FormatConversionCharInternal::f):
  349     case static_cast<uint8_t>(FormatConversionCharInternal::g):
  350     case static_cast<uint8_t>(FormatConversionCharInternal::A):
  351     case static_cast<uint8_t>(FormatConversionCharInternal::E):
  352     case static_cast<uint8_t>(FormatConversionCharInternal::F):
  353     case static_cast<uint8_t>(FormatConversionCharInternal::G):
  354       return ConvertFloatImpl(static_cast<double>(v), conv, sink);
  355 
  356     default:
  357       ABSL_ASSUME(false);
  358   }
  359 
  360   if (conv.is_basic()) {
  361     sink->Append(as_digits.with_neg_and_zero());
  362     return true;
  363   }
  364   return ConvertIntImplInnerSlow(as_digits, conv, sink);
  365 }
  366 
  367 template bool ConvertIntArg<char>(char v, FormatConversionSpecImpl conv,
  368                                   FormatSinkImpl *sink);
  369 template bool ConvertIntArg<signed char>(signed char v,
  370                                          FormatConversionSpecImpl conv,
  371                                          FormatSinkImpl *sink);
  372 template bool ConvertIntArg<unsigned char>(unsigned char v,
  373                                            FormatConversionSpecImpl conv,
  374                                            FormatSinkImpl *sink);
  375 template bool ConvertIntArg<short>(short v,  // NOLINT
  376                                    FormatConversionSpecImpl conv,
  377                                    FormatSinkImpl *sink);
  378 template bool ConvertIntArg<unsigned short>(unsigned short v,  // NOLINT
  379                                             FormatConversionSpecImpl conv,
  380                                             FormatSinkImpl *sink);
  381 template bool ConvertIntArg<int>(int v, FormatConversionSpecImpl conv,
  382                                  FormatSinkImpl *sink);
  383 template bool ConvertIntArg<unsigned int>(unsigned int v,
  384                                           FormatConversionSpecImpl conv,
  385                                           FormatSinkImpl *sink);
  386 template bool ConvertIntArg<long>(long v,  // NOLINT
  387                                   FormatConversionSpecImpl conv,
  388                                   FormatSinkImpl *sink);
  389 template bool ConvertIntArg<unsigned long>(unsigned long v,  // NOLINT
  390                                            FormatConversionSpecImpl conv,
  391                                            FormatSinkImpl *sink);
  392 template bool ConvertIntArg<long long>(long long v,  // NOLINT
  393                                        FormatConversionSpecImpl conv,
  394                                        FormatSinkImpl *sink);
  395 template bool ConvertIntArg<unsigned long long>(unsigned long long v,  // NOLINT
  396                                                 FormatConversionSpecImpl conv,
  397                                                 FormatSinkImpl *sink);
  398 
  399 // ==================== Strings ====================
  400 StringConvertResult FormatConvertImpl(const std::string &v,
  401                                       const FormatConversionSpecImpl conv,
  402                                       FormatSinkImpl *sink) {
  403   return {ConvertStringArg(v, conv, sink)};
  404 }
  405 
  406 StringConvertResult FormatConvertImpl(string_view v,
  407                                       const FormatConversionSpecImpl conv,
  408                                       FormatSinkImpl *sink) {
  409   return {ConvertStringArg(v, conv, sink)};
  410 }
  411 
  412 ArgConvertResult<FormatConversionCharSetUnion(
  413     FormatConversionCharSetInternal::s, FormatConversionCharSetInternal::p)>
  414 FormatConvertImpl(const char *v, const FormatConversionSpecImpl conv,
  415                   FormatSinkImpl *sink) {
  416   if (conv.conversion_char() == FormatConversionCharInternal::p)
  417     return {FormatConvertImpl(VoidPtr(v), conv, sink).value};
  418   size_t len;
  419   if (v == nullptr) {
  420     len = 0;
  421   } else if (conv.precision() < 0) {
  422     len = std::strlen(v);
  423   } else {
  424     // If precision is set, we look for the NUL-terminator on the valid range.
  425     len = static_cast<size_t>(std::find(v, v + conv.precision(), '\0') - v);
  426   }
  427   return {ConvertStringArg(string_view(v, len), conv, sink)};
  428 }
  429 
  430 // ==================== Raw pointers ====================
  431 ArgConvertResult<FormatConversionCharSetInternal::p> FormatConvertImpl(
  432     VoidPtr v, const FormatConversionSpecImpl conv, FormatSinkImpl *sink) {
  433   if (!v.value) {
  434     sink->Append("(nil)");
  435     return {true};
  436   }
  437   IntDigits as_digits;
  438   as_digits.PrintAsHexLower(v.value);
  439   return {ConvertIntImplInnerSlow(as_digits, conv, sink)};
  440 }
  441 
  442 // ==================== Floats ====================
  443 FloatingConvertResult FormatConvertImpl(float v,
  444                                         const FormatConversionSpecImpl conv,
  445                                         FormatSinkImpl *sink) {
  446   return {ConvertFloatArg(v, conv, sink)};
  447 }
  448 FloatingConvertResult FormatConvertImpl(double v,
  449                                         const FormatConversionSpecImpl conv,
  450                                         FormatSinkImpl *sink) {
  451   return {ConvertFloatArg(v, conv, sink)};
  452 }
  453 FloatingConvertResult FormatConvertImpl(long double v,
  454                                         const FormatConversionSpecImpl conv,
  455                                         FormatSinkImpl *sink) {
  456   return {ConvertFloatArg(v, conv, sink)};
  457 }
  458 
  459 // ==================== Chars ====================
  460 CharConvertResult FormatConvertImpl(char v, const FormatConversionSpecImpl conv,
  461                                     FormatSinkImpl *sink) {
  462   return {ConvertIntArg(v, conv, sink)};
  463 }
  464 
  465 // ==================== Ints ====================
  466 IntegralConvertResult FormatConvertImpl(signed char v,
  467                                         const FormatConversionSpecImpl conv,
  468                                         FormatSinkImpl *sink) {
  469   return {ConvertIntArg(v, conv, sink)};
  470 }
  471 IntegralConvertResult FormatConvertImpl(unsigned char v,
  472                                         const FormatConversionSpecImpl conv,
  473                                         FormatSinkImpl *sink) {
  474   return {ConvertIntArg(v, conv, sink)};
  475 }
  476 IntegralConvertResult FormatConvertImpl(short v,  // NOLINT
  477                                         const FormatConversionSpecImpl conv,
  478                                         FormatSinkImpl *sink) {
  479   return {ConvertIntArg(v, conv, sink)};
  480 }
  481 IntegralConvertResult FormatConvertImpl(unsigned short v,  // NOLINT
  482                                         const FormatConversionSpecImpl conv,
  483                                         FormatSinkImpl *sink) {
  484   return {ConvertIntArg(v, conv, sink)};
  485 }
  486 IntegralConvertResult FormatConvertImpl(int v,
  487                                         const FormatConversionSpecImpl conv,
  488                                         FormatSinkImpl *sink) {
  489   return {ConvertIntArg(v, conv, sink)};
  490 }
  491 IntegralConvertResult FormatConvertImpl(unsigned v,
  492                                         const FormatConversionSpecImpl conv,
  493                                         FormatSinkImpl *sink) {
  494   return {ConvertIntArg(v, conv, sink)};
  495 }
  496 IntegralConvertResult FormatConvertImpl(long v,  // NOLINT
  497                                         const FormatConversionSpecImpl conv,
  498                                         FormatSinkImpl *sink) {
  499   return {ConvertIntArg(v, conv, sink)};
  500 }
  501 IntegralConvertResult FormatConvertImpl(unsigned long v,  // NOLINT
  502                                         const FormatConversionSpecImpl conv,
  503                                         FormatSinkImpl *sink) {
  504   return {ConvertIntArg(v, conv, sink)};
  505 }
  506 IntegralConvertResult FormatConvertImpl(long long v,  // NOLINT
  507                                         const FormatConversionSpecImpl conv,
  508                                         FormatSinkImpl *sink) {
  509   return {ConvertIntArg(v, conv, sink)};
  510 }
  511 IntegralConvertResult FormatConvertImpl(unsigned long long v,  // NOLINT
  512                                         const FormatConversionSpecImpl conv,
  513                                         FormatSinkImpl *sink) {
  514   return {ConvertIntArg(v, conv, sink)};
  515 }
  516 IntegralConvertResult FormatConvertImpl(absl::int128 v,
  517                                         const FormatConversionSpecImpl conv,
  518                                         FormatSinkImpl *sink) {
  519   return {ConvertIntArg(v, conv, sink)};
  520 }
  521 IntegralConvertResult FormatConvertImpl(absl::uint128 v,
  522                                         const FormatConversionSpecImpl conv,
  523                                         FormatSinkImpl *sink) {
  524   return {ConvertIntArg(v, conv, sink)};
  525 }
  526 
  527 ABSL_INTERNAL_FORMAT_DISPATCH_OVERLOADS_EXPAND_();
  528 
  529 
  530 
  531 }  // namespace str_format_internal
  532 
  533 ABSL_NAMESPACE_END
  534 }  // namespace absl