Commit 3826ac14 authored by gabime's avatar gabime

bumped bundled fmt version to 4.1.0

parent d650fa24
...@@ -72,9 +72,11 @@ ...@@ -72,9 +72,11 @@
// Dummy implementations of strerror_r and strerror_s called if corresponding // Dummy implementations of strerror_r and strerror_s called if corresponding
// system functions are not available. // system functions are not available.
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_r(int, char *, ...) { static inline fmt::internal::Null<> strerror_r(int, char *, ...) {
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
FMT_MAYBE_UNUSED
static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) { static inline fmt::internal::Null<> strerror_s(char *, std::size_t, ...) {
return fmt::internal::Null<>(); return fmt::internal::Null<>();
} }
...@@ -121,7 +123,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef); ...@@ -121,7 +123,7 @@ typedef void (*FormatFunc)(Writer &, int, StringRef);
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
int safe_strerror( int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT { int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT {
FMT_ASSERT(buffer != 0 && buffer_size != 0, "invalid buffer"); FMT_ASSERT(buffer != FMT_NULL && buffer_size != 0, "invalid buffer");
class StrError { class StrError {
private: private:
...@@ -159,6 +161,11 @@ int safe_strerror( ...@@ -159,6 +161,11 @@ int safe_strerror(
ERANGE : result; ERANGE : result;
} }
#ifdef __c2__
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
// Fallback to strerror if strerror_r and strerror_s are not available. // Fallback to strerror if strerror_r and strerror_s are not available.
int fallback(internal::Null<>) { int fallback(internal::Null<>) {
errno = 0; errno = 0;
...@@ -166,13 +173,15 @@ int safe_strerror( ...@@ -166,13 +173,15 @@ int safe_strerror(
return errno; return errno;
} }
#ifdef __c2__
# pragma clang diagnostic pop
#endif
public: public:
StrError(int err_code, char *&buf, std::size_t buf_size) StrError(int err_code, char *&buf, std::size_t buf_size)
: error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {} : error_code_(err_code), buffer_(buf), buffer_size_(buf_size) {}
int run() { int run() {
// Suppress a warning about unused strerror_r.
strerror_r(0, FMT_NULL, "");
return handle(strerror_r(error_code_, buffer_, buffer_size_)); return handle(strerror_r(error_code_, buffer_, buffer_size_));
} }
}; };
...@@ -396,51 +405,6 @@ FMT_FUNC void format_system_error( ...@@ -396,51 +405,6 @@ FMT_FUNC void format_system_error(
fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32. fmt::format_error_code(out, error_code, message); // 'fmt::' is for bcc32.
} }
template <typename Char>
void internal::ArgMap<Char>::init(const ArgList &args) {
if (!map_.empty())
return;
typedef internal::NamedArg<Char> NamedArg;
const NamedArg *named_arg = FMT_NULL;
bool use_values =
args.type(ArgList::MAX_PACKED_ARGS - 1) == internal::Arg::NONE;
if (use_values) {
for (unsigned i = 0;/*nothing*/; ++i) {
internal::Arg::Type arg_type = args.type(i);
switch (arg_type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.values_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
return;
}
for (unsigned i = 0; i != ArgList::MAX_PACKED_ARGS; ++i) {
internal::Arg::Type arg_type = args.type(i);
if (arg_type == internal::Arg::NAMED_ARG) {
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
}
}
for (unsigned i = ArgList::MAX_PACKED_ARGS;/*nothing*/; ++i) {
switch (args.args_[i].type) {
case internal::Arg::NONE:
return;
case internal::Arg::NAMED_ARG:
named_arg = static_cast<const NamedArg*>(args.args_[i].pointer);
map_.push_back(Pair(named_arg->name, *named_arg));
break;
default:
/*nothing*/;
}
}
}
template <typename Char> template <typename Char>
void internal::FixedBuffer<Char>::grow(std::size_t) { void internal::FixedBuffer<Char>::grow(std::size_t) {
FMT_THROW(std::runtime_error("buffer overflow")); FMT_THROW(std::runtime_error("buffer overflow"));
...@@ -502,8 +466,6 @@ template struct internal::BasicData<void>; ...@@ -502,8 +466,6 @@ template struct internal::BasicData<void>;
template void internal::FixedBuffer<char>::grow(std::size_t); template void internal::FixedBuffer<char>::grow(std::size_t);
template void internal::ArgMap<char>::init(const ArgList &args);
template FMT_API int internal::CharTraits<char>::format_float( template FMT_API int internal::CharTraits<char>::format_float(
char *buffer, std::size_t size, const char *format, char *buffer, std::size_t size, const char *format,
unsigned width, int precision, double value); unsigned width, int precision, double value);
...@@ -516,8 +478,6 @@ template FMT_API int internal::CharTraits<char>::format_float( ...@@ -516,8 +478,6 @@ template FMT_API int internal::CharTraits<char>::format_float(
template void internal::FixedBuffer<wchar_t>::grow(std::size_t); template void internal::FixedBuffer<wchar_t>::grow(std::size_t);
template void internal::ArgMap<wchar_t>::init(const ArgList &args);
template FMT_API int internal::CharTraits<wchar_t>::format_float( template FMT_API int internal::CharTraits<wchar_t>::format_float(
wchar_t *buffer, std::size_t size, const wchar_t *format, wchar_t *buffer, std::size_t size, const wchar_t *format,
unsigned width, int precision, double value); unsigned width, int precision, double value);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -13,65 +13,59 @@ ...@@ -13,65 +13,59 @@
#include "format.h" #include "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_;
public:
public: FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
FormatBuf(Buffer<Char> &buffer) : buffer_(buffer) {}
protected:
protected: // The put-area is actually always empty. This makes the implementation
// The put-area is actually always empty. This makes the implementation // simpler and has the advantage that the streambuf and the buffer are always
// simpler and has the advantage that the streambuf and the buffer are always // in sync and sputc never writes into uninitialized memory. The obvious
// in sync and sputc never writes into uninitialized memory. The obvious // disadvantage is that each call to sputc always results in a (virtual) call
// disadvantage is that each call to sputc always results in a (virtual) call // to overflow. There is no disadvantage here for sputn since this always
// to overflow. There is no disadvantage here for sputn since this always // results in a call to xsputn.
// results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE if (!traits_type::eq_int_type(ch, traits_type::eof()))
{ buffer_.push_back(static_cast<Char>(ch));
if (!traits_type::eq_int_type(ch, traits_type::eof())) return ch;
buffer_.push_back(static_cast<Char>(ch)); }
return ch;
} std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
buffer_.append(s, s + count);
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE return count;
{ }
buffer_.append(s, s + count);
return count;
}
}; };
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<>); template <typename T>
typename EnableIf<sizeof(T) == 0>::type operator<<(const T &);
}; };
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. // Write the content of w to os.
...@@ -81,17 +75,17 @@ FMT_API void write(std::ostream &os, Writer &w); ...@@ -81,17 +75,17 @@ FMT_API void write(std::ostream &os, Writer &w);
// Formats a value. // Formats a value.
template <typename Char, typename ArgFormatter_, typename T> template <typename Char, typename ArgFormatter_, typename T>
void format_arg(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.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value;
BasicStringRef<Char> str(&buffer[0], buffer.size()); BasicStringRef<Char> str(&buffer[0], buffer.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));
} }
/** /**
......
...@@ -64,134 +64,112 @@ ...@@ -64,134 +64,112 @@
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
namespace fmt namespace fmt {
{
// An error code. // An error code.
class ErrorCode class ErrorCode {
{ private:
private: int value_;
int value_;
public: public:
explicit ErrorCode(int value = 0) FMT_NOEXCEPT : explicit ErrorCode(int value = 0) FMT_NOEXCEPT : value_(value) {}
value_(value) {}
int get() const FMT_NOEXCEPT int get() const FMT_NOEXCEPT { return value_; }
{
return value_;
}
}; };
// A buffered file. // A buffered file.
class BufferedFile class BufferedFile {
{ private:
private: FILE *file_;
FILE *file_;
friend class File; friend class File;
explicit BufferedFile(FILE *f) : file_(f) {} explicit BufferedFile(FILE *f) : file_(f) {}
public: public:
// Constructs a BufferedFile object which doesn't represent any file. // Constructs a BufferedFile object which doesn't represent any file.
BufferedFile() FMT_NOEXCEPT : BufferedFile() FMT_NOEXCEPT : file_(FMT_NULL) {}
file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
FMT_API ~BufferedFile() FMT_NOEXCEPT; FMT_API ~BufferedFile() FMT_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
// references are not supported. // references are not supported.
private: private:
// A proxy object to emulate a move constructor. // A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly. // It is private to make it impossible call operator Proxy directly.
struct Proxy struct Proxy {
{ FILE *file;
FILE *file; };
};
public: public:
// A "move constructor" for moving from a temporary. // A "move constructor" for moving from a temporary.
BufferedFile(Proxy p) FMT_NOEXCEPT : BufferedFile(Proxy p) FMT_NOEXCEPT : file_(p.file) {}
file_(p.file) {}
// A "move constructor" for moving from an lvalue.
// A "move constructor" for moving from an lvalue. BufferedFile(BufferedFile &f) FMT_NOEXCEPT : file_(f.file_) {
BufferedFile(BufferedFile &f) FMT_NOEXCEPT : f.file_ = FMT_NULL;
file_(f.file_) }
{
f.file_ = FMT_NULL; // A "move assignment operator" for moving from a temporary.
} BufferedFile &operator=(Proxy p) {
close();
// A "move assignment operator" for moving from a temporary. file_ = p.file;
BufferedFile &operator=(Proxy p) return *this;
{ }
close();
file_ = p.file; // A "move assignment operator" for moving from an lvalue.
return *this; BufferedFile &operator=(BufferedFile &other) {
} close();
file_ = other.file_;
// A "move assignment operator" for moving from an lvalue. other.file_ = FMT_NULL;
BufferedFile &operator=(BufferedFile &other) return *this;
{ }
close();
file_ = other.file_; // Returns a proxy object for moving from a temporary:
other.file_ = FMT_NULL; // BufferedFile file = BufferedFile(...);
return *this; operator Proxy() FMT_NOEXCEPT {
} Proxy p = {file_};
file_ = FMT_NULL;
// Returns a proxy object for moving from a temporary: return p;
// BufferedFile file = BufferedFile(...); }
operator Proxy() FMT_NOEXCEPT
{
Proxy p = {file_};
file_ = FMT_NULL;
return p;
}
#else #else
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile); FMT_DISALLOW_COPY_AND_ASSIGN(BufferedFile);
public: public:
BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : file_(other.file_) {
file_(other.file_) other.file_ = FMT_NULL;
{ }
other.file_ = FMT_NULL;
} BufferedFile& operator=(BufferedFile &&other) {
close();
BufferedFile& operator=(BufferedFile &&other) file_ = other.file_;
{ other.file_ = FMT_NULL;
close(); return *this;
file_ = other.file_; }
other.file_ = FMT_NULL;
return *this;
}
#endif #endif
// Opens a file. // Opens a file.
FMT_API BufferedFile(CStringRef filename, CStringRef mode); FMT_API BufferedFile(CStringRef filename, CStringRef mode);
// Closes the file. // Closes the file.
FMT_API void close(); FMT_API void close();
// Returns the pointer to a FILE object representing this file. // Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT FILE *get() const FMT_NOEXCEPT { return file_; }
{
return file_;
}
// We place parentheses around fileno to workaround a bug in some versions // We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro. // of MinGW that define fileno as a macro.
FMT_API int (fileno)() const; FMT_API int (fileno)() const;
void print(CStringRef format_str, const ArgList &args) void print(CStringRef format_str, const ArgList &args) {
{ fmt::print(file_, format_str, args);
fmt::print(file_, format_str, args); }
} FMT_VARIADIC(void, print, CStringRef)
FMT_VARIADIC(void, print, CStringRef)
}; };
// A file. Closed file is represented by a File object with descriptor -1. // A file. Closed file is represented by a File object with descriptor -1.
...@@ -200,141 +178,125 @@ BufferedFile(BufferedFile &&other) FMT_NOEXCEPT : ...@@ -200,141 +178,125 @@ BufferedFile(BufferedFile &&other) FMT_NOEXCEPT :
// closing the file multiple times will cause a crash on Windows rather // closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the // than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler. // invalid parameter handler with _set_invalid_parameter_handler.
class File class File {
{ private:
private: int fd_; // File descriptor.
int fd_; // File descriptor.
// Constructs a File object with a given descriptor. // Constructs a File object with a given descriptor.
explicit File(int fd) : fd_(fd) {} explicit File(int fd) : fd_(fd) {}
public: public:
// Possible values for the oflag argument to the constructor. // Possible values for the oflag argument to the constructor.
enum enum {
{ RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. };
};
// Constructs a File object which doesn't represent any file. // Constructs a File object which doesn't represent any file.
File() FMT_NOEXCEPT : File() FMT_NOEXCEPT : fd_(-1) {}
fd_(-1) {}
// Opens a file and constructs a File object representing this file. // Opens a file and constructs a File object representing this file.
FMT_API File(CStringRef path, int oflag); FMT_API File(CStringRef path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
// Emulate a move constructor and a move assignment operator if rvalue // Emulate a move constructor and a move assignment operator if rvalue
// references are not supported. // references are not supported.
private: private:
// A proxy object to emulate a move constructor. // A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly. // It is private to make it impossible call operator Proxy directly.
struct Proxy struct Proxy {
{ int fd;
int fd; };
};
public:
public: // A "move constructor" for moving from a temporary.
// A "move constructor" for moving from a temporary. File(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
File(Proxy p) FMT_NOEXCEPT :
fd_(p.fd) {} // A "move constructor" for moving from an lvalue.
File(File &other) FMT_NOEXCEPT : fd_(other.fd_) {
// A "move constructor" for moving from an lvalue. other.fd_ = -1;
File(File &other) FMT_NOEXCEPT : }
fd_(other.fd_)
{ // A "move assignment operator" for moving from a temporary.
other.fd_ = -1; File &operator=(Proxy p) {
} close();
fd_ = p.fd;
// A "move assignment operator" for moving from a temporary. return *this;
File &operator=(Proxy p) }
{
close(); // A "move assignment operator" for moving from an lvalue.
fd_ = p.fd; File &operator=(File &other) {
return *this; close();
} fd_ = other.fd_;
other.fd_ = -1;
// A "move assignment operator" for moving from an lvalue. return *this;
File &operator=(File &other) }
{
close(); // Returns a proxy object for moving from a temporary:
fd_ = other.fd_; // File file = File(...);
other.fd_ = -1; operator Proxy() FMT_NOEXCEPT {
return *this; Proxy p = {fd_};
} fd_ = -1;
return p;
// Returns a proxy object for moving from a temporary: }
// File file = File(...);
operator Proxy() FMT_NOEXCEPT
{
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else #else
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(File); FMT_DISALLOW_COPY_AND_ASSIGN(File);
public: public:
File(File &&other) FMT_NOEXCEPT : File(File &&other) FMT_NOEXCEPT : fd_(other.fd_) {
fd_(other.fd_) other.fd_ = -1;
{ }
other.fd_ = -1;
} File& operator=(File &&other) {
close();
File& operator=(File &&other) fd_ = other.fd_;
{ other.fd_ = -1;
close(); return *this;
fd_ = other.fd_; }
other.fd_ = -1;
return *this;
}
#endif #endif
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
FMT_API ~File() FMT_NOEXCEPT; FMT_API ~File() FMT_NOEXCEPT;
// Returns the file descriptor. // Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT int descriptor() const FMT_NOEXCEPT { return fd_; }
{
return fd_;
}
// Closes the file. // Closes the file.
FMT_API void close(); FMT_API void close();
// Returns the file size. The size has signed type for consistency with // Returns the file size. The size has signed type for consistency with
// stat::st_size. // stat::st_size.
FMT_API LongLong size() const; FMT_API LongLong size() const;
// Attempts to read count bytes from the file into the specified buffer. // Attempts to read count bytes from the file into the specified buffer.
FMT_API std::size_t read(void *buffer, std::size_t count); FMT_API std::size_t read(void *buffer, std::size_t count);
// Attempts to write count bytes from the specified buffer to the file. // Attempts to write count bytes from the specified buffer to the file.
FMT_API std::size_t write(const void *buffer, std::size_t count); FMT_API std::size_t write(const void *buffer, std::size_t count);
// Duplicates a file descriptor with the dup function and returns // Duplicates a file descriptor with the dup function and returns
// the duplicate as a file object. // the duplicate as a file object.
FMT_API static File dup(int fd); FMT_API static File dup(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if // Makes fd be the copy of this file descriptor, closing fd first if
// necessary. // necessary.
FMT_API void dup2(int fd); FMT_API void dup2(int fd);
// Makes fd be the copy of this file descriptor, closing fd first if // Makes fd be the copy of this file descriptor, closing fd first if
// necessary. // necessary.
FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT; FMT_API void dup2(int fd, ErrorCode &ec) FMT_NOEXCEPT;
// Creates a pipe setting up read_end and write_end file objects for reading // Creates a pipe setting up read_end and write_end file objects for reading
// and writing respectively. // and writing respectively.
FMT_API static void pipe(File &read_end, File &write_end); FMT_API static void pipe(File &read_end, File &write_end);
// Creates a BufferedFile object associated with this file and detaches // Creates a BufferedFile object associated with this file and detaches
// this File object from the file. // this File object from the file.
FMT_API BufferedFile fdopen(const char *mode); FMT_API BufferedFile fdopen(const char *mode);
}; };
// Returns the memory page size. // Returns the memory page size.
...@@ -347,77 +309,58 @@ long getpagesize(); ...@@ -347,77 +309,58 @@ long getpagesize();
#ifdef FMT_LOCALE #ifdef FMT_LOCALE
// A "C" numeric locale. // A "C" numeric locale.
class Locale class Locale {
{ private:
private:
# ifdef _MSC_VER # ifdef _MSC_VER
typedef _locale_t locale_t; typedef _locale_t locale_t;
enum { LC_NUMERIC_MASK = LC_NUMERIC }; enum { LC_NUMERIC_MASK = LC_NUMERIC };
static locale_t newlocale(int category_mask, const char *locale, locale_t) static locale_t newlocale(int category_mask, const char *locale, locale_t) {
{ return _create_locale(category_mask, locale);
return _create_locale(category_mask, locale); }
}
static void freelocale(locale_t locale) static void freelocale(locale_t locale) {
{ _free_locale(locale);
_free_locale(locale); }
}
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
{ return _strtod_l(nptr, endptr, locale);
return _strtod_l(nptr, endptr, locale); }
}
# endif # endif
locale_t locale_; locale_t locale_;
FMT_DISALLOW_COPY_AND_ASSIGN(Locale); FMT_DISALLOW_COPY_AND_ASSIGN(Locale);
public: public:
typedef locale_t Type; typedef locale_t Type;
Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
{ if (!locale_)
if (!locale_) FMT_THROW(fmt::SystemError(errno, "cannot create locale"));
FMT_THROW(fmt::SystemError(errno, "cannot create locale")); }
} ~Locale() { freelocale(locale_); }
~Locale()
{ Type get() const { return locale_; }
freelocale(locale_);
} // Converts string to floating-point number and advances str past the end
// of the parsed input.
Type get() const double strtod(const char *&str) const {
{ char *end = FMT_NULL;
return locale_; double result = strtod_l(str, &end, locale_);
} str = end;
return result;
// Converts string to floating-point number and advances str past the end }
// of the parsed input.
double strtod(const char *&str) const
{
char *end = FMT_NULL;
double result = strtod_l(str, &end, locale_);
str = end;
return result;
}
}; };
#endif // FMT_LOCALE #endif // FMT_LOCALE
} // namespace fmt } // namespace fmt
#if !FMT_USE_RVALUE_REFERENCES #if !FMT_USE_RVALUE_REFERENCES
namespace std namespace std {
{
// For compatibility with C++98. // For compatibility with C++98.
inline fmt::BufferedFile &move(fmt::BufferedFile &f) inline fmt::BufferedFile &move(fmt::BufferedFile &f) { return f; }
{ inline fmt::File &move(fmt::File &f) { return f; }
return f;
}
inline fmt::File &move(fmt::File &f)
{
return f;
}
} }
#endif #endif
......
...@@ -15,118 +15,78 @@ ...@@ -15,118 +15,78 @@
#include "ostream.h" #include "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;
}
}; };
// returns the default type for format specific "%s" // returns the default type for format specific "%s"
class DefaultType : public ArgVisitor<DefaultType, char> class DefaultType : public ArgVisitor<DefaultType, char> {
{ public:
public: char visit_char(int) { return 'c'; }
char visit_char(int)
{
return 'c';
}
char visit_bool(bool) char visit_bool(bool) { return 's'; }
{
return 's';
}
char visit_pointer(const void *) char visit_pointer(const void *) { return 'p'; }
{
return 'p';
}
template <typename T> template <typename T>
char visit_any_int(T) char visit_any_int(T) { return 'd'; }
{
return 'd';
}
template <typename T> template <typename T>
char visit_any_double(T) char visit_any_double(T) { return 'g'; }
{
return 'g';
}
char visit_unhandled_arg() char visit_unhandled_arg() { return 's'; }
{
return 's';
}
}; };
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,
...@@ -134,128 +94,108 @@ struct is_same<T, T> ...@@ -134,128 +94,108 @@ 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);
} void visit_char(int value) {
if (type_ != 's')
void visit_char(char value) visit_any_int(value);
{ }
if (type_ != 's')
visit_any_int(value); template <typename U>
void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i';
if (type_ == 's') {
is_signed = std::numeric_limits<U>::is_signed;
} }
template <typename U> using internal::Arg;
void visit_any_int(U value) typedef typename internal::Conditional<
{
bool is_signed = type_ == 'd' || type_ == 'i';
if (type_ == 's')
{
is_signed = std::numeric_limits<U>::is_signed;
}
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 (const_check(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
...@@ -278,359 +218,314 @@ public: ...@@ -278,359 +218,314 @@ public:
*/ */
template <typename Impl, typename Char, typename Spec> template <typename Impl, typename Char, typename Spec>
class BasicPrintfArgFormatter : class BasicPrintfArgFormatter :
public internal::ArgFormatterBase<Impl, Char, Spec> public internal::ArgFormatterBase<Impl, Char, Spec> {
{ 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, Spec> Base;
typedef internal::ArgFormatterBase<Impl, Char, Spec> 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> &w, Spec &s)
*/ : internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {}
BasicPrintfArgFormatter(BasicWriter<Char> &w, Spec &s)
: internal::ArgFormatterBase<Impl, Char, Spec>(w, s) {} /** Formats an argument of type ``bool``. */
void visit_bool(bool value) {
/** Formats an argument of type ``bool``. */ Spec &fmt_spec = this->spec();
void visit_bool(bool value) if (fmt_spec.type_ != 's')
{ return this->visit_any_int(value);
Spec &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 Spec &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 Spec &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, FormatSpec> public BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec> {
{ 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, FormatSpec>(w, s) {}
: BasicPrintfArgFormatter<PrintfArgFormatter<Char>, Char, FormatSpec>(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 &al, BasicWriter<Char> &w)
explicit PrintfFormatter(const ArgList &al, BasicWriter<Char> &w) : FormatterBase(al), writer_(w) {}
: FormatterBase(al), writer_(w) {}
/** Formats stored arguments and writes the output to the writer. */
/** Formats stored arguments and writes the output to the writer. */ void format(BasicCStringRef<Char> format_str);
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 = FMT_NULL;
const char *error = FMT_NULL; 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));
} else {
spec.precision_ = 0;
}
} }
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':
else // printf produces garbage when 'L' is omitted for long double, no
{ // need to do the same.
spec.precision_ = 0; break;
} default:
} --s;
ArgConverter<void>(arg, *s).visit(arg);
using internal::Arg; }
Arg arg = get_arg(s, arg_index);
if (spec.flag(HASH_FLAG) && internal::IsZeroInt().visit(arg)) // Parse type.
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); if (!*s)
if (spec.fill_ == '0') FMT_THROW(FormatError("invalid format string"));
{ spec.type_ = static_cast<char>(*s++);
if (arg.type <= Arg::LAST_NUMERIC_TYPE)
spec.align_ = ALIGN_NUMERIC; if (spec.type_ == 's') {
else // set the format type to the default if 's' is specified
spec.fill_ = ' '; // Ignore '0' flag for non-numeric types. spec.type_ = internal::DefaultType().visit(arg);
} }
// Parse length and convert the argument to the required type. if (arg.type <= Arg::LAST_INTEGER_TYPE) {
using internal::ArgConverter; // Normalize type.
switch (*s++) switch (spec.type_) {
{ case 'i': case 'u':
case 'h': spec.type_ = 'd';
if (*s == 'h') break;
ArgConverter<signed char>(arg, *++s).visit(arg); case 'c':
else // TODO: handle wchar_t
ArgConverter<short>(arg, *s).visit(arg); internal::CharConverter(arg).visit(arg);
break; 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 (spec.type_ == 's')
{
// set the format type to the default if 's' is specified
spec.type_ = internal::DefaultType().visit(arg);
}
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);
} }
inline void printf(Writer &w, CStringRef format, ArgList args) inline void printf(Writer &w, CStringRef format, ArgList args) {
{ PrintfFormatter<char>(args, w).format(format);
PrintfFormatter<char>(args, w).format(format);
} }
FMT_VARIADIC(void, printf, Writer &, CStringRef) FMT_VARIADIC(void, printf, Writer &, CStringRef)
inline void printf(WWriter &w, WCStringRef format, ArgList args) inline void printf(WWriter &w, WCStringRef format, ArgList args) {
{ PrintfFormatter<wchar_t>(args, w).format(format);
PrintfFormatter<wchar_t>(args, w).format(format);
} }
FMT_VARIADIC(void, printf, WWriter &, WCStringRef) FMT_VARIADIC(void, printf, WWriter &, WCStringRef)
...@@ -643,19 +538,17 @@ FMT_VARIADIC(void, printf, WWriter &, WCStringRef) ...@@ -643,19 +538,17 @@ FMT_VARIADIC(void, printf, WWriter &, WCStringRef)
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)
...@@ -680,9 +573,8 @@ FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) ...@@ -680,9 +573,8 @@ 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)
...@@ -695,12 +587,11 @@ FMT_VARIADIC(int, printf, CStringRef) ...@@ -695,12 +587,11 @@ FMT_VARIADIC(int, printf, CStringRef)
fprintf(cerr, "Don't %s!", "panic"); fprintf(cerr, "Don't %s!", "panic");
\endrst \endrst
*/ */
inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) inline int fprintf(std::ostream &os, CStringRef format_str, ArgList args) {
{ MemoryWriter w;
MemoryWriter w; printf(w, format_str, args);
printf(w, format_str, args); internal::write(os, w);
internal::write(os, w); return static_cast<int>(w.size());
return static_cast<int>(w.size());
} }
FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef) FMT_VARIADIC(int, fprintf, std::ostream &, CStringRef)
} // namespace fmt } // namespace fmt
......
...@@ -19,160 +19,120 @@ ...@@ -19,160 +19,120 @@
# pragma warning(disable: 4996) // "deprecated" functions # pragma warning(disable: 4996) // "deprecated" functions
#endif #endif
namespace fmt namespace fmt {
{
template <typename ArgFormatter> template <typename ArgFormatter>
void format_arg(BasicFormatter<char, ArgFormatter> &f, void format_arg(BasicFormatter<char, ArgFormatter> &f,
const char *&format_str, const std::tm &tm) const char *&format_str, const std::tm &tm) {
{ if (*format_str == ':')
if (*format_str == ':') ++format_str;
++format_str; const char *end = format_str;
const char *end = format_str; while (*end && *end != '}')
while (*end && *end != '}') ++end;
++end; if (*end != '}')
if (*end != '}') FMT_THROW(FormatError("missing '}' in format string"));
FMT_THROW(FormatError("missing '}' in format string")); internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format;
internal::MemoryBuffer<char, internal::INLINE_BUFFER_SIZE> format; format.append(format_str, end + 1);
format.append(format_str, end + 1); format[format.size() - 1] = '\0';
format[format.size() - 1] = '\0'; Buffer<char> &buffer = f.writer().buffer();
Buffer<char> &buffer = f.writer().buffer(); std::size_t start = buffer.size();
std::size_t start = buffer.size(); for (;;) {
for (;;) std::size_t size = buffer.capacity() - start;
{ std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm);
std::size_t size = buffer.capacity() - start; if (count != 0) {
std::size_t count = std::strftime(&buffer[start], size, &format[0], &tm); buffer.resize(start + count);
if (count != 0) break;
{
buffer.resize(start + count);
break;
}
if (size >= format.size() * 256)
{
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
} }
format_str = end + 1; if (size >= format.size() * 256) {
// If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases:
// https://github.com/fmtlib/fmt/issues/367
break;
}
const std::size_t MIN_GROWTH = 10;
buffer.reserve(buffer.capacity() + (size > MIN_GROWTH ? size : MIN_GROWTH));
}
format_str = end + 1;
} }
namespace internal namespace internal{
{ inline Null<> localtime_r(...) { return Null<>(); }
inline Null<> localtime_r(...) inline Null<> localtime_s(...) { return Null<>(); }
{ inline Null<> gmtime_r(...) { return Null<>(); }
return Null<>(); inline Null<> gmtime_s(...) { return Null<>(); }
}
inline Null<> localtime_s(...)
{
return Null<>();
}
inline Null<> gmtime_r(...)
{
return Null<>();
}
inline Null<> gmtime_s(...)
{
return Null<>();
}
} }
// Thread-safe replacement for std::localtime // Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) inline std::tm localtime(std::time_t time) {
{ struct LocalTime {
struct LocalTime std::time_t time_;
{ std::tm tm_;
std::time_t time_;
std::tm tm_; LocalTime(std::time_t t): time_(t) {}
LocalTime(std::time_t t): time_(t) {} bool run() {
using namespace fmt::internal;
bool run() return handle(localtime_r(&time_, &tm_));
{ }
using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_)); bool handle(std::tm *tm) { return tm != FMT_NULL; }
}
bool handle(internal::Null<>) {
bool handle(std::tm *tm) using namespace fmt::internal;
{ return fallback(localtime_s(&tm_, &time_));
return tm != FMT_NULL; }
}
bool fallback(int res) { return res == 0; }
bool handle(internal::Null<>)
{ bool fallback(internal::Null<>) {
using namespace fmt::internal; using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_)); std::tm *tm = std::localtime(&time_);
} if (tm) tm_ = *tm;
return tm != FMT_NULL;
bool fallback(int res) }
{ };
return res == 0; LocalTime lt(time);
} if (lt.run())
return lt.tm_;
bool fallback(internal::Null<>) // Too big time values may be unsupported.
{ FMT_THROW(fmt::FormatError("time_t value out of range"));
using namespace fmt::internal; return std::tm();
std::tm *tm = std::localtime(&time_);
if (tm) tm_ = *tm;
return tm != FMT_NULL;
}
};
LocalTime lt(time);
if (lt.run())
return lt.tm_;
// Too big time values may be unsupported.
FMT_THROW(fmt::FormatError("time_t value out of range"));
return std::tm();
} }
// Thread-safe replacement for std::gmtime // Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) inline std::tm gmtime(std::time_t time) {
{ struct GMTime {
struct GMTime std::time_t time_;
{ std::tm tm_;
std::time_t time_;
std::tm tm_; GMTime(std::time_t t): time_(t) {}
GMTime(std::time_t t): time_(t) {} bool run() {
using namespace fmt::internal;
bool run() return handle(gmtime_r(&time_, &tm_));
{ }
using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_)); bool handle(std::tm *tm) { return tm != FMT_NULL; }
}
bool handle(internal::Null<>) {
bool handle(std::tm *tm) using namespace fmt::internal;
{ return fallback(gmtime_s(&tm_, &time_));
return tm != FMT_NULL; }
}
bool fallback(int res) { return res == 0; }
bool handle(internal::Null<>)
{ bool fallback(internal::Null<>) {
using namespace fmt::internal; std::tm *tm = std::gmtime(&time_);
return fallback(gmtime_s(&tm_, &time_)); if (tm != FMT_NULL) tm_ = *tm;
} return tm != FMT_NULL;
}
bool fallback(int res) };
{ GMTime gt(time);
return res == 0; if (gt.run())
} return gt.tm_;
// Too big time values may be unsupported.
bool fallback(internal::Null<>) FMT_THROW(fmt::FormatError("time_t value out of range"));
{ return std::tm();
std::tm *tm = std::gmtime(&time_);
if (tm != FMT_NULL) tm_ = *tm;
return tm != FMT_NULL;
}
};
GMTime gt(time);
if (gt.run())
return gt.tm_;
// Too big time values may be unsupported.
FMT_THROW(fmt::FormatError("time_t value out of range"));
return std::tm();
} }
} //namespace fmt } //namespace fmt
......
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