Commit 72d51e0b authored by Glen Stark's avatar Glen Stark Committed by Victor Zverovich

Implemented #335: custom printf support

parent 6ccb5673
# Define the fmt library, its includes and the needed defines.
# format.cc is added to FMT_HEADERS for the header-only configuration.
set(FMT_HEADERS format.h format.cc ostream.h ostream.cc string.h time.h)
set(FMT_HEADERS format.h format.cc ostream.h ostream.cc printf.h
string.h time.h)
if (HAVE_OPEN)
set(FMT_HEADERS ${FMT_HEADERS} posix.h)
set(FMT_SOURCES ${FMT_SOURCES} posix.cc)
......
This diff is collapsed.
......@@ -1318,8 +1318,8 @@ class RuntimeError : public std::runtime_error {
RuntimeError() : std::runtime_error("") {}
};
template <typename Char>
class PrintfArgFormatter;
template <typename Impl, typename Char>
class BasicPrintfArgFormatter;
template <typename Char>
class ArgMap;
......@@ -1937,26 +1937,6 @@ class FormatterBase {
w << BasicStringRef<Char>(start, internal::to_unsigned(end - start));
}
};
// A printf formatter.
template <typename Char>
class PrintfFormatter : private FormatterBase {
private:
void parse_flags(FormatSpec &spec, const Char *&s);
// Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument.
Arg get_arg(const Char *s,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index.
unsigned parse_header(const Char *&s, FormatSpec &spec);
public:
explicit PrintfFormatter(const ArgList &args) : FormatterBase(args) {}
FMT_API void format(BasicWriter<Char> &writer,
BasicCStringRef<Char> format_str);
};
} // namespace internal
/**
......@@ -2420,7 +2400,8 @@ class BasicWriter {
template <typename Impl, typename Char_>
friend class internal::ArgFormatterBase;
friend class internal::PrintfArgFormatter<Char>;
template <typename Impl, typename Char_>
friend class internal::BasicPrintfArgFormatter;
protected:
/**
......@@ -3187,56 +3168,6 @@ FMT_API void print(std::FILE *f, CStringRef format_str, ArgList args);
*/
FMT_API void print(CStringRef format_str, ArgList args);
template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
internal::PrintfFormatter<Char>(args).format(w, format);
}
/**
\rst
Formats arguments and returns the result as a string.
**Example**::
std::string message = fmt::sprintf("The answer is %d", 42);
\endrst
*/
inline std::string sprintf(CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
return w.str();
}
inline std::wstring sprintf(WCStringRef format, ArgList args) {
WMemoryWriter w;
printf(w, format, args);
return w.str();
}
/**
\rst
Prints formatted data to the file *f*.
**Example**::
fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::FILE *f, CStringRef format, ArgList args);
/**
\rst
Prints formatted data to ``stdout``.
**Example**::
fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst
*/
inline int printf(CStringRef format, ArgList args) {
return fprintf(stdout, format, args);
}
/**
Fast integer formatter.
*/
......@@ -3502,12 +3433,7 @@ FMT_VARIADIC(std::string, format, CStringRef)
FMT_VARIADIC_W(std::wstring, format, WCStringRef)
FMT_VARIADIC(void, print, CStringRef)
FMT_VARIADIC(void, print, std::FILE *, CStringRef)
FMT_VARIADIC(void, print_colored, Color, CStringRef)
FMT_VARIADIC(std::string, sprintf, CStringRef)
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
FMT_VARIADIC(int, printf, CStringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
namespace internal {
template <typename Char>
......
......@@ -26,6 +26,7 @@
*/
#include "fmt/ostream.h"
#include "fmt/printf.h"
namespace fmt {
......
This diff is collapsed.
......@@ -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.
......
/*
Custom argument formatter tests
Copyright (c) 2016, Victor Zverovich
All rights reserved.
For the license information refer to format.h.
*/
#include "fmt/printf.h"
#include "gtest-extra.h"
using fmt::internal::BasicPrintfArgFormatter;
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomArgFormatter
: public fmt::BasicArgFormatter<CustomArgFormatter, char> {
public:
CustomArgFormatter(fmt::BasicFormatter<char, CustomArgFormatter> &f,
fmt::FormatSpec &s, const char *fmt)
: fmt::BasicArgFormatter<CustomArgFormatter, char>(f, s, fmt) {}
void visit_double(double value) {
if (round(value * pow(10, spec().precision())) == 0)
value = 0;
fmt::BasicArgFormatter<CustomArgFormatter, char>::visit_double(value);
}
};
// A custom argument formatter that doesn't print `-` for floating-point values
// rounded to 0.
class CustomPAF : public BasicPrintfArgFormatter<CustomPAF, char> {
public:
CustomPAF(fmt::BasicWriter<char> &writer, fmt::FormatSpec &spec)
: BasicPrintfArgFormatter<CustomPAF, char>(writer, spec) {}
void visit_double(double value) {
if (round(value * pow(10, spec().precision())) == 0)
value = 0;
BasicPrintfArgFormatter<CustomPAF, char>::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<char, CustomArgFormatter> formatter(args, writer);
formatter.format(format_str);
return writer.str();
}
FMT_VARIADIC(std::string, custom_format, const char *)
std::string custom_sprintf(const char* fstr, fmt::ArgList args){
fmt::MemoryWriter writer;
fmt::internal::PrintfFormatter< char, CustomPAF > pfer( args);
pfer.format(writer, fstr);
return writer.str();
}
FMT_VARIADIC(std::string, custom_sprintf, const char*);
TEST(CustomFormatterTest, Format) {
EXPECT_EQ("0.00", custom_format("{:.2f}", -.00001));
EXPECT_EQ("0.00", custom_sprintf("%.2f", -.00001));
}
......@@ -46,7 +46,7 @@ TEST(FormatTest, ArgConverter) {
Arg arg = Arg();
arg.type = Arg::LONG_LONG;
arg.long_long_value = std::numeric_limits<fmt::LongLong>::max();
fmt::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg);
fmt::internal::ArgConverter<fmt::LongLong>(arg, 'd').visit(arg);
EXPECT_EQ(Arg::LONG_LONG, arg.type);
}
......
......@@ -29,6 +29,7 @@
#include <climits>
#include <cstring>
#include "fmt/printf.h"
#include "fmt/format.h"
#include "gtest-extra.h"
#include "util.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment