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);
}