} // namespace detail
-
-template <bool containerMode, class... Args>
-Formatter<containerMode, Args...>::Formatter(StringPiece str, Args&&... args)
- : str_(str),
- values_(FormatValue<typename std::decay<Args>::type>(
- std::forward<Args>(args))...) {
+template <class Derived, bool containerMode, class... Args>
+BaseFormatter<Derived, containerMode, Args...>::BaseFormatter(StringPiece str,
+ Args&&... args)
+ : str_(str),
+ values_(FormatValue<typename std::decay<Args>::type>(
+ std::forward<Args>(args))...) {
static_assert(!containerMode || sizeof...(Args) == 1,
"Exactly one argument required in container mode");
}
-template <bool containerMode, class... Args>
-void Formatter<containerMode, Args...>::handleFormatStrError() const {
+template <class Derived, bool containerMode, class... Args>
+void BaseFormatter<Derived, containerMode, Args...>::handleFormatStrError()
+ const {
if (crashOnError_) {
LOG(FATAL) << "folly::format: bad format string \"" << str_ << "\": " <<
folly::exceptionStr(std::current_exception());
throw;
}
-template <bool containerMode, class... Args>
+template <class Derived, bool containerMode, class... Args>
template <class Output>
-void Formatter<containerMode, Args...>::operator()(Output& out) const {
+void BaseFormatter<Derived, containerMode, Args...>::operator()(Output& out)
+ const {
// Catch BadFormatArg and range_error exceptions, and call
// handleFormatStrError().
//
}
}
-template <bool containerMode, class... Args>
+template <class Derived, bool containerMode, class... Args>
template <class Output>
-void Formatter<containerMode, Args...>::appendOutput(Output& out) const {
+void BaseFormatter<Derived, containerMode, Args...>::appendOutput(Output& out)
+ const {
auto p = str_.begin();
auto end = str_.end();
}
}
-template <bool containerMode, class... Args>
-void writeTo(FILE* fp, const Formatter<containerMode, Args...>& formatter) {
+template <class Derived, bool containerMode, class... Args>
+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);
if (n < sp.size()) {
int padRemaining = 0;
if (arg.width != FormatArg::kDefaultWidth && val.size() < 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) {
format_value::formatString(val, arg, cb);
}
-template <class FormatCallback, bool containerMode, class... Args>
-void formatFormatter(const Formatter<containerMode, Args...>& formatter,
- FormatArg& arg,
- FormatCallback& cb) {
+template <class FormatCallback,
+ class Derived,
+ bool containerMode,
+ class... Args>
+void formatFormatter(
+ const BaseFormatter<Derived, containerMode, Args...>& formatter,
+ FormatArg& arg,
+ FormatCallback& cb) {
if (arg.width == FormatArg::kDefaultWidth &&
arg.precision == FormatArg::kDefaultPrecision) {
// nothing to do
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;
};
// Partial specialization of FormatValue for nested Formatters
-template <bool containerMode, class... Args>
-class FormatValue<Formatter<containerMode, Args...>, void> {
- typedef Formatter<containerMode, Args...> FormatterValue;
+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> {
+ typedef typename F<containerMode, Args...>::BaseType FormatterValue;
+
public:
explicit FormatValue(const FormatterValue& f) : f_(f) { }
* Formatter objects can be appended to strings, and therefore they're
* compatible with folly::toAppend and folly::to.
*/
-template <class Tgt, bool containerMode, class... Args>
-typename std::enable_if<
- IsSomeString<Tgt>::value>::type
-toAppend(const Formatter<containerMode, Args...>& value, Tgt * result) {
+template <class Tgt, class Derived, bool containerMode, class... Args>
+typename std::enable_if<IsSomeString<Tgt>::value>::type toAppend(
+ const BaseFormatter<Derived, containerMode, Args...>& value, Tgt* result) {
value.appendTo(*result);
}