mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-24 12:14:26 +00:00
BasicArgFormatter -> ArgFormatter. FullFormat -> ActiveFormatter. Use ActiveFormatter to implement Format and Print.
This commit is contained in:
parent
57dbd2c3fe
commit
87b5ebfc4a
18
README.rst
18
README.rst
@ -46,6 +46,24 @@ An object of any user-defined type for which there is an overloaded
|
|||||||
std::string s = str(fmt::Format("The date is {0}") << Date(2012, 12, 9));
|
std::string s = str(fmt::Format("The date is {0}") << Date(2012, 12, 9));
|
||||||
// s == "The date is 2012-12-9"
|
// s == "The date is 2012-12-9"
|
||||||
|
|
||||||
|
You can use ``fmt::ActiveFormatter`` to create your own functions
|
||||||
|
similar to ``fmt::Format`` and ``fmt::Print`` with an arbitrary action
|
||||||
|
performed when formatting is complete:
|
||||||
|
|
||||||
|
struct PrintError {
|
||||||
|
void operator()(const fmt::Formatter &f) const {
|
||||||
|
std::cerr << "Error: " << f.str() << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Formats an error message and prints it to std::cerr.
|
||||||
|
fmt::ActiveFormatter<PrintError> ReportError(const char *format) {
|
||||||
|
fmt::ActiveFormatter<PrintError> af(format);
|
||||||
|
return af;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReportError("File not found: {0}") << path;
|
||||||
|
|
||||||
Format string syntax
|
Format string syntax
|
||||||
--------------------
|
--------------------
|
||||||
|
|
||||||
|
@ -366,8 +366,3 @@ void fmt::Formatter::DoFormat() {
|
|||||||
buffer_.append(start, s + 1);
|
buffer_.append(start, s + 1);
|
||||||
buffer_.resize(buffer_.size() - 1); // Don't count the terminating zero.
|
buffer_.resize(buffer_.size() - 1); // Don't count the terminating zero.
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt::BasicArgFormatter::~BasicArgFormatter() {
|
|
||||||
if (!formatter_) return;
|
|
||||||
FinishFormatting();
|
|
||||||
}
|
|
||||||
|
111
format.h
111
format.h
@ -94,7 +94,7 @@ class FormatError : public std::runtime_error {
|
|||||||
FormatError(const std::string &message) : std::runtime_error(message) {}
|
FormatError(const std::string &message) : std::runtime_error(message) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class BasicArgFormatter;
|
class ArgFormatter;
|
||||||
|
|
||||||
// Formatter provides string formatting functionality similar to Python's
|
// Formatter provides string formatting functionality similar to Python's
|
||||||
// str.format. The output is stored in a memory buffer that grows dynamically.
|
// str.format. The output is stored in a memory buffer that grows dynamically.
|
||||||
@ -183,17 +183,17 @@ class Formatter {
|
|||||||
format(&Formatter::FormatCustomArg<T>) {}
|
format(&Formatter::FormatCustomArg<T>) {}
|
||||||
|
|
||||||
~Arg() {
|
~Arg() {
|
||||||
// Format is called here to make sure that the argument object
|
// Format is called here to make sure that a referred object is
|
||||||
// referred to is still alive, for example:
|
// still alive, for example:
|
||||||
//
|
//
|
||||||
// Print("{0}") << std::string("test");
|
// Print("{0}") << std::string("test");
|
||||||
//
|
//
|
||||||
// Here an Arg object refers to a temporary std::string which is
|
// Here an Arg object refers to a temporary std::string which is
|
||||||
// destroyed at the end of the statement. Since the string object is
|
// destroyed at the end of the statement. Since the string object is
|
||||||
// constructed before the Arg object, it will be destroyed after,
|
// constructed before the Arg object, it will be destroyed after,
|
||||||
// so it will be alive in the Arg's destructor when Format is called.
|
// so it will be alive in the Arg's destructor where Format is called.
|
||||||
// Note that the string object will not necessarily be alive when
|
// Note that the string object will not necessarily be alive when
|
||||||
// the destructor of BasicArgFormatter is called.
|
// the destructor of ArgFormatter is called.
|
||||||
formatter->Format();
|
formatter->Format();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -203,7 +203,7 @@ class Formatter {
|
|||||||
|
|
||||||
const char *format_; // Format string.
|
const char *format_; // Format string.
|
||||||
|
|
||||||
friend class BasicArgFormatter;
|
friend class ArgFormatter;
|
||||||
|
|
||||||
void Add(const Arg &arg) {
|
void Add(const Arg &arg) {
|
||||||
args_.push_back(&arg);
|
args_.push_back(&arg);
|
||||||
@ -238,36 +238,38 @@ class Formatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Formatter() : format_(0) {}
|
Formatter() : format_(0) { buffer_[0] = 0; }
|
||||||
|
|
||||||
// Formats a string appending the output to the internal buffer.
|
// Formats a string appending the output to the internal buffer.
|
||||||
// Arguments are accepted through the returned BasicArgFormatter object
|
// Arguments are accepted through the returned ArgFormatter object
|
||||||
// using inserter operator<<.
|
// using inserter operator<<.
|
||||||
BasicArgFormatter operator()(const char *format);
|
ArgFormatter operator()(const char *format);
|
||||||
|
|
||||||
std::size_t size() const { return buffer_.size(); }
|
std::size_t size() const { return buffer_.size(); }
|
||||||
|
|
||||||
const char *data() const { return &buffer_[0]; }
|
const char *data() const { return &buffer_[0]; }
|
||||||
const char *c_str() const { return &buffer_[0]; }
|
const char *c_str() const { return &buffer_[0]; }
|
||||||
|
|
||||||
|
std::string str() const { return std::string(&buffer_[0], buffer_.size()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
// Argument formatter. This is a transient object that normally exists
|
// Argument formatter. This is a transient object that normally exists
|
||||||
// only as a temporary returned by one of the formatting functions.
|
// only as a temporary returned by one of the formatting functions.
|
||||||
// It stores a reference to a formatter and provides operators <<
|
// It stores a reference to a formatter and provides operator<<
|
||||||
// that feed arguments to the formatter.
|
// that feeds arguments to the formatter.
|
||||||
class BasicArgFormatter {
|
class ArgFormatter {
|
||||||
private:
|
private:
|
||||||
friend class Formatter;
|
friend class Formatter;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable Formatter *formatter_;
|
mutable Formatter *formatter_;
|
||||||
|
|
||||||
BasicArgFormatter(BasicArgFormatter& other)
|
ArgFormatter(ArgFormatter& other)
|
||||||
: formatter_(other.formatter_) {
|
: formatter_(other.formatter_) {
|
||||||
other.formatter_ = 0;
|
other.formatter_ = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicArgFormatter& operator=(const BasicArgFormatter& other) {
|
ArgFormatter& operator=(const ArgFormatter& other) {
|
||||||
formatter_ = other.formatter_;
|
formatter_ = other.formatter_;
|
||||||
other.formatter_ = 0;
|
other.formatter_ = 0;
|
||||||
return *this;
|
return *this;
|
||||||
@ -283,33 +285,24 @@ class BasicArgFormatter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit BasicArgFormatter(Formatter &f) : formatter_(&f) {}
|
explicit ArgFormatter(Formatter &f) : formatter_(&f) {}
|
||||||
~BasicArgFormatter();
|
~ArgFormatter() { FinishFormatting(); }
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(const Formatter::Arg &arg) {
|
// Feeds an argument to a formatter.
|
||||||
|
ArgFormatter &operator<<(const Formatter::Arg &arg) {
|
||||||
arg.formatter = formatter_;
|
arg.formatter = formatter_;
|
||||||
formatter_->Add(arg);
|
formatter_->Add(arg);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
friend const char *c_str(const BasicArgFormatter &af) {
|
// Performs formatting and returns a C string with the output.
|
||||||
|
friend const char *c_str(const ArgFormatter &af) {
|
||||||
return af.FinishFormatting()->c_str();
|
return af.FinishFormatting()->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
friend std::string str(const BasicArgFormatter &af) {
|
// Performs formatting and returns a std::string with the output.
|
||||||
return af.FinishFormatting()->c_str();
|
friend std::string str(const ArgFormatter &af) {
|
||||||
}
|
return af.FinishFormatting()->str();
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Callback>
|
|
||||||
class ArgFormatter : public BasicArgFormatter {
|
|
||||||
public:
|
|
||||||
explicit ArgFormatter(Formatter &f) : BasicArgFormatter(f) {}
|
|
||||||
|
|
||||||
~ArgFormatter() {
|
|
||||||
if (!formatter_) return;
|
|
||||||
Callback callback;
|
|
||||||
callback(*formatter_);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -325,55 +318,53 @@ void Formatter::FormatCustomArg(const void *arg, int width) {
|
|||||||
std::fill_n(out + str.size(), width - str.size(), ' ');
|
std::fill_n(out + str.size(), width - str.size(), ' ');
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BasicArgFormatter Formatter::operator()(const char *format) {
|
inline ArgFormatter Formatter::operator()(const char *format) {
|
||||||
BasicArgFormatter formatter(*this);
|
ArgFormatter formatter(*this);
|
||||||
format_ = format;
|
format_ = format;
|
||||||
args_.clear();
|
args_.clear();
|
||||||
return formatter;
|
return formatter;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FullFormat : public BasicArgFormatter {
|
// A formatter with an action performed when formatting is complete.
|
||||||
|
template <typename Action>
|
||||||
|
class ActiveFormatter : public ArgFormatter {
|
||||||
private:
|
private:
|
||||||
mutable Formatter formatter_;
|
mutable Formatter formatter_;
|
||||||
|
|
||||||
// Do not implement.
|
// Do not implement.
|
||||||
FullFormat& operator=(const FullFormat&);
|
ActiveFormatter& operator=(const ActiveFormatter&);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit FullFormat(const char *format) : BasicArgFormatter(formatter_) {
|
explicit ActiveFormatter(const char *format) : ArgFormatter(formatter_) {
|
||||||
BasicArgFormatter::operator=(formatter_(format));
|
ArgFormatter::operator=(formatter_(format));
|
||||||
}
|
}
|
||||||
|
|
||||||
FullFormat(FullFormat& other) : BasicArgFormatter(other) {}
|
ActiveFormatter(ActiveFormatter& other) : ArgFormatter(other) {}
|
||||||
|
|
||||||
~FullFormat() {
|
~ActiveFormatter() {
|
||||||
FinishFormatting();
|
Action()(*FinishFormatting());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline FullFormat Format(const char *format) {
|
struct Ignore {
|
||||||
FullFormat ff(format);
|
void operator()(Formatter &) const {}
|
||||||
return ff;
|
};
|
||||||
|
|
||||||
|
inline ActiveFormatter<Ignore> Format(const char *format) {
|
||||||
|
ActiveFormatter<Ignore> af(format);
|
||||||
|
return af;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Print : public BasicArgFormatter {
|
struct Write {
|
||||||
private:
|
void operator()(Formatter &f) const {
|
||||||
Formatter formatter_;
|
std::fwrite(f.data(), 1, f.size(), stdout);
|
||||||
|
|
||||||
// Do not implement.
|
|
||||||
Print(const Print&);
|
|
||||||
Print& operator=(const Print&);
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit Print(const char *format) : BasicArgFormatter(formatter_) {
|
|
||||||
BasicArgFormatter::operator=(formatter_(format));
|
|
||||||
}
|
|
||||||
|
|
||||||
~Print() {
|
|
||||||
FinishFormatting();
|
|
||||||
std::fwrite(formatter_.data(), 1, formatter_.size(), stdout);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline ActiveFormatter<Write> Print(const char *format) {
|
||||||
|
ActiveFormatter<Write> af(format);
|
||||||
|
return af;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace fmt = format;
|
namespace fmt = format;
|
||||||
|
@ -525,18 +525,58 @@ TEST(FormatterTest, FormatStringFromSpeedTest) {
|
|||||||
TEST(FormatterTest, ArgLifetime) {
|
TEST(FormatterTest, ArgLifetime) {
|
||||||
// The following code is for testing purposes only. It is a definite abuse
|
// The following code is for testing purposes only. It is a definite abuse
|
||||||
// of the API and shouldn't be used in real applications.
|
// of the API and shouldn't be used in real applications.
|
||||||
const fmt::BasicArgFormatter &af = fmt::Format("{0}");
|
const fmt::ArgFormatter &af = fmt::Format("{0}");
|
||||||
const_cast<fmt::BasicArgFormatter&>(af) << std::string("test");
|
const_cast<fmt::ArgFormatter&>(af) << std::string("test");
|
||||||
// String object passed as an argument to Print has been destroyed,
|
// String object passed as an argument to Print has been destroyed,
|
||||||
// but BasicArgFormatter dtor hasn't been called yet.
|
// but BasicArgFormatter dtor hasn't been called yet.
|
||||||
EXPECT_EQ("test", str(af));
|
EXPECT_EQ("test", str(af));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, Formatter) {
|
TEST(FormatterTest, FormatterCtor) {
|
||||||
|
Formatter format;
|
||||||
|
EXPECT_EQ(0, format.size());
|
||||||
|
EXPECT_STREQ("", format.data());
|
||||||
|
EXPECT_STREQ("", format.c_str());
|
||||||
|
EXPECT_EQ("", format.str());
|
||||||
|
format("part{0}") << 1;
|
||||||
|
format("part{0}") << 2;
|
||||||
|
EXPECT_EQ("part1part2", format.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatterAppend) {
|
||||||
|
Formatter format;
|
||||||
|
format("part{0}") << 1;
|
||||||
|
EXPECT_EQ(strlen("part1"), format.size());
|
||||||
|
EXPECT_STREQ("part1", format.c_str());
|
||||||
|
EXPECT_STREQ("part1", format.data());
|
||||||
|
EXPECT_EQ("part1", format.str());
|
||||||
|
format("part{0}") << 2;
|
||||||
|
EXPECT_EQ(strlen("part1part2"), format.size());
|
||||||
|
EXPECT_STREQ("part1part2", format.c_str());
|
||||||
|
EXPECT_STREQ("part1part2", format.data());
|
||||||
|
EXPECT_EQ("part1part2", format.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, FormatterExample) {
|
||||||
Formatter format;
|
Formatter format;
|
||||||
format("Current point:\n");
|
format("Current point:\n");
|
||||||
format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
format("({0:+f}, {1:+f})\n") << -3.14 << 3.14;
|
||||||
EXPECT_STREQ("Current point:\n(-3.140000, +3.140000)\n", format.c_str());
|
EXPECT_EQ("Current point:\n(-3.140000, +3.140000)\n", format.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: test API
|
struct PrintError {
|
||||||
|
void operator()(const fmt::Formatter &f) const {
|
||||||
|
std::cerr << "Error: " << f.str() << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fmt::ActiveFormatter<PrintError> ReportError(const char *format) {
|
||||||
|
fmt::ActiveFormatter<PrintError> af(format);
|
||||||
|
return af;
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(FormatterTest, ArgFormatter) {
|
||||||
|
std::string path = "somefile";
|
||||||
|
ReportError("File not found: {0}") << path;
|
||||||
|
}
|
||||||
|
// TODO: test ArgFormatter
|
||||||
|
Loading…
Reference in New Issue
Block a user