Commit 6312748c authored by gabime's avatar gabime

updated bundled fmt to version 1fb0586b065c4202e976528a6bdc6384dc56dc04

parent 87d79eb9
...@@ -25,9 +25,9 @@ ...@@ -25,9 +25,9 @@
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
// Commented out by spdlog to use header only // Commented out by spdlog to use header only
// #include "fmt/format.h" // #include "fmt/format.h"
// #include "fmt/printf.h" // #include "fmt/printf.h"
#include <string.h> #include <string.h>
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -7,15 +7,13 @@ ...@@ -7,15 +7,13 @@
For the license information refer to format.h. For the license information refer to format.h.
*/ */
// Commented out by spdlog to use header only // Commented out by spdlog to use header only
// #include "fmt/ostream.h" // #include "fmt/ostream.h"
// #include "fmt/printf.h"
namespace fmt { namespace fmt {
namespace { namespace internal {
// Write the content of w to os. FMT_FUNC void write(std::ostream &os, Writer &w) {
void write(std::ostream &os, Writer &w) {
const char *data = w.data(); const char *data = w.data();
typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize; typedef internal::MakeUnsigned<std::streamsize>::Type UnsignedStreamSize;
UnsignedStreamSize size = w.size(); UnsignedStreamSize size = w.size();
...@@ -33,13 +31,6 @@ void write(std::ostream &os, Writer &w) { ...@@ -33,13 +31,6 @@ void write(std::ostream &os, Writer &w) {
FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) { FMT_FUNC void print(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w; MemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
write(os, w); internal::write(os, w);
}
FMT_FUNC int fprintf(std::ostream &os, CStringRef format, ArgList args) {
MemoryWriter w;
printf(w, format, args);
write(os, w);
return static_cast<int>(w.size());
} }
} // namespace fmt } // namespace fmt
...@@ -14,85 +14,77 @@ ...@@ -14,85 +14,77 @@
// #include "fmt/format.h" // #include "fmt/format.h"
#include <ostream> #include <ostream>
namespace fmt namespace fmt {
{
namespace internal namespace internal {
{
template <class Char> template <class Char>
class FormatBuf : public std::basic_streambuf<Char> class FormatBuf : public std::basic_streambuf<Char> {
{ private:
private: typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::int_type int_type; typedef typename std::basic_streambuf<Char>::traits_type traits_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type;
Buffer<Char> &buffer_;
Buffer<Char> &buffer_; Char *start_;
Char *start_;
public:
public: FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) {
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer), start_(&buffer[0]) this->setp(start_, start_ + buffer_.capacity());
{ }
this->setp(start_, start_ + buffer_.capacity());
int_type overflow(int_type ch = traits_type::eof()) {
if (!traits_type::eq_int_type(ch, traits_type::eof())) {
size_t buf_size = size();
buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2);
start_ = &buffer_[0];
start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
} }
return ch;
}
int_type overflow(int_type ch = traits_type::eof()) size_t size() const {
{ return to_unsigned(this->pptr() - start_);
if (!traits_type::eq_int_type(ch, traits_type::eof())) }
{
size_t buf_size = size();
buffer_.resize(buf_size);
buffer_.reserve(buf_size * 2);
start_ = &buffer_[0];
start_[buf_size] = traits_type::to_char_type(ch);
this->setp(start_+ buf_size + 1, start_ + buf_size * 2);
}
return ch;
}
size_t size() const
{
return to_unsigned(this->pptr() - start_);
}
}; };
Yes &convert(std::ostream &); Yes &convert(std::ostream &);
struct DummyStream : std::ostream struct DummyStream : std::ostream {
{ DummyStream(); // Suppress a bogus warning in MSVC.
DummyStream(); // Suppress a bogus warning in MSVC. // Hide all operator<< overloads from std::ostream.
// Hide all operator<< overloads from std::ostream. void operator<<(Null<>);
void operator<<(Null<>);
}; };
No &operator<<(std::ostream &, int); No &operator<<(std::ostream &, int);
template<typename T> template<typename T>
struct ConvertToIntImpl<T, true> struct ConvertToIntImpl<T, true> {
{ // Convert to int only if T doesn't have an overloaded operator<<.
// Convert to int only if T doesn't have an overloaded operator<<. enum {
enum value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
{ };
value = sizeof(convert(get<DummyStream>() << get<T>())) == sizeof(No)
};
}; };
// Write the content of w to os.
void write(std::ostream &os, Writer &w);
} // namespace internal } // namespace internal
// Formats a value. // Formats a value.
template <typename Char, typename ArgFormatter, typename T> template <typename Char, typename ArgFormatter, typename T>
void format(BasicFormatter<Char, ArgFormatter> &f, void format_arg(BasicFormatter<Char, ArgFormatter> &f,
const Char *&format_str, const T &value) const Char *&format_str, const T &value) {
{ internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE> buffer;
internal::FormatBuf<Char> format_buf(buffer);
internal::FormatBuf<Char> format_buf(buffer); std::basic_ostream<Char> output(&format_buf);
std::basic_ostream<Char> output(&format_buf); output << value;
output << value;
BasicStringRef<Char> str(&buffer[0], format_buf.size());
BasicStringRef<Char> str(&buffer[0], format_buf.size()); typedef internal::MakeArg< BasicFormatter<Char> > MakeArg;
typedef internal::MakeArg< BasicFormatter<Char> > MakeArg; format_str = f.format(format_str, MakeArg(str));
format_str = f.format(format_str, MakeArg(str));
} }
/** /**
...@@ -106,18 +98,6 @@ void format(BasicFormatter<Char, ArgFormatter> &f, ...@@ -106,18 +98,6 @@ void format(BasicFormatter<Char, ArgFormatter> &f,
*/ */
FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args); FMT_API void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef) FMT_VARIADIC(void, print, std::ostream &, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
FMT_API int fprintf(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
#ifdef FMT_HEADER_ONLY #ifdef FMT_HEADER_ONLY
......
...@@ -13,83 +13,62 @@ ...@@ -13,83 +13,62 @@
#include <algorithm> // std::fill_n #include <algorithm> // std::fill_n
#include <limits> // std::numeric_limits #include <limits> // std::numeric_limits
#include "fmt/format.h" #include "fmt/ostream.h"
namespace fmt namespace fmt {
{ namespace internal {
namespace internal
{
// Checks if a value fits in int - used to avoid warnings about comparing // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers. // signed and unsigned integers.
template <bool IsSigned> template <bool IsSigned>
struct IntChecker struct IntChecker {
{ template <typename T>
template <typename T> static bool fits_in_int(T value) {
static bool fits_in_int(T value) unsigned max = std::numeric_limits<int>::max();
{ return value <= max;
unsigned max = std::numeric_limits<int>::max(); }
return value <= max; static bool fits_in_int(bool) { return true; }
}
static bool fits_in_int(bool)
{
return true;
}
}; };
template <> template <>
struct IntChecker<true> struct IntChecker<true> {
{ template <typename T>
template <typename T> static bool fits_in_int(T value) {
static bool fits_in_int(T value) return value >= std::numeric_limits<int>::min() &&
{ value <= std::numeric_limits<int>::max();
return value >= std::numeric_limits<int>::min() && }
value <= std::numeric_limits<int>::max(); static bool fits_in_int(int) { return true; }
}
static bool fits_in_int(int)
{
return true;
}
}; };
class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> class PrecisionHandler : public ArgVisitor<PrecisionHandler, int> {
{ public:
public: void report_unhandled_arg() {
void report_unhandled_arg() FMT_THROW(FormatError("precision is not integer"));
{ }
FMT_THROW(FormatError("precision is not integer"));
} template <typename T>
int visit_any_int(T value) {
template <typename T> if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
int visit_any_int(T value) FMT_THROW(FormatError("number is too big"));
{ return static_cast<int>(value);
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) }
FMT_THROW(FormatError("number is too big"));
return static_cast<int>(value);
}
}; };
// IsZeroInt::visit(arg) returns true iff arg is a zero integer. // IsZeroInt::visit(arg) returns true iff arg is a zero integer.
class IsZeroInt : public ArgVisitor<IsZeroInt, bool> class IsZeroInt : public ArgVisitor<IsZeroInt, bool> {
{ public:
public: template <typename T>
template <typename T> bool visit_any_int(T value) { return value == 0; }
bool visit_any_int(T value)
{
return value == 0;
}
}; };
template <typename T, typename U> template <typename T, typename U>
struct is_same struct is_same {
{ enum { value = 0 };
enum { value = 0 };
}; };
template <typename T> template <typename T>
struct is_same<T, T> struct is_same<T, T> {
{ enum { value = 1 };
enum { value = 1 };
}; };
// An argument visitor that converts an integer argument to T for printf, // An argument visitor that converts an integer argument to T for printf,
...@@ -97,117 +76,99 @@ struct is_same<T, T> ...@@ -97,117 +76,99 @@ struct is_same<T, T>
// corresponding signed or unsigned type depending on the type specifier: // corresponding signed or unsigned type depending on the type specifier:
// 'd' and 'i' - signed, other - unsigned) // 'd' and 'i' - signed, other - unsigned)
template <typename T = void> template <typename T = void>
class ArgConverter : public ArgVisitor<ArgConverter<T>, void> class ArgConverter : public ArgVisitor<ArgConverter<T>, void> {
{ private:
private: internal::Arg &arg_;
internal::Arg &arg_; wchar_t type_;
wchar_t type_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public:
public: ArgConverter(internal::Arg &arg, wchar_t type)
ArgConverter(internal::Arg &arg, wchar_t type) : arg_(arg), type_(type) {}
: arg_(arg), type_(type) {}
void visit_bool(bool value) {
void visit_bool(bool value) if (type_ != 's')
{ visit_any_int(value);
if (type_ != 's') }
visit_any_int(value);
} template <typename U>
void visit_any_int(U value) {
template <typename U> bool is_signed = type_ == 'd' || type_ == 'i';
void visit_any_int(U value) using internal::Arg;
{ typedef typename internal::Conditional<
bool is_signed = type_ == 'd' || type_ == 'i';
using internal::Arg;
typedef typename internal::Conditional<
is_same<T, void>::value, U, T>::type TargetType; is_same<T, void>::value, U, T>::type TargetType;
if (sizeof(TargetType) <= sizeof(int)) if (sizeof(TargetType) <= sizeof(int)) {
{ // Extra casts are used to silence warnings.
// Extra casts are used to silence warnings. if (is_signed) {
if (is_signed) arg_.type = Arg::INT;
{ arg_.int_value = static_cast<int>(static_cast<TargetType>(value));
arg_.type = Arg::INT; } else {
arg_.int_value = static_cast<int>(static_cast<TargetType>(value)); arg_.type = Arg::UINT;
} typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned;
else arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value));
{ }
arg_.type = Arg::UINT; } else {
typedef typename internal::MakeUnsigned<TargetType>::Type Unsigned; if (is_signed) {
arg_.uint_value = static_cast<unsigned>(static_cast<Unsigned>(value)); arg_.type = Arg::LONG_LONG;
} // glibc's printf doesn't sign extend arguments of smaller types:
} // std::printf("%lld", -42); // prints "4294967254"
else // but we don't have to do the same because it's a UB.
{ arg_.long_long_value = static_cast<LongLong>(value);
if (is_signed) } else {
{ arg_.type = Arg::ULONG_LONG;
arg_.type = Arg::LONG_LONG; arg_.ulong_long_value =
// glibc's printf doesn't sign extend arguments of smaller types: static_cast<typename internal::MakeUnsigned<U>::Type>(value);
// std::printf("%lld", -42); // prints "4294967254" }
// but we don't have to do the same because it's a UB.
arg_.long_long_value = static_cast<LongLong>(value);
}
else
{
arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value =
static_cast<typename internal::MakeUnsigned<U>::Type>(value);
}
}
} }
}
}; };
// Converts an integer argument to char for printf. // Converts an integer argument to char for printf.
class CharConverter : public ArgVisitor<CharConverter, void> class CharConverter : public ArgVisitor<CharConverter, void> {
{ private:
private: internal::Arg &arg_;
internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter); FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public: public:
explicit CharConverter(internal::Arg &arg) : arg_(arg) {} explicit CharConverter(internal::Arg &arg) : arg_(arg) {}
template <typename T> template <typename T>
void visit_any_int(T value) void visit_any_int(T value) {
{ arg_.type = internal::Arg::CHAR;
arg_.type = internal::Arg::CHAR; arg_.int_value = static_cast<char>(value);
arg_.int_value = static_cast<char>(value); }
}
}; };
// Checks if an argument is a valid printf width specifier and sets // Checks if an argument is a valid printf width specifier and sets
// left alignment if it is negative. // left alignment if it is negative.
class WidthHandler : public ArgVisitor<WidthHandler, unsigned> class WidthHandler : public ArgVisitor<WidthHandler, unsigned> {
{ private:
private: FormatSpec &spec_;
FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public:
public: explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
explicit WidthHandler(FormatSpec &spec) : spec_(spec) {}
void report_unhandled_arg() {
void report_unhandled_arg() FMT_THROW(FormatError("width is not integer"));
{ }
FMT_THROW(FormatError("width is not integer"));
} template <typename T>
unsigned visit_any_int(T value) {
template <typename T> typedef typename internal::IntTraits<T>::MainType UnsignedType;
unsigned visit_any_int(T value) UnsignedType width = static_cast<UnsignedType>(value);
{ if (internal::is_negative(value)) {
typedef typename internal::IntTraits<T>::MainType UnsignedType; spec_.align_ = ALIGN_LEFT;
UnsignedType width = static_cast<UnsignedType>(value); width = 0 - width;
if (internal::is_negative(value))
{
spec_.align_ = ALIGN_LEFT;
width = 0 - width;
}
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max)
FMT_THROW(FormatError("number is too big"));
return static_cast<unsigned>(width);
} }
unsigned int_max = std::numeric_limits<int>::max();
if (width > int_max)
FMT_THROW(FormatError("number is too big"));
return static_cast<unsigned>(width);
}
}; };
} // namespace internal } // namespace internal
...@@ -229,343 +190,302 @@ public: ...@@ -229,343 +190,302 @@ public:
\endrst \endrst
*/ */
template <typename Impl, typename Char> template <typename Impl, typename Char>
class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char> class BasicPrintfArgFormatter : public internal::ArgFormatterBase<Impl, Char> {
{ private:
private: void write_null_pointer() {
void write_null_pointer() this->spec().type_ = 0;
{ this->write("(nil)");
this->spec().type_ = 0; }
this->write("(nil)");
} typedef internal::ArgFormatterBase<Impl, Char> Base;
typedef internal::ArgFormatterBase<Impl, Char> Base; public:
/**
public: \rst
/** Constructs an argument formatter object.
\rst *writer* is a reference to the output writer and *spec* contains format
Constructs an argument formatter object. specifier information for standard argument types.
*writer* is a reference to the output writer and *spec* contains format \endrst
specifier information for standard argument types. */
\endrst BasicPrintfArgFormatter(BasicWriter<Char> &writer, FormatSpec &spec)
*/ : internal::ArgFormatterBase<Impl, Char>(writer, spec) {}
BasicPrintfArgFormatter(BasicWriter<Char> &writer, FormatSpec &spec)
: internal::ArgFormatterBase<Impl, Char>(writer, spec) {} /** Formats an argument of type ``bool``. */
void visit_bool(bool value) {
/** Formats an argument of type ``bool``. */ FormatSpec &fmt_spec = this->spec();
void visit_bool(bool value) if (fmt_spec.type_ != 's')
{ return this->visit_any_int(value);
FormatSpec &fmt_spec = this->spec(); fmt_spec.type_ = 0;
if (fmt_spec.type_ != 's') this->write(value);
return this->visit_any_int(value); }
fmt_spec.type_ = 0;
this->write(value); /** Formats a character. */
} void visit_char(int value) {
const FormatSpec &fmt_spec = this->spec();
/** Formats a character. */ BasicWriter<Char> &w = this->writer();
void visit_char(int value) if (fmt_spec.type_ && fmt_spec.type_ != 'c')
{ w.write_int(value, fmt_spec);
const FormatSpec &fmt_spec = this->spec(); typedef typename BasicWriter<Char>::CharPtr CharPtr;
BasicWriter<Char> &w = this->writer(); CharPtr out = CharPtr();
if (fmt_spec.type_ && fmt_spec.type_ != 'c') if (fmt_spec.width_ > 1) {
w.write_int(value, fmt_spec); Char fill = ' ';
typedef typename BasicWriter<Char>::CharPtr CharPtr; out = w.grow_buffer(fmt_spec.width_);
CharPtr out = CharPtr(); if (fmt_spec.align_ != ALIGN_LEFT) {
if (fmt_spec.width_ > 1) std::fill_n(out, fmt_spec.width_ - 1, fill);
{ out += fmt_spec.width_ - 1;
Char fill = ' '; } else {
out = w.grow_buffer(fmt_spec.width_); std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
if (fmt_spec.align_ != ALIGN_LEFT) }
{ } else {
std::fill_n(out, fmt_spec.width_ - 1, fill); out = w.grow_buffer(1);
out += fmt_spec.width_ - 1;
}
else
{
std::fill_n(out + 1, fmt_spec.width_ - 1, fill);
}
}
else
{
out = w.grow_buffer(1);
}
*out = static_cast<Char>(value);
}
/** Formats a null-terminated C string. */
void visit_cstring(const char *value)
{
if (value)
Base::visit_cstring(value);
else if (this->spec().type_ == 'p')
write_null_pointer();
else
this->write("(null)");
}
/** Formats a pointer. */
void visit_pointer(const void *value)
{
if (value)
return Base::visit_pointer(value);
this->spec().type_ = 0;
write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c)
{
BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0};
const Char *format = format_str;
c.format(&formatter, c.value, &format);
} }
*out = static_cast<Char>(value);
}
/** Formats a null-terminated C string. */
void visit_cstring(const char *value) {
if (value)
Base::visit_cstring(value);
else if (this->spec().type_ == 'p')
write_null_pointer();
else
this->write("(null)");
}
/** Formats a pointer. */
void visit_pointer(const void *value) {
if (value)
return Base::visit_pointer(value);
this->spec().type_ = 0;
write_null_pointer();
}
/** Formats an argument of a custom (user-defined) type. */
void visit_custom(internal::Arg::CustomValue c) {
BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0};
const Char *format = format_str;
c.format(&formatter, c.value, &format);
}
}; };
/** The default printf argument formatter. */ /** The default printf argument formatter. */
template <typename Char> template <typename Char>
class PrintfArgFormatter class PrintfArgFormatter
: public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> : public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char> {
{ public:
public: /** Constructs an argument formatter object. */
/** Constructs an argument formatter object. */ PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s)
PrintfArgFormatter(BasicWriter<Char> &w, FormatSpec &s) : BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char>(w, s) {}
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> > template <typename Char, typename ArgFormatter = PrintfArgFormatter<Char> >
class PrintfFormatter : private internal::FormatterBase class PrintfFormatter : private internal::FormatterBase {
{ private:
private: BasicWriter<Char> &writer_;
BasicWriter<Char> &writer_;
void parse_flags(FormatSpec &spec, const Char *&s);
void parse_flags(FormatSpec &spec, const Char *&s);
// Returns the argument with specified index or, if arg_index is equal
// Returns the argument with specified index or, if arg_index is equal // to the maximum unsigned value, the next argument.
// to the maximum unsigned value, the next argument. internal::Arg get_arg(
internal::Arg get_arg( const Char *s,
const Char *s, unsigned arg_index = (std::numeric_limits<unsigned>::max)());
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index.
// Parses argument index, flags and width and returns the argument index. unsigned parse_header(const Char *&s, FormatSpec &spec);
unsigned parse_header(const Char *&s, FormatSpec &spec);
public:
public: /**
/** \rst
\rst Constructs a ``PrintfFormatter`` object. References to the arguments and
Constructs a ``PrintfFormatter`` object. References to the arguments and the writer are stored in the formatter object so make sure they have
the writer are stored in the formatter object so make sure they have appropriate lifetimes.
appropriate lifetimes. \endrst
\endrst */
*/ explicit PrintfFormatter(const ArgList &args, BasicWriter<Char> &w)
explicit PrintfFormatter(const ArgList &args, BasicWriter<Char> &w) : FormatterBase(args), writer_(w) {}
: FormatterBase(args), writer_(w) {}
/** Formats stored arguments and writes the output to the writer. */
/** Formats stored arguments and writes the output to the writer. */ FMT_API void format(BasicCStringRef<Char> format_str);
FMT_API void format(BasicCStringRef<Char> format_str);
}; };
template <typename Char, typename AF> template <typename Char, typename AF>
void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) void PrintfFormatter<Char, AF>::parse_flags(FormatSpec &spec, const Char *&s) {
{ for (;;) {
for (;;) switch (*s++) {
{ case '-':
switch (*s++) spec.align_ = ALIGN_LEFT;
{ break;
case '-': case '+':
spec.align_ = ALIGN_LEFT; spec.flags_ |= SIGN_FLAG | PLUS_FLAG;
break; break;
case '+': case '0':
spec.flags_ |= SIGN_FLAG | PLUS_FLAG; spec.fill_ = '0';
break; break;
case '0': case ' ':
spec.fill_ = '0'; spec.flags_ |= SIGN_FLAG;
break; break;
case ' ': case '#':
spec.flags_ |= SIGN_FLAG; spec.flags_ |= HASH_FLAG;
break; break;
case '#': default:
spec.flags_ |= HASH_FLAG; --s;
break; return;
default:
--s;
return;
}
} }
}
} }
template <typename Char, typename AF> template <typename Char, typename AF>
internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s, internal::Arg PrintfFormatter<Char, AF>::get_arg(const Char *s,
unsigned arg_index) unsigned arg_index) {
{ (void)s;
(void)s; const char *error = 0;
const char *error = 0; internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ?
internal::Arg arg = arg_index == std::numeric_limits<unsigned>::max() ? next_arg(error) : FormatterBase::get_arg(arg_index - 1, error);
next_arg(error) : FormatterBase::get_arg(arg_index - 1, error); if (error)
if (error) FMT_THROW(FormatError(!*s ? "invalid format string" : error));
FMT_THROW(FormatError(!*s ? "invalid format string" : error)); return arg;
return arg;
} }
template <typename Char, typename AF> template <typename Char, typename AF>
unsigned PrintfFormatter<Char, AF>::parse_header( unsigned PrintfFormatter<Char, AF>::parse_header(
const Char *&s, FormatSpec &spec) const Char *&s, FormatSpec &spec) {
{ unsigned arg_index = std::numeric_limits<unsigned>::max();
unsigned arg_index = std::numeric_limits<unsigned>::max(); Char c = *s;
Char c = *s; if (c >= '0' && c <= '9') {
if (c >= '0' && c <= '9') // Parse an argument index (if followed by '$') or a width possibly
{ // preceded with '0' flag(s).
// Parse an argument index (if followed by '$') or a width possibly unsigned value = internal::parse_nonnegative_int(s);
// preceded with '0' flag(s). if (*s == '$') { // value is an argument index
unsigned value = internal::parse_nonnegative_int(s); ++s;
if (*s == '$') // value is an argument index arg_index = value;
{ } else {
++s; if (c == '0')
arg_index = value; spec.fill_ = '0';
} if (value != 0) {
else // Nonzero value means that we parsed width and don't need to
{ // parse it or flags again, so return now.
if (c == '0') spec.width_ = value;
spec.fill_ = '0'; return arg_index;
if (value != 0) }
{
// Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now.
spec.width_ = value;
return arg_index;
}
}
} }
parse_flags(spec, s); }
// Parse width. parse_flags(spec, s);
if (*s >= '0' && *s <= '9') // Parse width.
{ if (*s >= '0' && *s <= '9') {
spec.width_ = internal::parse_nonnegative_int(s); spec.width_ = internal::parse_nonnegative_int(s);
} else if (*s == '*') {
++s;
spec.width_ = internal::WidthHandler(spec).visit(get_arg(s));
}
return arg_index;
}
template <typename Char, typename AF>
void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) {
const Char *start = format_str.c_str();
const Char *s = start;
while (*s) {
Char c = *s++;
if (c != '%') continue;
if (*s == c) {
write(writer_, start, s);
start = ++s;
continue;
} }
else if (*s == '*') write(writer_, start, s - 1);
{
FormatSpec spec;
spec.align_ = ALIGN_RIGHT;
// Parse argument index, flags and width.
unsigned arg_index = parse_header(s, spec);
// Parse precision.
if (*s == '.') {
++s;
if ('0' <= *s && *s <= '9') {
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s));
} else if (*s == '*') {
++s; ++s;
spec.width_ = internal::WidthHandler(spec).visit(get_arg(s)); spec.precision_ = internal::PrecisionHandler().visit(get_arg(s));
}
} }
return arg_index;
}
template <typename Char, typename AF> using internal::Arg;
void PrintfFormatter<Char, AF>::format(BasicCStringRef<Char> format_str) Arg arg = get_arg(s, arg_index);
{ if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg))
const Char *start = format_str.c_str(); spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
const Char *s = start; if (spec.fill_ == '0') {
while (*s) if (arg.type <= Arg::LAST_NUMERIC_TYPE)
{ spec.align_ = ALIGN_NUMERIC;
Char c = *s++; else
if (c != '%') continue; spec.fill_ = ' '; // Ignore '0' flag for non-numeric types.
if (*s == c) }
{
write(writer_, start, s); // Parse length and convert the argument to the required type.
start = ++s; using internal::ArgConverter;
continue; switch (*s++) {
} case 'h':
write(writer_, start, s - 1); if (*s == 'h')
ArgConverter<signed char>(arg, *++s).visit(arg);
FormatSpec spec; else
spec.align_ = ALIGN_RIGHT; ArgConverter<short>(arg, *s).visit(arg);
break;
// Parse argument index, flags and width. case 'l':
unsigned arg_index = parse_header(s, spec); if (*s == 'l')
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
// Parse precision. else
if (*s == '.') ArgConverter<long>(arg, *s).visit(arg);
{ break;
++s; case 'j':
if ('0' <= *s && *s <= '9') ArgConverter<intmax_t>(arg, *s).visit(arg);
{ break;
spec.precision_ = static_cast<int>(internal::parse_nonnegative_int(s)); case 'z':
} ArgConverter<std::size_t>(arg, *s).visit(arg);
else if (*s == '*') break;
{ case 't':
++s; ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
spec.precision_ = internal::PrecisionHandler().visit(get_arg(s)); break;
} case 'L':
} // printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
using internal::Arg; break;
Arg arg = get_arg(s, arg_index); default:
if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) --s;
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); ArgConverter<void>(arg, *s).visit(arg);
if (spec.fill_ == '0') }
{
if (arg.type <= Arg::LAST_NUMERIC_TYPE) // Parse type.
spec.align_ = ALIGN_NUMERIC; if (!*s)
else FMT_THROW(FormatError("invalid format string"));
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. spec.type_ = static_cast<char>(*s++);
} if (arg.type <= Arg::LAST_INTEGER_TYPE) {
// Normalize type.
// Parse length and convert the argument to the required type. switch (spec.type_) {
using internal::ArgConverter; case 'i': case 'u':
switch (*s++) spec.type_ = 'd';
{ break;
case 'h': case 'c':
if (*s == 'h') // TODO: handle wchar_t
ArgConverter<signed char>(arg, *++s).visit(arg); internal::CharConverter(arg).visit(arg);
else break;
ArgConverter<short>(arg, *s).visit(arg); }
break;
case 'l':
if (*s == 'l')
ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
else
ArgConverter<long>(arg, *s).visit(arg);
break;
case 'j':
ArgConverter<intmax_t>(arg, *s).visit(arg);
break;
case 'z':
ArgConverter<std::size_t>(arg, *s).visit(arg);
break;
case 't':
ArgConverter<std::ptrdiff_t>(arg, *s).visit(arg);
break;
case 'L':
// printf produces garbage when 'L' is omitted for long double, no
// need to do the same.
break;
default:
--s;
ArgConverter<void>(arg, *s).visit(arg);
}
// Parse type.
if (!*s)
FMT_THROW(FormatError("invalid format string"));
spec.type_ = static_cast<char>(*s++);
if (arg.type <= Arg::LAST_INTEGER_TYPE)
{
// Normalize type.
switch (spec.type_)
{
case 'i':
case 'u':
spec.type_ = 'd';
break;
case 'c':
// TODO: handle wchar_t
internal::CharConverter(arg).visit(arg);
break;
}
}
start = s;
// Format argument.
AF(writer_, spec).visit(arg);
} }
write(writer_, start, s);
start = s;
// Format argument.
AF(writer_, spec).visit(arg);
}
write(writer_, start, s);
} }
template <typename Char> template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
{ PrintfFormatter<Char>(args, w).format(format);
PrintfFormatter<Char>(args, w).format(format);
} }
/** /**
...@@ -577,19 +497,17 @@ void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) ...@@ -577,19 +497,17 @@ void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args)
std::string message = fmt::sprintf("The answer is %d", 42); std::string message = fmt::sprintf("The answer is %d", 42);
\endrst \endrst
*/ */
inline std::string sprintf(CStringRef format, ArgList args) inline std::string sprintf(CStringRef format, ArgList args) {
{ MemoryWriter w;
MemoryWriter w; printf(w, format, args);
printf(w, format, args); return w.str();
return w.str();
} }
FMT_VARIADIC(std::string, sprintf, CStringRef) FMT_VARIADIC(std::string, sprintf, CStringRef)
inline std::wstring sprintf(WCStringRef format, ArgList args) inline std::wstring sprintf(WCStringRef format, ArgList args) {
{ WMemoryWriter w;
WMemoryWriter w; printf(w, format, args);
printf(w, format, args); return w.str();
return w.str();
} }
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef) FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
...@@ -614,11 +532,27 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) ...@@ -614,11 +532,27 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
fmt::printf("Elapsed time: %.2f seconds", 1.23); fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst \endrst
*/ */
inline int printf(CStringRef format, ArgList args) inline int printf(CStringRef format, ArgList args) {
{ return fprintf(stdout, format, args);
return fprintf(stdout, format, args);
} }
FMT_VARIADIC(int, printf, CStringRef) FMT_VARIADIC(int, printf, CStringRef)
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
fprintf(cerr, "Don't %s!", "panic");
\endrst
*/
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
MemoryWriter w;
printf(w, format_str, args);
internal::write(os, w);
return static_cast<int>(w.size());
}
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
#endif // FMT_PRINTF_H_ #endif // FMT_PRINTF_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