/*
- * Copyright 2014 Facebook, Inc.
+ * Copyright 2015 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
namespace detail {
+// Updates the end of the buffer after the comma separators have been added.
+void insertThousandsGroupingUnsafe(char* start_buffer, char** end_buffer);
+
extern const char formatHexUpper[256][2];
extern const char formatHexLower[256][2];
extern const char formatOctal[512][3];
template <class Output>
void BaseFormatter<Derived, containerMode, Args...>::appendOutput(Output& out)
const {
- auto p = str_.begin();
- auto end = str_.end();
// Copy raw string (without format specifiers) to output;
// not as simple as we'd like, as we still need to translate "}}" to "}"
}
};
+ auto p = str_.begin();
+ auto end = str_.end();
+
int nextArg = 0;
bool hasDefaultArgIndex = false;
bool hasExplicitArgIndex = false;
void writeTo(FILE* fp,
const BaseFormatter<Derived, containerMode, Args...>& formatter) {
auto writer = [fp] (StringPiece sp) {
- ssize_t n = fwrite(sp.data(), 1, sp.size(), fp);
+ size_t n = fwrite(sp.data(), 1, sp.size(), fp);
if (n < sp.size()) {
throwSystemError("Formatter writeTo", "fwrite failed");
}
template <class FormatCallback>
void formatString(StringPiece val, FormatArg& arg, FormatCallback& cb) {
+ if (arg.width != FormatArg::kDefaultWidth && arg.width < 0) {
+ throw BadFormatArg("folly::format: invalid width");
+ }
+ if (arg.precision != FormatArg::kDefaultPrecision && arg.precision < 0) {
+ throw BadFormatArg("folly::format: invalid precision");
+ }
+
+ // XXX: clang should be smart enough to not need the two static_cast<size_t>
+ // uses below given the above checks. If clang ever becomes that smart, we
+ // should remove the otherwise unnecessary warts.
+
if (arg.precision != FormatArg::kDefaultPrecision &&
- val.size() > arg.precision) {
+ val.size() > static_cast<size_t>(arg.precision)) {
val.reset(val.data(), arg.precision);
}
};
int padRemaining = 0;
- if (arg.width != FormatArg::kDefaultWidth && val.size() < arg.width) {
+ if (arg.width != FormatArg::kDefaultWidth &&
+ val.size() < static_cast<size_t>(arg.width)) {
char fill = arg.fill == FormatArg::kDefaultFill ? ' ' : arg.fill;
- int padChars = arg.width - val.size();
+ int padChars = static_cast<int> (arg.width - val.size());
memset(padBuf, fill, std::min(padBufSize, padChars));
switch (arg.align) {
char* valBufBegin = nullptr;
char* valBufEnd = nullptr;
- // Defer to sprintf
- auto useSprintf = [&] (const char* format) mutable {
- valBufBegin = valBuf + 3; // room for sign and base prefix
- valBufEnd = valBufBegin + sprintf(valBufBegin, format,
- static_cast<uintmax_t>(uval));
- };
-
int prefixLen = 0;
-
switch (presentation) {
- case 'n': // TODO(tudorb): locale awareness?
+ 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 + 3; // room for sign and base prefix
+ valBufEnd = valBufBegin + sprintf(valBufBegin, "%'ju",
+ static_cast<uintmax_t>(uval));
+ break;
case 'd':
arg.enforce(!arg.basePrefix,
"base prefix not allowed with '", presentation,
"' specifier");
+ valBufBegin = valBuf + 3; // room for sign and base prefix
+
+ // Use uintToBuffer, faster than sprintf
+ valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
if (arg.thousandsSeparator) {
- useSprintf("%'ju");
- } else {
- // Use uintToBuffer, faster than sprintf
- valBufBegin = valBuf + 3;
- valBufEnd = valBufBegin + uint64ToBufferUnsafe(uval, valBufBegin);
+ detail::insertThousandsGroupingUnsafe(valBufBegin, &valBufEnd);
}
break;
case 'c':
DoubleToStringConverter::kMaxFixedDigitsAfterPoint),
(8 + DoubleToStringConverter::kMaxExponentialDigits),
(7 + DoubleToStringConverter::kMaxPrecisionDigits)})];
- StringBuilder builder(buf + 1, sizeof(buf) - 1);
+ StringBuilder builder(buf + 1, static_cast<int> (sizeof(buf) - 1));
char plusSign;
switch (arg.sign) {
break;
};
+ auto flags =
+ DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN |
+ (arg.trailingDot ? DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT
+ : 0);
+
double val = val_;
switch (arg.presentation) {
case '%':
DoubleToStringConverter::kMaxFixedDigitsAfterPoint) {
arg.precision = DoubleToStringConverter::kMaxFixedDigitsAfterPoint;
}
- DoubleToStringConverter conv(
- DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
- infinitySymbol,
- nanSymbol,
- exponentSymbol,
- -4, arg.precision,
- 0, 0);
+ DoubleToStringConverter conv(flags,
+ infinitySymbol,
+ nanSymbol,
+ exponentSymbol,
+ -4,
+ arg.precision,
+ 0,
+ 0);
arg.enforce(conv.ToFixed(val, arg.precision, &builder),
"fixed double conversion failed");
}
arg.precision = DoubleToStringConverter::kMaxExponentialDigits;
}
- DoubleToStringConverter conv(
- DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
- infinitySymbol,
- nanSymbol,
- exponentSymbol,
- -4, arg.precision,
- 0, 0);
+ DoubleToStringConverter conv(flags,
+ infinitySymbol,
+ nanSymbol,
+ exponentSymbol,
+ -4,
+ arg.precision,
+ 0,
+ 0);
arg.enforce(conv.ToExponential(val, arg.precision, &builder));
}
break;
DoubleToStringConverter::kMaxPrecisionDigits) {
arg.precision = DoubleToStringConverter::kMaxPrecisionDigits;
}
- DoubleToStringConverter conv(
- DoubleToStringConverter::EMIT_POSITIVE_EXPONENT_SIGN,
- infinitySymbol,
- nanSymbol,
- exponentSymbol,
- -4, arg.precision,
- 0, 0);
+ DoubleToStringConverter conv(flags,
+ infinitySymbol,
+ nanSymbol,
+ exponentSymbol,
+ -4,
+ arg.precision,
+ 0,
+ 0);
arg.enforce(conv.ToShortest(val, &builder));
}
break;
static const value_type& at(const C& c, int idx,
const value_type& dflt) {
- return (idx >= 0 && idx < c.size()) ? c.at(idx) : dflt;
+ return (idx >= 0 && size_t(idx) < c.size()) ? c.at(idx) : dflt;
}
};
};
// Partial specialization of FormatValue for nested Formatters
-template <bool containerMode,
- class... Args,
- template <bool containerMode, class... Args> class F>
+template <bool containerMode, class... Args,
+ template <bool, class...> class F>
class FormatValue<F<containerMode, Args...>,
typename std::enable_if<detail::IsFormatter<
F<containerMode, Args...>>::value>::type> {