void FormatValue::formatHelper()

in folly/Format.cpp [98:230]


void FormatValue<double>::formatHelper(
    fbstring& piece, int& prefixLen, FormatArg& arg) const {
  using ::double_conversion::DoubleToStringConverter;
  using ::double_conversion::StringBuilder;

  arg.validate(FormatArg::Type::FLOAT);

  if (arg.presentation == FormatArg::kDefaultPresentation) {
    arg.presentation = 'g';
  }

  const char* infinitySymbol = isupper(arg.presentation) ? "INF" : "inf";
  const char* nanSymbol = isupper(arg.presentation) ? "NAN" : "nan";
  char exponentSymbol = isupper(arg.presentation) ? 'E' : 'e';

  if (arg.precision == FormatArg::kDefaultPrecision) {
    arg.precision = 6;
  }

  // 2+: for null terminator and optional sign shenanigans.
  constexpr int bufLen = 2 +
      constexpr_max(2 + DoubleToStringConverter::kMaxFixedDigitsBeforePoint +
                        DoubleToStringConverter::kMaxFixedDigitsAfterPoint,
                    constexpr_max(
                        8 + DoubleToStringConverter::kMaxExponentialDigits,
                        7 + DoubleToStringConverter::kMaxPrecisionDigits));
  char buf[bufLen];
  StringBuilder builder(buf + 1, bufLen - 1);

  char plusSign;
  switch (arg.sign) {
    case FormatArg::Sign::PLUS_OR_MINUS:
      plusSign = '+';
      break;
    case FormatArg::Sign::SPACE_OR_MINUS:
      plusSign = ' ';
      break;
    case FormatArg::Sign::DEFAULT:
    case FormatArg::Sign::MINUS:
    case FormatArg::Sign::INVALID:
    default:
      plusSign = '\0';
      break;
  };

  auto flags = DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
      (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
                       : 0);

  double val = val_;
  switch (arg.presentation) {
    case '%':
      val *= 100;
      FOLLY_FALLTHROUGH;
    case 'f':
    case 'F': {
      if (arg.precision > DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
        arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
      }
      DoubleToStringConverter conv(
          flags,
          infinitySymbol,
          nanSymbol,
          exponentSymbol,
          -4,
          arg.precision,
          0,
          0);
      arg.enforce(
          conv.ToFixed(val, arg.precision, &builder),
          "fixed double conversion failed");
      break;
    }
    case 'e':
    case 'E': {
      if (arg.precision > DoubleToStringConverter::kMaxExponentialDigits) {
        arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
      }

      DoubleToStringConverter conv(
          flags,
          infinitySymbol,
          nanSymbol,
          exponentSymbol,
          -4,
          arg.precision,
          0,
          0);
      arg.enforce(conv.ToExponential(val, arg.precision, &builder));
      break;
    }
    case 'n': // should be locale-aware, but isn't
    case 'g':
    case 'G': {
      if (arg.precision < DoubleToStringConverter::kMinPrecisionDigits) {
        arg.precision = DoubleToStringConverter::kMinPrecisionDigits;
      } else if (arg.precision > DoubleToStringConverter::kMaxPrecisionDigits) {
        arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
      }
      DoubleToStringConverter conv(
          flags,
          infinitySymbol,
          nanSymbol,
          exponentSymbol,
          -4,
          arg.precision,
          0,
          0);
      arg.enforce(conv.ToShortest(val, &builder));
      break;
    }
    default:
      arg.error("invalid specifier '", arg.presentation, "'");
  }

  auto len = builder.position();
  builder.Finalize();
  assert(len > 0);

  // Add '+' or ' ' sign if needed
  char* p = buf + 1;
  // anything that's neither negative nor nan
  prefixLen = 0;
  if (plusSign && (*p != '-' && *p != 'n' && *p != 'N')) {
    *--p = plusSign;
    ++len;
    prefixLen = 1;
  } else if (*p == '-') {
    prefixLen = 1;
  }

  piece = fbstring(p, size_t(len));
}