diff --git a/fmt/format.cc b/fmt/format.cc index ad3a1cb0..157bfbcc 100644 --- a/fmt/format.cc +++ b/fmt/format.cc @@ -686,8 +686,8 @@ FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg( return arg; } -template -void fmt::internal::PrintfFormatter::parse_flags( +template +void fmt::internal::PrintfFormatter::parse_flags( FormatSpec &spec, const Char *&s) { for (;;) { switch (*s++) { @@ -713,8 +713,8 @@ void fmt::internal::PrintfFormatter::parse_flags( } } -template -Arg fmt::internal::PrintfFormatter::get_arg( +template +Arg fmt::internal::PrintfFormatter::get_arg( const Char *s, unsigned arg_index) { (void)s; const char *error = 0; @@ -725,8 +725,8 @@ Arg fmt::internal::PrintfFormatter::get_arg( return arg; } -template -unsigned fmt::internal::PrintfFormatter::parse_header( +template +unsigned fmt::internal::PrintfFormatter::parse_header( const Char *&s, FormatSpec &spec) { unsigned arg_index = UINT_MAX; Char c = *s; @@ -759,8 +759,8 @@ unsigned fmt::internal::PrintfFormatter::parse_header( return arg_index; } -template -void fmt::internal::PrintfFormatter::format( +template + void fmt::internal::PrintfFormatter::format( BasicWriter &writer, BasicCStringRef format_str) { const Char *start = format_str.c_str(); const Char *s = start; @@ -853,11 +853,12 @@ void fmt::internal::PrintfFormatter::format( start = s; // Format argument. - internal::PrintfArgFormatter(writer, spec).visit(arg); + PAF(writer, spec).visit(arg); } write(writer, start, s); } + FMT_FUNC void fmt::report_system_error( int error_code, fmt::StringRef message) FMT_NOEXCEPT { // 'fmt::' is for bcc32. diff --git a/fmt/format.h b/fmt/format.h index 7cdac979..e6a8f423 100644 --- a/fmt/format.h +++ b/fmt/format.h @@ -237,7 +237,7 @@ typedef __int64 intmax_t; # define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n) #endif -// Some compilers masquerade as both MSVC and GCC-likes or +// Some compilers masquerade as both MSVC and GCC-likes or // otherwise support __builtin_clz and __builtin_clzll, so // only define FMT_BUILTIN_CLZ using the MSVC intrinsics // if the clz and clzll builtins are not available. @@ -253,7 +253,7 @@ inline uint32_t clz(uint32_t x) { assert(x != 0); // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, + // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 31 - r; @@ -279,7 +279,7 @@ inline uint32_t clzll(uint64_t x) { assert(x != 0); // Static analysis complains about using uninitialized data - // "r", but the only way that can happen is if "x" is 0, + // "r", but the only way that can happen is if "x" is 0, // which the callers guarantee to not happen. # pragma warning(suppress: 6102) return 63 - r; @@ -378,6 +378,7 @@ class BasicWriter; typedef BasicWriter Writer; typedef BasicWriter WWriter; +// Define default ArgFormatter and BasicFormatter. template class ArgFormatter; @@ -1296,7 +1297,7 @@ public: MakeArg() { type = Arg::NONE; } - + template MakeArg(const T &value) : Arg(MakeValue(value)) { @@ -1939,7 +1940,7 @@ class FormatterBase { }; // A printf formatter. -template + template > class PrintfFormatter : private FormatterBase { private: void parse_flags(FormatSpec &spec, const Char *&s); @@ -2091,7 +2092,7 @@ struct ArgArray; template struct ArgArray { typedef Value Type[N > 0 ? N : 1]; - + template static Value make(const T &value) { #ifdef __clang__ @@ -2287,7 +2288,7 @@ class SystemError : public internal::RuntimeError { Formats an error returned by an operating system or a language runtime, for example a file opening error, and writes it to *out* in the following form: - + .. parsed-literal:: **: ** @@ -3187,9 +3188,9 @@ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args); */ FMT_API void print(CStringRef format_str, ArgList args); -template + template void printf(BasicWriter &w, BasicCStringRef format, ArgList args) { - internal::PrintfFormatter(args).format(w, format); + internal::PrintfFormatter(args).format(w, format); } /** @@ -3815,8 +3816,10 @@ struct UdlArg { } }; + } // namespace internal + inline namespace literals { /** @@ -3850,6 +3853,7 @@ inline internal::UdlArg operator"" _a(const wchar_t *s, std::size_t) { return {s}; } } // inline namespace literals + } // namespace fmt #endif // FMT_USE_USER_DEFINED_LITERALS diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8758e47e..2371ae21 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -80,6 +80,7 @@ add_fmt_test(printf-test) add_fmt_test(string-test) add_fmt_test(util-test mock-allocator.h) add_fmt_test(macro-test) +add_fmt_test(custom-formatter-test) # Enable stricter options for one test to make sure that the header is free of # warnings. @@ -129,7 +130,7 @@ if (FMT_PEDANTIC) "${CMAKE_CURRENT_BINARY_DIR}/compile-test" --build-generator ${CMAKE_GENERATOR} --build-makeprogram ${CMAKE_MAKE_PROGRAM} - --build-options + --build-options "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" "-DCPP11_FLAG=${CPP11_FLAG}" "-DSUPPORTS_USER_DEFINED_LITERALS=${SUPPORTS_USER_DEFINED_LITERALS}") diff --git a/test/custom-formatter-test.cc b/test/custom-formatter-test.cc new file mode 100644 index 00000000..bb20f413 --- /dev/null +++ b/test/custom-formatter-test.cc @@ -0,0 +1,41 @@ +#include "fmt/format.h" +#include + +// A custom argument formatter that doesn't print `-` for floating-point values +// rounded to 0. +class CustomArgFormatter : + public fmt::BasicArgFormatter { + public: + CustomArgFormatter(fmt::BasicFormatter &f, + fmt::FormatSpec &s, const char *fmt) + : fmt::BasicArgFormatter(f, s, fmt) {} + + void visit_double(double value) { + if (round(value * pow(10, spec().precision())) == 0) + value = 0; + fmt::BasicArgFormatter::visit_double(value); + } +}; + +std::string custom_format(const char *format_str, fmt::ArgList args) { + fmt::MemoryWriter writer; + // Pass custom argument formatter as a template arg to BasicFormatter. + fmt::BasicFormatter formatter(args, writer); + formatter.format(format_str); + return writer.str(); +} +FMT_VARIADIC(std::string, custom_format, const char *) + +std::string printfer(const char* fstr, fmt::ArgList args){ + fmt::MemoryWriter writer; + fmt::internal::PrintfFormatter pfer(args); + pfer.format(writer,fstr); + return writer.str(); +} + +FMT_VARIADIC(std::string, printfer, const char*); + +int main() { + std::cout << custom_format("custom: {:.2f}", -0.000001) << std::endl; + std::cout << printfer("printf: %.2f", -0.0001) << std::endl; +}