mirror of
https://github.com/fmtlib/fmt.git
synced 2024-11-26 12:10:06 +00:00
Fix a lifetime issue.
This commit is contained in:
parent
b1e4cbb023
commit
4db5a66455
@ -244,7 +244,7 @@ void fmt::Formatter::Format() {
|
|||||||
unsigned arg_index = ParseUInt(s);
|
unsigned arg_index = ParseUInt(s);
|
||||||
if (arg_index >= args_.size())
|
if (arg_index >= args_.size())
|
||||||
ReportError(s, "argument index is out of range in format");
|
ReportError(s, "argument index is out of range in format");
|
||||||
const Arg &arg = args_[arg_index];
|
const Arg &arg = *args_[arg_index];
|
||||||
|
|
||||||
unsigned flags = 0;
|
unsigned flags = 0;
|
||||||
int width = 0;
|
int width = 0;
|
||||||
|
166
format.h
166
format.h
@ -15,13 +15,6 @@
|
|||||||
|
|
||||||
namespace format {
|
namespace format {
|
||||||
|
|
||||||
class FormatError : public std::runtime_error {
|
|
||||||
public:
|
|
||||||
FormatError(const std::string &message) : std::runtime_error(message) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class BasicArgFormatter;
|
|
||||||
|
|
||||||
// A buffer with the first SIZE elements stored in the object itself.
|
// A buffer with the first SIZE elements stored in the object itself.
|
||||||
template <typename T, std::size_t SIZE>
|
template <typename T, std::size_t SIZE>
|
||||||
class Buffer {
|
class Buffer {
|
||||||
@ -95,6 +88,13 @@ void Buffer<T, SIZE>::append(const T *begin, const T *end) {
|
|||||||
size_ += num_elements;
|
size_ += num_elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FormatError : public std::runtime_error {
|
||||||
|
public:
|
||||||
|
FormatError(const std::string &message) : std::runtime_error(message) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class BasicArgFormatter;
|
||||||
|
|
||||||
// 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.
|
||||||
// Usage:
|
// Usage:
|
||||||
@ -124,7 +124,24 @@ class Formatter {
|
|||||||
typedef void (Formatter::*FormatFunc)(const void *arg, int width);
|
typedef void (Formatter::*FormatFunc)(const void *arg, int width);
|
||||||
|
|
||||||
// A format argument.
|
// A format argument.
|
||||||
struct Arg {
|
class Arg {
|
||||||
|
private:
|
||||||
|
// This method is private to disallow formatting of arbitrary pointers.
|
||||||
|
// If you want to output a pointer cast it to const void*. Do not implement!
|
||||||
|
template <typename T>
|
||||||
|
Arg(const T *value);
|
||||||
|
|
||||||
|
// This method is private to disallow formatting of arbitrary pointers.
|
||||||
|
// If you want to output a pointer cast it to void*. Do not implement!
|
||||||
|
template <typename T>
|
||||||
|
Arg(T *value);
|
||||||
|
|
||||||
|
// This method is private to disallow formatting of wide characters.
|
||||||
|
// If you want to output a wide character cast it to integer type.
|
||||||
|
// Do not implement!
|
||||||
|
Arg(wchar_t value);
|
||||||
|
|
||||||
|
public:
|
||||||
Type type;
|
Type type;
|
||||||
union {
|
union {
|
||||||
int int_value;
|
int int_value;
|
||||||
@ -143,32 +160,55 @@ class Formatter {
|
|||||||
FormatFunc format;
|
FormatFunc format;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
mutable Formatter **formatter;
|
||||||
|
|
||||||
Arg() {}
|
Arg(int value) : type(INT), int_value(value) {}
|
||||||
explicit Arg(int value) : type(INT), int_value(value) {}
|
Arg(unsigned value) : type(UINT), uint_value(value) {}
|
||||||
explicit Arg(unsigned value) : type(UINT), uint_value(value) {}
|
Arg(long value) : type(LONG), long_value(value) {}
|
||||||
explicit Arg(long value) : type(LONG), long_value(value) {}
|
Arg(unsigned long value) : type(ULONG), ulong_value(value) {}
|
||||||
explicit Arg(unsigned long value) : type(ULONG), ulong_value(value) {}
|
Arg(double value) : type(DOUBLE), double_value(value) {}
|
||||||
explicit Arg(double value) : type(DOUBLE), double_value(value) {}
|
Arg(long double value) : type(LONG_DOUBLE), long_double_value(value) {}
|
||||||
explicit Arg(long double value)
|
Arg(char value) : type(CHAR), int_value(value) {}
|
||||||
: type(LONG_DOUBLE), long_double_value(value) {}
|
Arg(const char *value) : type(STRING), string_value(value), size(0) {}
|
||||||
explicit Arg(char value) : type(CHAR), int_value(value) {}
|
Arg(char *value) : type(STRING), string_value(value), size(0) {}
|
||||||
explicit Arg(const char *value, std::size_t size = 0)
|
Arg(const void *value) : type(POINTER), pointer_value(value) {}
|
||||||
: type(STRING), string_value(value), size(size) {}
|
Arg(void *value) : type(POINTER), pointer_value(value) {}
|
||||||
explicit Arg(const void *value) : type(POINTER), pointer_value(value) {}
|
Arg(const std::string &value)
|
||||||
explicit Arg(const void *value, FormatFunc f)
|
: type(STRING), string_value(value.c_str()), size(value.size()) {}
|
||||||
: type(CUSTOM), custom_value(value), format(f) {}
|
|
||||||
|
template <typename T>
|
||||||
|
Arg(const T &value)
|
||||||
|
: type(CUSTOM), custom_value(&value),
|
||||||
|
format(&Formatter::FormatCustomArg<T>) {}
|
||||||
|
|
||||||
|
~Arg() {
|
||||||
|
// Format is called here to make sure that the argument object
|
||||||
|
// referred to is still alive, for example:
|
||||||
|
//
|
||||||
|
// Print("{0}") << std::string("test");
|
||||||
|
//
|
||||||
|
// Here an Arg object refers to a temporary std::string which is
|
||||||
|
// destroyed at the end of the statement. Since the string object is
|
||||||
|
// constructed before the Arg object, it will be destroyed after,
|
||||||
|
// so it will be alive in the Arg's destructor when Format is called.
|
||||||
|
// Note that the string object will not necessarily be alive when
|
||||||
|
// the destructor of BasicArgFormatter is called.
|
||||||
|
if (*formatter) {
|
||||||
|
(*formatter)->Format();
|
||||||
|
*formatter = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { NUM_INLINE_ARGS = 10 };
|
enum { NUM_INLINE_ARGS = 10 };
|
||||||
Buffer<Arg, NUM_INLINE_ARGS> args_; // Format arguments.
|
Buffer<const Arg*, NUM_INLINE_ARGS> args_; // Format arguments.
|
||||||
|
|
||||||
const char *format_; // Format string.
|
const char *format_; // Format string.
|
||||||
|
|
||||||
friend class BasicArgFormatter;
|
friend class BasicArgFormatter;
|
||||||
|
|
||||||
void Add(const Arg &arg) {
|
void Add(const Arg &arg) {
|
||||||
args_.push_back(arg);
|
args_.push_back(&arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Formats an integer.
|
// Formats an integer.
|
||||||
@ -216,16 +256,6 @@ class BasicArgFormatter {
|
|||||||
private:
|
private:
|
||||||
friend class Formatter;
|
friend class Formatter;
|
||||||
|
|
||||||
// This method is private to disallow formatting of arbitrary pointers.
|
|
||||||
// If you want to output a pointer cast it to void*. Do not implement!
|
|
||||||
template <typename T>
|
|
||||||
BasicArgFormatter &operator<<(const T *value);
|
|
||||||
|
|
||||||
// This method is private to disallow formatting of wide characters.
|
|
||||||
// If you want to output a wide character cast it to integer type.
|
|
||||||
// Do not implement!
|
|
||||||
BasicArgFormatter &operator<<(wchar_t value);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
mutable Formatter *formatter_;
|
mutable Formatter *formatter_;
|
||||||
|
|
||||||
@ -253,6 +283,12 @@ class BasicArgFormatter {
|
|||||||
explicit BasicArgFormatter(Formatter &f) : formatter_(&f) {}
|
explicit BasicArgFormatter(Formatter &f) : formatter_(&f) {}
|
||||||
~BasicArgFormatter();
|
~BasicArgFormatter();
|
||||||
|
|
||||||
|
BasicArgFormatter &operator<<(const Formatter::Arg &arg) {
|
||||||
|
arg.formatter = &formatter_;
|
||||||
|
formatter_->Add(arg);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
friend const char *c_str(const BasicArgFormatter &af) {
|
friend const char *c_str(const BasicArgFormatter &af) {
|
||||||
return af.FinishFormatting()->c_str();
|
return af.FinishFormatting()->c_str();
|
||||||
}
|
}
|
||||||
@ -260,68 +296,6 @@ class BasicArgFormatter {
|
|||||||
friend std::string str(const BasicArgFormatter &af) {
|
friend std::string str(const BasicArgFormatter &af) {
|
||||||
return af.FinishFormatting()->c_str();
|
return af.FinishFormatting()->c_str();
|
||||||
}
|
}
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(int value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(unsigned value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(long value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(unsigned long value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(double value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(long double value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(char value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(const char *value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(const std::string &value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value.c_str(), value.size()));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
BasicArgFormatter &operator<<(const void *value) {
|
|
||||||
formatter_->Add(Formatter::Arg(value));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
BasicArgFormatter &operator<<(T *value) {
|
|
||||||
const T *const_value = value;
|
|
||||||
return *this << const_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
BasicArgFormatter &operator<<(const T &value) {
|
|
||||||
formatter_->Add(Formatter::Arg(&value, &Formatter::FormatCustomArg<T>));
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Callback>
|
template <typename Callback>
|
||||||
|
Loading…
Reference in New Issue
Block a user