void doFormat()

in folly/Format-inl.h [427:622]


  void doFormat(FormatArg& arg, FormatCallback& cb) const {
    char presentation = arg.presentation;
    if (presentation == FormatArg::kDefaultPresentation) {
      presentation = std::is_same<T, char>::value ? 'c' : 'd';
    }

    // Do all work as unsigned, we'll add the prefix ('0' or '0x' if necessary)
    // and sign ourselves.
    typedef typename std::make_unsigned<T>::type UT;
    UT uval;
    char sign;
    if (std::is_signed<T>::value) {
      if (folly::is_negative(val_)) {
        // avoid unary negation of unsigned types, which may be warned against
        // avoid ub signed integer overflow, which ubsan checks against
        uval = UT(0 - static_cast<UT>(val_));
        sign = '-';
      } else {
        uval = static_cast<UT>(val_);
        FOLLY_PUSH_WARNING
        FOLLY_CLANG_DISABLE_WARNING("-Wcovered-switch-default")
        switch (arg.sign) {
          case FormatArg::Sign::PLUS_OR_MINUS:
            sign = '+';
            break;
          case FormatArg::Sign::SPACE_OR_MINUS:
            sign = ' ';
            break;
          case FormatArg::Sign::DEFAULT:
          case FormatArg::Sign::MINUS:
          case FormatArg::Sign::INVALID:
          default:
            sign = '\0';
            break;
        }
        FOLLY_POP_WARNING
      }
    } else {
      uval = static_cast<UT>(val_);
      sign = '\0';

      arg.enforce(
          arg.sign == FormatArg::Sign::DEFAULT,
          "sign specifications not allowed for unsigned values");
    }

    // 1 byte for sign, plus max of:
    // #x: two byte "0x" prefix + kMaxHexLength
    // #o: one byte "0" prefix + kMaxOctalLength
    // #b: two byte "0b" prefix + kMaxBinaryLength
    // n: 19 bytes + 1 NUL
    // ,d: 26 bytes (including thousands separators!)
    //
    // Binary format must take the most space, so we use that.
    //
    // Note that we produce a StringPiece rather than NUL-terminating,
    // so we don't need an extra byte for a NUL.
    constexpr size_t valBufSize = 1 + 2 + detail::kMaxBinaryLength;
    char valBuf[valBufSize];
    char* valBufBegin = nullptr;
    char* valBufEnd = nullptr;

    int prefixLen = 0;
    switch (presentation) {
      case 'n': {
        arg.enforce(
            !arg.basePrefix,
            "base prefix not allowed with '",
            presentation,
            "' specifier");

        arg.enforce(
            !arg.thousandsSeparator,
            "cannot use ',' with the '",
            presentation,
            "' specifier");

        valBufBegin = valBuf + 1; // room for sign
#if defined(__ANDROID__)
        int len = snprintf(
            valBufBegin,
            (valBuf + valBufSize) - valBufBegin,
            "%" PRIuMAX,
            static_cast<uintmax_t>(uval));
#else
        int len = snprintf(
            valBufBegin,
            size_t((valBuf + valBufSize) - valBufBegin),
            "%ju",
            static_cast<uintmax_t>(uval));
#endif
        // valBufSize should always be big enough, so this should never
        // happen.
        assert(len < valBuf + valBufSize - valBufBegin);
        valBufEnd = valBufBegin + len;
        break;
      }
      case 'd':
        arg.enforce(
            !arg.basePrefix,
            "base prefix not allowed with '",
            presentation,
            "' specifier");
        valBufBegin = valBuf + 1; // room for sign

        // Use to_ascii_decimal, faster than sprintf
        valBufEnd = valBufBegin +
            to_ascii_decimal(valBufBegin, valBuf + sizeof(valBuf), uval);
        if (arg.thousandsSeparator) {
          detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
        }
        break;
      case 'c':
        arg.enforce(
            !arg.basePrefix,
            "base prefix not allowed with '",
            presentation,
            "' specifier");
        arg.enforce(
            !arg.thousandsSeparator,
            "thousands separator (',') not allowed with '",
            presentation,
            "' specifier");
        valBufBegin = valBuf + 1; // room for sign
        *valBufBegin = static_cast<char>(uval);
        valBufEnd = valBufBegin + 1;
        break;
      case 'o':
      case 'O':
        arg.enforce(
            !arg.thousandsSeparator,
            "thousands separator (',') not allowed with '",
            presentation,
            "' specifier");
        valBufEnd = valBuf + valBufSize;
        valBufBegin = &valBuf[detail::uintToOctal(valBuf, valBufSize, uval)];
        if (arg.basePrefix) {
          *--valBufBegin = '0';
          prefixLen = 1;
        }
        break;
      case 'x':
        arg.enforce(
            !arg.thousandsSeparator,
            "thousands separator (',') not allowed with '",
            presentation,
            "' specifier");
        valBufEnd = valBuf + valBufSize;
        valBufBegin = &valBuf[detail::uintToHexLower(valBuf, valBufSize, uval)];
        if (arg.basePrefix) {
          *--valBufBegin = 'x';
          *--valBufBegin = '0';
          prefixLen = 2;
        }
        break;
      case 'X':
        arg.enforce(
            !arg.thousandsSeparator,
            "thousands separator (',') not allowed with '",
            presentation,
            "' specifier");
        valBufEnd = valBuf + valBufSize;
        valBufBegin = &valBuf[detail::uintToHexUpper(valBuf, valBufSize, uval)];
        if (arg.basePrefix) {
          *--valBufBegin = 'X';
          *--valBufBegin = '0';
          prefixLen = 2;
        }
        break;
      case 'b':
      case 'B':
        arg.enforce(
            !arg.thousandsSeparator,
            "thousands separator (',') not allowed with '",
            presentation,
            "' specifier");
        valBufEnd = valBuf + valBufSize;
        valBufBegin = &valBuf[detail::uintToBinary(valBuf, valBufSize, uval)];
        if (arg.basePrefix) {
          *--valBufBegin = presentation; // 0b or 0B
          *--valBufBegin = '0';
          prefixLen = 2;
        }
        break;
      default:
        arg.error("invalid specifier '", presentation, "'");
    }

    if (sign) {
      *--valBufBegin = sign;
      ++prefixLen;
    }

    format_value::formatNumber(
        StringPiece(valBufBegin, valBufEnd), prefixLen, arg, cb);
  }