Commit c1dd340a authored by gabime's avatar gabime

Updated cppformat to version 86a7d856fa03fb5ba96f1a27907a4b7171f42e56 and...

Updated cppformat to version 86a7d856fa03fb5ba96f1a27907a4b7171f42e56 and remove spdlog::details namespace from it's source
parent 9cfdfc75
/* /*
Formatting library for C++
Modified version of cppformat formatting library
Orginal license:
Copyright (c) 2012 - 2014, Victor Zverovich Copyright (c) 2012 - 2014, Victor Zverovich
All rights reserved. All rights reserved.
...@@ -28,7 +25,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ...@@ -28,7 +25,7 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "format.h"
#include <string.h> #include <string.h>
...@@ -39,18 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -39,18 +36,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <cstdarg> #include <cstdarg>
#ifdef _WIN32 #ifdef _WIN32
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# ifdef __MINGW32__ # ifdef __MINGW32__
# include <cstring> # include <cstring>
# endif # endif
# include <windows.h> # include <windows.h>
#endif #endif
using spdlog::details::fmt::LongLong; using fmt::internal::Arg;
using spdlog::details::fmt::ULongLong;
using spdlog::details::fmt::internal::Arg;
// Check if exceptions are disabled. // Check if exceptions are disabled.
#if __GNUC__ && !__EXCEPTIONS #if __GNUC__ && !__EXCEPTIONS
...@@ -74,8 +66,10 @@ using spdlog::details::fmt::internal::Arg; ...@@ -74,8 +66,10 @@ using spdlog::details::fmt::internal::Arg;
#ifndef FMT_THROW #ifndef FMT_THROW
# if FMT_EXCEPTIONS # if FMT_EXCEPTIONS
# define FMT_THROW(x) throw x # define FMT_THROW(x) throw x
# define FMT_RETURN_AFTER_THROW(x)
# else # else
# define FMT_THROW(x) assert(false) # define FMT_THROW(x) assert(false)
# define FMT_RETURN_AFTER_THROW(x) return x
# endif # endif
#endif #endif
...@@ -88,6 +82,7 @@ using spdlog::details::fmt::internal::Arg; ...@@ -88,6 +82,7 @@ using spdlog::details::fmt::internal::Arg;
#if _MSC_VER #if _MSC_VER
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4702) // unreachable code
#endif #endif
namespace { namespace {
...@@ -126,7 +121,7 @@ struct IntChecker<true> { ...@@ -126,7 +121,7 @@ struct IntChecker<true> {
const char RESET_COLOR[] = "\x1b[0m"; const char RESET_COLOR[] = "\x1b[0m";
typedef void(*FormatFunc)(spdlog::details::fmt::Writer &, int, spdlog::details::fmt::StringRef); typedef void(*FormatFunc)(fmt::Writer &, int, fmt::StringRef);
// Portable thread-safe version of strerror. // Portable thread-safe version of strerror.
// Sets buffer to point to a string describing the error code. // Sets buffer to point to a string describing the error code.
...@@ -137,11 +132,17 @@ typedef void(*FormatFunc)(spdlog::details::fmt::Writer &, int, spdlog::details:: ...@@ -137,11 +132,17 @@ typedef void(*FormatFunc)(spdlog::details::fmt::Writer &, int, spdlog::details::
// ERANGE - buffer is not large enough to store the error message // ERANGE - buffer is not large enough to store the error message
// other - failure // other - failure
// Buffer should be at least of size 1. // Buffer should be at least of size 1.
FMT_FUNC int safe_strerror( int safe_strerror(
int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT(true) { int error_code, char *&buffer, std::size_t buffer_size) FMT_NOEXCEPT{
assert(buffer != 0 && buffer_size != 0); assert(buffer != 0 && buffer_size != 0);
int result = 0; int result = 0;
#ifdef _GNU_SOURCE #if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || __ANDROID__
// XSI-compliant version of strerror_r.
result = strerror_r(error_code, buffer, buffer_size);
if (result != 0)
result = errno;
#elif _GNU_SOURCE
// GNU-specific version of strerror_r.
char *message = strerror_r(error_code, buffer, buffer_size); char *message = strerror_r(error_code, buffer, buffer_size);
// If the buffer is full then the message is probably truncated. // If the buffer is full then the message is probably truncated.
if (message == buffer && strlen(buffer) == buffer_size - 1) if (message == buffer && strlen(buffer) == buffer_size - 1)
...@@ -165,27 +166,27 @@ FMT_FUNC int safe_strerror( ...@@ -165,27 +166,27 @@ FMT_FUNC int safe_strerror(
return result; return result;
} }
FMT_FUNC void format_error_code(spdlog::details::fmt::Writer &out, int error_code, void format_error_code(fmt::Writer &out, int error_code,
spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { fmt::StringRef message) FMT_NOEXCEPT{
// Report error code making sure that the output fits into // Report error code making sure that the output fits into
// INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential // INLINE_BUFFER_SIZE to avoid dynamic memory allocation and potential
// bad_alloc. // bad_alloc.
out.clear(); out.clear();
static const char SEP[] = ": "; static const char SEP[] = ": ";
static const char FMT_ERROR[] = "error "; static const char ERR[] = "error ";
spdlog::details::fmt::internal::IntTraits<int>::MainType ec_value = error_code; fmt::internal::IntTraits<int>::MainType ec_value = error_code;
// Subtract 2 to account for terminating null characters in SEP and FMT_ERROR. // Subtract 2 to account for terminating null characters in SEP and ERR.
std::size_t error_code_size = std::size_t error_code_size =
sizeof(SEP) + sizeof(FMT_ERROR) + spdlog::details::fmt::internal::count_digits(ec_value) - 2; sizeof(SEP) + sizeof(ERR) + fmt::internal::count_digits(ec_value) - 2;
if (message.size() <= spdlog::details::fmt::internal::INLINE_BUFFER_SIZE - error_code_size) if (message.size() <= fmt::internal::INLINE_BUFFER_SIZE - error_code_size)
out << message << SEP; out << message << SEP;
out << FMT_ERROR << error_code; out << ERR << error_code;
assert(out.size() <= spdlog::details::fmt::internal::INLINE_BUFFER_SIZE); assert(out.size() <= fmt::internal::INLINE_BUFFER_SIZE);
} }
FMT_FUNC void report_error(FormatFunc func, void report_error(FormatFunc func,
int error_code, spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { int error_code, fmt::StringRef message) FMT_NOEXCEPT{
spdlog::details::fmt::MemoryWriter full_message; fmt::MemoryWriter full_message;
func(full_message, error_code, message); func(full_message, error_code, message);
// Use Writer::data instead of Writer::c_str to avoid potential memory // Use Writer::data instead of Writer::c_str to avoid potential memory
// allocation. // allocation.
...@@ -194,7 +195,7 @@ FMT_FUNC void report_error(FormatFunc func, ...@@ -194,7 +195,7 @@ FMT_FUNC void report_error(FormatFunc func,
} }
// 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 spdlog::details::fmt::internal::ArgVisitor<IsZeroInt, bool> { class IsZeroInt : public fmt::internal::ArgVisitor<IsZeroInt, bool> {
public: public:
template <typename T> template <typename T>
bool visit_any_int(T value) { bool visit_any_int(T value) {
...@@ -205,7 +206,7 @@ public: ...@@ -205,7 +206,7 @@ public:
// Parses an unsigned integer advancing s to the end of the parsed input. // Parses an unsigned integer advancing s to the end of the parsed input.
// This function assumes that the first character of s is a digit. // This function assumes that the first character of s is a digit.
template <typename Char> template <typename Char>
FMT_FUNC int parse_nonnegative_int(const Char *&s) { int parse_nonnegative_int(const Char *&s) {
assert('0' <= *s && *s <= '9'); assert('0' <= *s && *s <= '9');
unsigned value = 0; unsigned value = 0;
do { do {
...@@ -218,88 +219,92 @@ FMT_FUNC int parse_nonnegative_int(const Char *&s) { ...@@ -218,88 +219,92 @@ FMT_FUNC int parse_nonnegative_int(const Char *&s) {
value = new_value; value = new_value;
} while ('0' <= *s && *s <= '9'); } while ('0' <= *s && *s <= '9');
if (value > INT_MAX) if (value > INT_MAX)
FMT_THROW(spdlog::details::fmt::FormatError("number is too big")); FMT_THROW(fmt::FormatError("number is too big"));
return value; return value;
} }
inline void require_numeric_argument(const Arg &arg, char spec) { inline void require_numeric_argument(const Arg &arg, char spec) {
if (arg.type > Arg::LAST_NUMERIC_TYPE) { if (arg.type > Arg::LAST_NUMERIC_TYPE) {
std::string message = std::string message =
spdlog::details::fmt::format("format specifier '{}' requires numeric argument", spec); fmt::format("format specifier '{}' requires numeric argument", spec);
FMT_THROW(spdlog::details::fmt::FormatError(message)); FMT_THROW(fmt::FormatError(message));
} }
} }
template <typename Char> template <typename Char>
FMT_FUNC void check_sign(const Char *&s, const Arg &arg) { void check_sign(const Char *&s, const Arg &arg) {
char sign = static_cast<char>(*s); char sign = static_cast<char>(*s);
require_numeric_argument(arg, sign); require_numeric_argument(arg, sign);
if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) { if (arg.type == Arg::UINT || arg.type == Arg::ULONG_LONG) {
FMT_THROW(spdlog::details::fmt::FormatError(spdlog::details::fmt::format( FMT_THROW(fmt::FormatError(fmt::format(
"format specifier '{}' requires signed argument", sign))); "format specifier '{}' requires signed argument", sign)));
} }
++s; ++s;
} }
// 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 spdlog::details::fmt::internal::ArgVisitor<WidthHandler, unsigned> { class WidthHandler : public fmt::internal::ArgVisitor<WidthHandler, unsigned> {
private: private:
spdlog::details::fmt::FormatSpec &spec_; fmt::FormatSpec &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(WidthHandler);
public: public:
explicit WidthHandler(spdlog::details::fmt::FormatSpec &spec) : spec_(spec) {} explicit WidthHandler(fmt::FormatSpec &spec) : spec_(spec) {}
unsigned visit_unhandled_arg() { unsigned visit_unhandled_arg() {
FMT_THROW(spdlog::details::fmt::FormatError("width is not integer")); FMT_THROW(fmt::FormatError("width is not integer"));
return 0; FMT_RETURN_AFTER_THROW(0);
} }
template <typename T> template <typename T>
unsigned visit_any_int(T value) { unsigned visit_any_int(T value) {
typedef typename spdlog::details::fmt::internal::IntTraits<T>::MainType UnsignedType; typedef typename fmt::internal::IntTraits<T>::MainType UnsignedType;
UnsignedType width = value; UnsignedType width = value;
if (spdlog::details::fmt::internal::is_negative(value)) { if (fmt::internal::is_negative(value)) {
spec_.align_ = spdlog::details::fmt::ALIGN_LEFT; spec_.align_ = fmt::ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
if (width > INT_MAX) if (width > INT_MAX)
FMT_THROW(spdlog::details::fmt::FormatError("number is too big")); FMT_THROW(fmt::FormatError("number is too big"));
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
}; };
class PrecisionHandler : class PrecisionHandler :
public spdlog::details::fmt::internal::ArgVisitor<PrecisionHandler, int> { public fmt::internal::ArgVisitor<PrecisionHandler, int> {
public: public:
unsigned visit_unhandled_arg() { unsigned visit_unhandled_arg() {
FMT_THROW(spdlog::details::fmt::FormatError("precision is not integer")); FMT_THROW(fmt::FormatError("precision is not integer"));
return 0; FMT_RETURN_AFTER_THROW(0);
} }
template <typename T> template <typename T>
int visit_any_int(T value) { int visit_any_int(T value) {
if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) if (!IntChecker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(spdlog::details::fmt::FormatError("number is too big")); FMT_THROW(fmt::FormatError("number is too big"));
return static_cast<int>(value); return static_cast<int>(value);
} }
}; };
// Converts an integer argument to an integral type T for printf. // Converts an integer argument to an integral type T for printf.
template <typename T> template <typename T>
class ArgConverter : public spdlog::details::fmt::internal::ArgVisitor<ArgConverter<T>, void> { class ArgConverter : public fmt::internal::ArgVisitor<ArgConverter<T>, void> {
private: private:
spdlog::details::fmt::internal::Arg &arg_; fmt::internal::Arg &arg_;
wchar_t type_; wchar_t type_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgConverter);
public: public:
ArgConverter(spdlog::details::fmt::internal::Arg &arg, wchar_t type) ArgConverter(fmt::internal::Arg &arg, wchar_t type)
: arg_(arg), type_(type) {} : arg_(arg), type_(type) {}
template <typename U> template <typename U>
void visit_any_int(U value) { void visit_any_int(U value) {
bool is_signed = type_ == 'd' || type_ == 'i'; bool is_signed = type_ == 'd' || type_ == 'i';
using spdlog::details::fmt::internal::Arg; using fmt::internal::Arg;
if (sizeof(T) <= sizeof(int)) { if (sizeof(T) <= sizeof(int)) {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) { if (is_signed) {
...@@ -309,31 +314,33 @@ public: ...@@ -309,31 +314,33 @@ public:
else { else {
arg_.type = Arg::UINT; arg_.type = Arg::UINT;
arg_.uint_value = static_cast<unsigned>( arg_.uint_value = static_cast<unsigned>(
static_cast<typename spdlog::details::fmt::internal::MakeUnsigned<T>::Type>(value)); static_cast<typename fmt::internal::MakeUnsigned<T>::Type>(value));
} }
} }
else { else {
if (is_signed) { if (is_signed) {
arg_.type = Arg::LONG_LONG; arg_.type = Arg::LONG_LONG;
arg_.long_long_value = arg_.long_long_value =
static_cast<typename spdlog::details::fmt::internal::MakeUnsigned<U>::Type>(value); static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
} }
else { else {
arg_.type = Arg::ULONG_LONG; arg_.type = Arg::ULONG_LONG;
arg_.ulong_long_value = arg_.ulong_long_value =
static_cast<typename spdlog::details::fmt::internal::MakeUnsigned<U>::Type>(value); static_cast<typename fmt::internal::MakeUnsigned<U>::Type>(value);
} }
} }
} }
}; };
// Converts an integer argument to char for printf. // Converts an integer argument to char for printf.
class CharConverter : public spdlog::details::fmt::internal::ArgVisitor<CharConverter, void> { class CharConverter : public fmt::internal::ArgVisitor<CharConverter, void> {
private: private:
spdlog::details::fmt::internal::Arg &arg_; fmt::internal::Arg &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(CharConverter);
public: public:
explicit CharConverter(spdlog::details::fmt::internal::Arg &arg) : arg_(arg) {} explicit CharConverter(fmt::internal::Arg &arg) : arg_(arg) {}
template <typename T> template <typename T>
void visit_any_int(T value) { void visit_any_int(T value) {
...@@ -361,17 +368,17 @@ inline Arg::StringValue<wchar_t> ignore_incompatible_str( ...@@ -361,17 +368,17 @@ inline Arg::StringValue<wchar_t> ignore_incompatible_str(
} }
} // namespace } // namespace
FMT_FUNC void spdlog::details::fmt::SystemError::init( FMT_FUNC void fmt::SystemError::init(
int error_code, StringRef format_str, ArgList args) { int err_code, StringRef format_str, ArgList args) {
error_code_ = error_code; error_code_ = err_code;
MemoryWriter w; MemoryWriter w;
internal::format_system_error(w, error_code, format(format_str, args)); internal::format_system_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this; std::runtime_error &base = *this;
base = std::runtime_error(w.str()); base = std::runtime_error(w.str());
} }
template <typename T> template <typename T>
FMT_FUNC int spdlog::details::fmt::internal::CharTraits<char>::format_float( int fmt::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, T value) { unsigned width, int precision, T value) {
if (width == 0) { if (width == 0) {
...@@ -385,7 +392,7 @@ FMT_FUNC int spdlog::details::fmt::internal::CharTraits<char>::format_float( ...@@ -385,7 +392,7 @@ FMT_FUNC int spdlog::details::fmt::internal::CharTraits<char>::format_float(
} }
template <typename T> template <typename T>
FMT_FUNC int spdlog::details::fmt::internal::CharTraits<wchar_t>::format_float( int fmt::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, T value) { unsigned width, int precision, T value) {
if (width == 0) { if (width == 0) {
...@@ -399,7 +406,7 @@ FMT_FUNC int spdlog::details::fmt::internal::CharTraits<wchar_t>::format_float( ...@@ -399,7 +406,7 @@ FMT_FUNC int spdlog::details::fmt::internal::CharTraits<wchar_t>::format_float(
} }
template <typename T> template <typename T>
const char spdlog::details::fmt::internal::BasicData<T>::DIGITS[] = const char fmt::internal::BasicData<T>::DIGITS[] =
"0001020304050607080910111213141516171819" "0001020304050607080910111213141516171819"
"2021222324252627282930313233343536373839" "2021222324252627282930313233343536373839"
"4041424344454647484950515253545556575859" "4041424344454647484950515253545556575859"
...@@ -418,53 +425,53 @@ const char spdlog::details::fmt::internal::BasicData<T>::DIGITS[] = ...@@ -418,53 +425,53 @@ const char spdlog::details::fmt::internal::BasicData<T>::DIGITS[] =
factor * 1000000000 factor * 1000000000
template <typename T> template <typename T>
const uint32_t spdlog::details::fmt::internal::BasicData<T>::POWERS_OF_10_32[] = { const uint32_t fmt::internal::BasicData<T>::POWERS_OF_10_32[] = {
0, FMT_POWERS_OF_10(1) 0, FMT_POWERS_OF_10(1)
}; };
template <typename T> template <typename T>
const uint64_t spdlog::details::fmt::internal::BasicData<T>::POWERS_OF_10_64[] = { const uint64_t fmt::internal::BasicData<T>::POWERS_OF_10_64[] = {
0, 0,
FMT_POWERS_OF_10(1), FMT_POWERS_OF_10(1),
FMT_POWERS_OF_10(ULongLong(1000000000)), FMT_POWERS_OF_10(fmt::ULongLong(1000000000)),
// Multiply several constants instead of using a single long long constant // Multiply several constants instead of using a single long long constant
// to avoid warnings about C++98 not supporting long long. // to avoid warnings about C++98 not supporting long long.
ULongLong(1000000000) * ULongLong(1000000000) * 10 fmt::ULongLong(1000000000) * fmt::ULongLong(1000000000) * 10
}; };
FMT_FUNC void spdlog::details::fmt::internal::report_unknown_type(char code, const char *type) { FMT_FUNC void fmt::internal::report_unknown_type(char code, const char *type) {
if (std::isprint(static_cast<unsigned char>(code))) { if (std::isprint(static_cast<unsigned char>(code))) {
FMT_THROW(spdlog::details::fmt::FormatError( FMT_THROW(fmt::FormatError(
spdlog::details::fmt::format("unknown format code '{}' for {}", code, type))); fmt::format("unknown format code '{}' for {}", code, type)));
} }
FMT_THROW(spdlog::details::fmt::FormatError( FMT_THROW(fmt::FormatError(
spdlog::details::fmt::format("unknown format code '\\x{:02x}' for {}", fmt::format("unknown format code '\\x{:02x}' for {}",
static_cast<unsigned>(code), type))); static_cast<unsigned>(code), type)));
} }
#ifdef _WIN32 #ifdef _WIN32
FMT_FUNC spdlog::details::fmt::internal::UTF8ToUTF16::UTF8ToUTF16(spdlog::details::fmt::StringRef s) { FMT_FUNC fmt::internal::UTF8ToUTF16::UTF8ToUTF16(fmt::StringRef s) {
int length = MultiByteToWideChar( int length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0); CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, 0, 0);
static const char FMT_ERROR[] = "cannot convert string from UTF-8 to UTF-16"; static const char ERROR_MSG[] = "cannot convert string from UTF-8 to UTF-16";
if (length == 0) if (length == 0)
FMT_THROW(WindowsError(GetLastError(), FMT_ERROR)); FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
buffer_.resize(length); buffer_.resize(length);
length = MultiByteToWideChar( length = MultiByteToWideChar(
CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length); CP_UTF8, MB_ERR_INVALID_CHARS, s.c_str(), -1, &buffer_[0], length);
if (length == 0) if (length == 0)
FMT_THROW(WindowsError(GetLastError(), FMT_ERROR)); FMT_THROW(WindowsError(GetLastError(), ERROR_MSG));
} }
FMT_FUNC spdlog::details::fmt::internal::UTF16ToUTF8::UTF16ToUTF8(spdlog::details::fmt::WStringRef s) { FMT_FUNC fmt::internal::UTF16ToUTF8::UTF16ToUTF8(fmt::WStringRef s) {
if (int error_code = convert(s)) { if (int error_code = convert(s)) {
FMT_THROW(WindowsError(error_code, FMT_THROW(WindowsError(error_code,
"cannot convert string from UTF-16 to UTF-8")); "cannot convert string from UTF-16 to UTF-8"));
} }
} }
FMT_FUNC int spdlog::details::fmt::internal::UTF16ToUTF8::convert(spdlog::details::fmt::WStringRef s) { FMT_FUNC int fmt::internal::UTF16ToUTF8::convert(fmt::WStringRef s) {
int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0); int length = WideCharToMultiByte(CP_UTF8, 0, s.c_str(), -1, 0, 0, 0, 0);
if (length == 0) if (length == 0)
return GetLastError(); return GetLastError();
...@@ -476,21 +483,21 @@ FMT_FUNC int spdlog::details::fmt::internal::UTF16ToUTF8::convert(spdlog::detail ...@@ -476,21 +483,21 @@ FMT_FUNC int spdlog::details::fmt::internal::UTF16ToUTF8::convert(spdlog::detail
return 0; return 0;
} }
FMT_FUNC void spdlog::details::fmt::WindowsError::init( FMT_FUNC void fmt::WindowsError::init(
int error_code, StringRef format_str, ArgList args) { int err_code, StringRef format_str, ArgList args) {
error_code_ = error_code; error_code_ = err_code;
MemoryWriter w; MemoryWriter w;
internal::format_windows_error(w, error_code, format(format_str, args)); internal::format_windows_error(w, err_code, format(format_str, args));
std::runtime_error &base = *this; std::runtime_error &base = *this;
base = std::runtime_error(w.str()); base = std::runtime_error(w.str());
} }
#endif #endif
FMT_FUNC void spdlog::details::fmt::internal::format_system_error( FMT_FUNC void fmt::internal::format_system_error(
spdlog::details::fmt::Writer &out, int error_code, fmt::Writer &out, int error_code,
spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { fmt::StringRef message) FMT_NOEXCEPT{
FMT_TRY { FMT_TRY{
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer; MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer;
buffer.resize(INLINE_BUFFER_SIZE); buffer.resize(INLINE_BUFFER_SIZE);
for (;;) { for (;;) {
...@@ -509,9 +516,9 @@ FMT_FUNC void spdlog::details::fmt::internal::format_system_error( ...@@ -509,9 +516,9 @@ FMT_FUNC void spdlog::details::fmt::internal::format_system_error(
} }
#ifdef _WIN32 #ifdef _WIN32
FMT_FUNC void spdlog::details::fmt::internal::format_windows_error( FMT_FUNC void fmt::internal::format_windows_error(
spdlog::details::fmt::Writer &out, int error_code, fmt::Writer &out, int error_code,
spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { fmt::StringRef message) FMT_NOEXCEPT{
class String { class String {
private: private:
LPWSTR str_; LPWSTR str_;
...@@ -524,11 +531,9 @@ FMT_FUNC void spdlog::details::fmt::internal::format_windows_error( ...@@ -524,11 +531,9 @@ FMT_FUNC void spdlog::details::fmt::internal::format_windows_error(
LPWSTR *ptr() { LPWSTR *ptr() {
return &str_; return &str_;
} }
LPCWSTR c_str() const { LPCWSTR c_str() const { return str_; }
return str_;
}
}; };
FMT_TRY { FMT_TRY{
String system_message; String system_message;
if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0, FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, 0,
...@@ -547,17 +552,19 @@ FMT_FUNC void spdlog::details::fmt::internal::format_windows_error( ...@@ -547,17 +552,19 @@ FMT_FUNC void spdlog::details::fmt::internal::format_windows_error(
// An argument formatter. // An argument formatter.
template <typename Char> template <typename Char>
class spdlog::details::fmt::internal::ArgFormatter : class fmt::internal::ArgFormatter :
public spdlog::details::fmt::internal::ArgVisitor<spdlog::details::fmt::internal::ArgFormatter<Char>, void> { public fmt::internal::ArgVisitor<fmt::internal::ArgFormatter<Char>, void> {
private: private:
spdlog::details::fmt::BasicFormatter<Char> &formatter_; fmt::BasicFormatter<Char> &formatter_;
spdlog::details::fmt::BasicWriter<Char> &writer_; fmt::BasicWriter<Char> &writer_;
spdlog::details::fmt::FormatSpec &spec_; fmt::FormatSpec &spec_;
const Char *format_; const Char *format_;
FMT_DISALLOW_COPY_AND_ASSIGN(ArgFormatter);
public: public:
ArgFormatter( ArgFormatter(
spdlog::details::fmt::BasicFormatter<Char> &f, spdlog::details::fmt::FormatSpec &s, const Char *fmt) fmt::BasicFormatter<Char> &f, fmt::FormatSpec &s, const Char *fmt)
: formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {} : formatter_(f), writer_(f.writer()), spec_(s), format_(fmt) {}
template <typename T> template <typename T>
...@@ -578,16 +585,20 @@ public: ...@@ -578,16 +585,20 @@ public:
} }
if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0) if (spec_.align_ == ALIGN_NUMERIC || spec_.flags_ != 0)
FMT_THROW(FormatError("invalid format specifier for char")); FMT_THROW(FormatError("invalid format specifier for char"));
typedef typename spdlog::details::fmt::BasicWriter<Char>::CharPtr CharPtr; typedef typename fmt::BasicWriter<Char>::CharPtr CharPtr;
Char fill = static_cast<Char>(spec_.fill());
if (spec_.precision_ == 0) {
std::fill_n(writer_.grow_buffer(spec_.width_), spec_.width_, fill);
return;
}
CharPtr out = CharPtr(); CharPtr out = CharPtr();
if (spec_.width_ > 1) { if (spec_.width_ > 1) {
Char fill = static_cast<Char>(spec_.fill());
out = writer_.grow_buffer(spec_.width_); out = writer_.grow_buffer(spec_.width_);
if (spec_.align_ == spdlog::details::fmt::ALIGN_RIGHT) { if (spec_.align_ == fmt::ALIGN_RIGHT) {
std::fill_n(out, spec_.width_ - 1, fill); std::fill_n(out, spec_.width_ - 1, fill);
out += spec_.width_ - 1; out += spec_.width_ - 1;
} }
else if (spec_.align_ == spdlog::details::fmt::ALIGN_CENTER) { else if (spec_.align_ == fmt::ALIGN_CENTER) {
out = writer_.fill_padding(out, spec_.width_, 1, fill); out = writer_.fill_padding(out, spec_.width_, 1, fill);
} }
else { else {
...@@ -609,8 +620,8 @@ public: ...@@ -609,8 +620,8 @@ public:
void visit_pointer(const void *value) { void visit_pointer(const void *value) {
if (spec_.type_ && spec_.type_ != 'p') if (spec_.type_ && spec_.type_ != 'p')
spdlog::details::fmt::internal::report_unknown_type(spec_.type_, "pointer"); fmt::internal::report_unknown_type(spec_.type_, "pointer");
spec_.flags_ = spdlog::details::fmt::HASH_FLAG; spec_.flags_ = fmt::HASH_FLAG;
spec_.type_ = 'x'; spec_.type_ = 'x';
writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_); writer_.write_int(reinterpret_cast<uintptr_t>(value), spec_);
} }
...@@ -622,34 +633,39 @@ public: ...@@ -622,34 +633,39 @@ public:
template <typename Char> template <typename Char>
template <typename StrChar> template <typename StrChar>
FMT_FUNC void spdlog::details::fmt::BasicWriter<Char>::write_str( void fmt::BasicWriter<Char>::write_str(
const Arg::StringValue<StrChar> &str, const FormatSpec &spec) { const Arg::StringValue<StrChar> &s, const FormatSpec &spec) {
// Check if StrChar is convertible to Char. // Check if StrChar is convertible to Char.
internal::CharTraits<Char>::convert(StrChar()); internal::CharTraits<Char>::convert(StrChar());
if (spec.type_ && spec.type_ != 's') if (spec.type_ && spec.type_ != 's')
internal::report_unknown_type(spec.type_, "string"); internal::report_unknown_type(spec.type_, "string");
const StrChar *s = str.value; const StrChar *str_value = s.value;
std::size_t size = str.size; std::size_t str_size = s.size;
if (size == 0) { if (str_size == 0) {
if (!s) if (!str_value)
FMT_THROW(FormatError("string pointer is null")); FMT_THROW(FormatError("string pointer is null"));
if (*s) if (*str_value)
size = std::char_traits<StrChar>::length(s); str_size = std::char_traits<StrChar>::length(str_value);
} }
write_str(s, size, spec); std::size_t precision = spec.precision_;
if (spec.precision_ >= 0 && precision < str_size)
str_size = spec.precision_;
write_str(str_value, str_size, spec);
} }
template <typename Char> template <typename Char>
inline Arg spdlog::details::fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) { inline Arg fmt::BasicFormatter<Char>::parse_arg_index(const Char *&s) {
const char *error = 0; const char *error = 0;
Arg arg = *s < '0' || *s > '9' ? next_arg(error) : get_arg(parse_nonnegative_int(s), error); Arg arg = *s < '0' || *s > '9' ?
next_arg(error) : get_arg(parse_nonnegative_int(s), error);
if (error) { if (error) {
FMT_THROW(FormatError(*s != '}' && *s != ':' ? "invalid format string" : error)); FMT_THROW(FormatError(
*s != '}' && *s != ':' ? "invalid format string" : error));
} }
return arg; return arg;
} }
FMT_FUNC Arg spdlog::details::fmt::internal::FormatterBase::do_get_arg( FMT_FUNC Arg fmt::internal::FormatterBase::do_get_arg(
unsigned arg_index, const char *&error) { unsigned arg_index, const char *&error) {
Arg arg = args_[arg_index]; Arg arg = args_[arg_index];
if (arg.type == Arg::NONE) if (arg.type == Arg::NONE)
...@@ -657,14 +673,14 @@ FMT_FUNC Arg spdlog::details::fmt::internal::FormatterBase::do_get_arg( ...@@ -657,14 +673,14 @@ FMT_FUNC Arg spdlog::details::fmt::internal::FormatterBase::do_get_arg(
return arg; return arg;
} }
inline Arg spdlog::details::fmt::internal::FormatterBase::next_arg(const char *&error) { inline Arg fmt::internal::FormatterBase::next_arg(const char *&error) {
if (next_arg_index_ >= 0) if (next_arg_index_ >= 0)
return do_get_arg(next_arg_index_++, error); return do_get_arg(next_arg_index_++, error);
error = "cannot switch from manual to automatic argument indexing"; error = "cannot switch from manual to automatic argument indexing";
return Arg(); return Arg();
} }
inline Arg spdlog::details::fmt::internal::FormatterBase::get_arg( inline Arg fmt::internal::FormatterBase::get_arg(
unsigned arg_index, const char *&error) { unsigned arg_index, const char *&error) {
if (next_arg_index_ <= 0) { if (next_arg_index_ <= 0) {
next_arg_index_ = -1; next_arg_index_ = -1;
...@@ -675,7 +691,7 @@ inline Arg spdlog::details::fmt::internal::FormatterBase::get_arg( ...@@ -675,7 +691,7 @@ inline Arg spdlog::details::fmt::internal::FormatterBase::get_arg(
} }
template <typename Char> template <typename Char>
FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::parse_flags( void fmt::internal::PrintfFormatter<Char>::parse_flags(
FormatSpec &spec, const Char *&s) { FormatSpec &spec, const Char *&s) {
for (;;) { for (;;) {
switch (*s++) { switch (*s++) {
...@@ -702,7 +718,7 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::parse_flags ...@@ -702,7 +718,7 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::parse_flags
} }
template <typename Char> template <typename Char>
FMT_FUNC Arg spdlog::details::fmt::internal::PrintfFormatter<Char>::get_arg( Arg fmt::internal::PrintfFormatter<Char>::get_arg(
const Char *s, unsigned arg_index) { const Char *s, unsigned arg_index) {
const char *error = 0; const char *error = 0;
Arg arg = arg_index == UINT_MAX ? Arg arg = arg_index == UINT_MAX ?
...@@ -713,7 +729,7 @@ FMT_FUNC Arg spdlog::details::fmt::internal::PrintfFormatter<Char>::get_arg( ...@@ -713,7 +729,7 @@ FMT_FUNC Arg spdlog::details::fmt::internal::PrintfFormatter<Char>::get_arg(
} }
template <typename Char> template <typename Char>
FMT_FUNC unsigned spdlog::details::fmt::internal::PrintfFormatter<Char>::parse_header( unsigned fmt::internal::PrintfFormatter<Char>::parse_header(
const Char *&s, FormatSpec &spec) { const Char *&s, FormatSpec &spec) {
unsigned arg_index = UINT_MAX; unsigned arg_index = UINT_MAX;
Char c = *s; Char c = *s;
...@@ -749,10 +765,10 @@ FMT_FUNC unsigned spdlog::details::fmt::internal::PrintfFormatter<Char>::parse_h ...@@ -749,10 +765,10 @@ FMT_FUNC unsigned spdlog::details::fmt::internal::PrintfFormatter<Char>::parse_h
} }
template <typename Char> template <typename Char>
FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format( void fmt::internal::PrintfFormatter<Char>::format(
BasicWriter<Char> &writer, BasicStringRef<Char> format, BasicWriter<Char> &writer, BasicStringRef<Char> format_str,
const ArgList &args) { const ArgList &args) {
const Char *start = format.c_str(); const Char *start = format_str.c_str();
set_args(args); set_args(args);
const Char *s = start; const Char *s = start;
while (*s) { while (*s) {
...@@ -803,7 +819,7 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format( ...@@ -803,7 +819,7 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format(
break; break;
case 'l': case 'l':
if (*s == 'l') if (*s == 'l')
ArgConverter<spdlog::details::fmt::LongLong>(arg, *++s).visit(arg); ArgConverter<fmt::LongLong>(arg, *++s).visit(arg);
else else
ArgConverter<long>(arg, *s).visit(arg); ArgConverter<long>(arg, *s).visit(arg);
break; break;
...@@ -907,8 +923,8 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format( ...@@ -907,8 +923,8 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format(
case Arg::CUSTOM: { case Arg::CUSTOM: {
if (spec.type_) if (spec.type_)
internal::report_unknown_type(spec.type_, "object"); internal::report_unknown_type(spec.type_, "object");
const void *s = "s"; const void *str_format = "s";
arg.custom.format(&writer, arg.custom.value, &s); arg.custom.format(&writer, arg.custom.value, &str_format);
break; break;
} }
default: default:
...@@ -920,7 +936,7 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format( ...@@ -920,7 +936,7 @@ FMT_FUNC void spdlog::details::fmt::internal::PrintfFormatter<Char>::format(
} }
template <typename Char> template <typename Char>
FMT_FUNC const Char *spdlog::details::fmt::BasicFormatter<Char>::format( const Char *fmt::BasicFormatter<Char>::format(
const Char *&format_str, const Arg &arg) { const Char *&format_str, const Arg &arg) {
const Char *s = format_str; const Char *s = format_str;
FormatSpec spec; FormatSpec spec;
...@@ -1039,9 +1055,10 @@ FMT_FUNC const Char *spdlog::details::fmt::BasicFormatter<Char>::format( ...@@ -1039,9 +1055,10 @@ FMT_FUNC const Char *spdlog::details::fmt::BasicFormatter<Char>::format(
else { else {
FMT_THROW(FormatError("missing precision specifier")); FMT_THROW(FormatError("missing precision specifier"));
} }
if (arg.type != Arg::DOUBLE && arg.type != Arg::LONG_DOUBLE) { if (arg.type < Arg::LAST_INTEGER_TYPE || arg.type == Arg::POINTER) {
FMT_THROW(FormatError( FMT_THROW(FormatError(
"precision specifier requires floating-point argument")); fmt::format("precision not allowed in {} format specifier",
arg.type == Arg::POINTER ? "pointer" : "integer")));
} }
} }
...@@ -1060,7 +1077,7 @@ FMT_FUNC const Char *spdlog::details::fmt::BasicFormatter<Char>::format( ...@@ -1060,7 +1077,7 @@ FMT_FUNC const Char *spdlog::details::fmt::BasicFormatter<Char>::format(
} }
template <typename Char> template <typename Char>
FMT_FUNC void spdlog::details::fmt::BasicFormatter<Char>::format( void fmt::BasicFormatter<Char>::format(
BasicStringRef<Char> format_str, const ArgList &args) { BasicStringRef<Char> format_str, const ArgList &args) {
const Char *s = start_ = format_str.c_str(); const Char *s = start_ = format_str.c_str();
set_args(args); set_args(args);
...@@ -1081,35 +1098,35 @@ FMT_FUNC void spdlog::details::fmt::BasicFormatter<Char>::format( ...@@ -1081,35 +1098,35 @@ FMT_FUNC void spdlog::details::fmt::BasicFormatter<Char>::format(
write(writer_, start_, s); write(writer_, start_, s);
} }
FMT_FUNC void spdlog::details::fmt::report_system_error( FMT_FUNC void fmt::report_system_error(
int error_code, spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { int error_code, fmt::StringRef message) FMT_NOEXCEPT{
report_error(internal::format_system_error, error_code, message); report_error(internal::format_system_error, error_code, message);
} }
#ifdef _WIN32 #ifdef _WIN32
FMT_FUNC void spdlog::details::fmt::report_windows_error( FMT_FUNC void fmt::report_windows_error(
int error_code, spdlog::details::fmt::StringRef message) FMT_NOEXCEPT(true) { int error_code, fmt::StringRef message) FMT_NOEXCEPT{
report_error(internal::format_windows_error, error_code, message); report_error(internal::format_windows_error, error_code, message);
} }
#endif #endif
FMT_FUNC void spdlog::details::fmt::print(std::FILE *f, StringRef format_str, ArgList args) { FMT_FUNC void fmt::print(std::FILE *f, StringRef format_str, ArgList args) {
MemoryWriter w; MemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
std::fwrite(w.data(), 1, w.size(), f); std::fwrite(w.data(), 1, w.size(), f);
} }
FMT_FUNC void spdlog::details::fmt::print(StringRef format_str, ArgList args) { FMT_FUNC void fmt::print(StringRef format_str, ArgList args) {
print(stdout, format_str, args); print(stdout, format_str, args);
} }
FMT_FUNC void spdlog::details::fmt::print(std::ostream &os, StringRef format_str, ArgList args) { FMT_FUNC void fmt::print(std::ostream &os, StringRef format_str, ArgList args) {
MemoryWriter w; MemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
os.write(w.data(), w.size()); os.write(w.data(), w.size());
} }
FMT_FUNC void spdlog::details::fmt::print_colored(Color c, StringRef format, ArgList args) { FMT_FUNC void fmt::print_colored(Color c, StringRef format, ArgList args) {
char escape[] = "\x1b[30m"; char escape[] = "\x1b[30m";
escape[3] = '0' + static_cast<char>(c); escape[3] = '0' + static_cast<char>(c);
std::fputs(escape, stdout); std::fputs(escape, stdout);
...@@ -1117,7 +1134,7 @@ FMT_FUNC void spdlog::details::fmt::print_colored(Color c, StringRef format, Arg ...@@ -1117,7 +1134,7 @@ FMT_FUNC void spdlog::details::fmt::print_colored(Color c, StringRef format, Arg
std::fputs(RESET_COLOR, stdout); std::fputs(RESET_COLOR, stdout);
} }
FMT_FUNC int spdlog::details::fmt::fprintf(std::FILE *f, StringRef format, ArgList args) { FMT_FUNC int fmt::fprintf(std::FILE *f, StringRef format, ArgList args) {
MemoryWriter w; MemoryWriter w;
printf(w, format, args); printf(w, format, args);
std::size_t size = w.size(); std::size_t size = w.size();
...@@ -1126,40 +1143,40 @@ FMT_FUNC int spdlog::details::fmt::fprintf(std::FILE *f, StringRef format, ArgLi ...@@ -1126,40 +1143,40 @@ FMT_FUNC int spdlog::details::fmt::fprintf(std::FILE *f, StringRef format, ArgLi
// Explicit instantiations for char. // Explicit instantiations for char.
template const char *spdlog::details::fmt::BasicFormatter<char>::format( template const char *fmt::BasicFormatter<char>::format(
const char *&format_str, const spdlog::details::fmt::internal::Arg &arg); const char *&format_str, const fmt::internal::Arg &arg);
template void spdlog::details::fmt::BasicFormatter<char>::format( template void fmt::BasicFormatter<char>::format(
BasicStringRef<char> format, const ArgList &args); BasicStringRef<char> format, const ArgList &args);
template void spdlog::details::fmt::internal::PrintfFormatter<char>::format( template void fmt::internal::PrintfFormatter<char>::format(
BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args); BasicWriter<char> &writer, BasicStringRef<char> format, const ArgList &args);
template int spdlog::details::fmt::internal::CharTraits<char>::format_float( template int fmt::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);
template int spdlog::details::fmt::internal::CharTraits<char>::format_float( template int fmt::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, long double value); unsigned width, int precision, long double value);
// Explicit instantiations for wchar_t. // Explicit instantiations for wchar_t.
template const wchar_t *spdlog::details::fmt::BasicFormatter<wchar_t>::format( template const wchar_t *fmt::BasicFormatter<wchar_t>::format(
const wchar_t *&format_str, const spdlog::details::fmt::internal::Arg &arg); const wchar_t *&format_str, const fmt::internal::Arg &arg);
template void spdlog::details::fmt::BasicFormatter<wchar_t>::format( template void fmt::BasicFormatter<wchar_t>::format(
BasicStringRef<wchar_t> format, const ArgList &args); BasicStringRef<wchar_t> format, const ArgList &args);
template void spdlog::details::fmt::internal::PrintfFormatter<wchar_t>::format( template void fmt::internal::PrintfFormatter<wchar_t>::format(
BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format, BasicWriter<wchar_t> &writer, BasicStringRef<wchar_t> format,
const ArgList &args); const ArgList &args);
template int spdlog::details::fmt::internal::CharTraits<wchar_t>::format_float( template int fmt::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);
template int spdlog::details::fmt::internal::CharTraits<wchar_t>::format_float( template int fmt::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, long double value); unsigned width, int precision, long double value);
......
...@@ -25,8 +25,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ...@@ -25,8 +25,10 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
#ifndef SPDLOG_FMT_FORMAT_H_ #ifndef FMT_FORMAT_H_
#define SPDLOG_FMT_FORMAT_H_ #define FMT_FORMAT_H_
#define FMT_HEADER_ONLY
#include <stdint.h> #include <stdint.h>
...@@ -44,23 +46,65 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -44,23 +46,65 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# include <iterator> # include <iterator>
#endif #endif
#ifdef __GNUC__ #ifdef _MSC_VER
// Ignore shadow warnings # include <intrin.h> // _BitScanReverse, _BitScanReverse64
# pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wshadow" namespace fmt {
namespace internal {
# pragma intrinsic(_BitScanReverse)
inline uint32_t clz(uint32_t x) {
unsigned long r = 0;
_BitScanReverse(&r, x);
return 31 - r;
}
# define FMT_BUILTIN_CLZ(n) fmt::internal::clz(n)
# ifdef _WIN64
# pragma intrinsic(_BitScanReverse64)
# endif
inline uint32_t clzll(uint64_t x) {
unsigned long r = 0;
# ifdef _WIN64
_BitScanReverse64(&r, x);
# else
// Scan the high 32 bits.
if (_BitScanReverse(&r, static_cast<uint32_t>(x >> 32)))
return 63 - (r + 32);
// Scan the low 32 bits.
_BitScanReverse(&r, static_cast<uint32_t>(x));
# endif
return 63 - r;
}
# define FMT_BUILTIN_CLZLL(n) fmt::internal::clzll(n)
}
}
#endif
#ifdef __GNUC__
# define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) # define FMT_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__)
# define FMT_GCC_EXTENSION __extension__ # define FMT_GCC_EXTENSION __extension__
// Disable warning about "long long" which is sometimes reported even
// when using __extension__.
# if FMT_GCC_VERSION >= 406 # if FMT_GCC_VERSION >= 406
# pragma GCC diagnostic push # pragma GCC diagnostic push
// Disable the warning about "long long" which is sometimes reported even
// when using __extension__.
# pragma GCC diagnostic ignored "-Wlong-long" # pragma GCC diagnostic ignored "-Wlong-long"
// Disable the warning about declaration shadowing because it affects too
// many valid cases.
# pragma GCC diagnostic ignored "-Wshadow"
# endif
# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__
# define FMT_HAS_GXX_CXX11 1
# endif # endif
#else #else
# define FMT_GCC_EXTENSION # define FMT_GCC_EXTENSION
#endif #endif
#ifdef __clang__
# pragma clang diagnostic ignored "-Wdocumentation"
#endif
#ifdef __GNUC_LIBSTD__ #ifdef __GNUC_LIBSTD__
# define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__) # define FMT_GNUC_LIBSTD_VERSION (__GNUC_LIBSTD__ * 100 + __GNUC_LIBSTD_MINOR__)
#endif #endif
...@@ -77,13 +121,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -77,13 +121,19 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# define FMT_HAS_BUILTIN(x) 0 # define FMT_HAS_BUILTIN(x) 0
#endif #endif
#ifdef __has_cpp_attribute
# define FMT_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x)
#else
# define FMT_HAS_CPP_ATTRIBUTE(x) 0
#endif
#ifndef FMT_USE_VARIADIC_TEMPLATES #ifndef FMT_USE_VARIADIC_TEMPLATES
// Variadic templates are available in GCC since version 4.4 // Variadic templates are available in GCC since version 4.4
// (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++ // (http://gcc.gnu.org/projects/cxx0x.html) and in Visual C++
// since version 2013. // since version 2013.
# define FMT_USE_VARIADIC_TEMPLATES \ # define FMT_USE_VARIADIC_TEMPLATES \
(FMT_HAS_FEATURE(cxx_variadic_templates) || \ (FMT_HAS_FEATURE(cxx_variadic_templates) || \
(FMT_GCC_VERSION >= 404 && __cplusplus >= 201103) || _MSC_VER >= 1800) (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800)
#endif #endif
#ifndef FMT_USE_RVALUE_REFERENCES #ifndef FMT_USE_RVALUE_REFERENCES
...@@ -94,7 +144,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -94,7 +144,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
# else # else
# define FMT_USE_RVALUE_REFERENCES \ # define FMT_USE_RVALUE_REFERENCES \
(FMT_HAS_FEATURE(cxx_rvalue_references) || \ (FMT_HAS_FEATURE(cxx_rvalue_references) || \
(FMT_GCC_VERSION >= 403 && __cplusplus >= 201103) || _MSC_VER >= 1600) (FMT_GCC_VERSION >= 403 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1600)
# endif # endif
#endif #endif
...@@ -104,23 +154,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ...@@ -104,23 +154,26 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature). // Define FMT_USE_NOEXCEPT to make C++ Format use noexcept (C++11 feature).
#if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ #if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
(FMT_GCC_VERSION >= 408 && __cplusplus >= 201103) (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11)
# define FMT_NOEXCEPT(expr) noexcept(expr) # define FMT_NOEXCEPT noexcept
#else #else
# define FMT_NOEXCEPT(expr) # define FMT_NOEXCEPT throw()
#endif #endif
// A macro to disallow the copy constructor and operator= functions // A macro to disallow the copy constructor and operator= functions
// This should be used in the private: declarations for a class // This should be used in the private: declarations for a class
#define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \ #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
TypeName(const TypeName&); \ (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800
void operator=(const TypeName&) # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
namespace spdlog TypeName(const TypeName&) = delete; \
{ TypeName& operator=(const TypeName&) = delete
namespace details #else
{ # define FMT_DISALLOW_COPY_AND_ASSIGN(TypeName) \
namespace fmt TypeName(const TypeName&); \
{ TypeName& operator=(const TypeName&)
#endif
namespace fmt {
// Fix the warning about long long on older versions of GCC // Fix the warning about long long on older versions of GCC
// that don't support the diagnostic pragma. // that don't support the diagnostic pragma.
...@@ -162,15 +215,14 @@ This class is most useful as a parameter type to allow passing ...@@ -162,15 +215,14 @@ This class is most useful as a parameter type to allow passing
different types of strings to a function, for example:: different types of strings to a function, for example::
template <typename... Args> template <typename... Args>
std::string format(StringRef format, const Args & ... args); std::string format(StringRef format_str, const Args & ... args);
format("{}", 42); format("{}", 42);
format(std::string("{}"), 42); format(std::string("{}"), 42);
\endrst \endrst
*/ */
template <typename Char> template <typename Char>
class BasicStringRef class BasicStringRef {
{
private: private:
const Char *data_; const Char *data_;
std::size_t size_; std::size_t size_;
...@@ -197,33 +249,28 @@ public: ...@@ -197,33 +249,28 @@ public:
/** /**
Converts a string reference to an `std::string` object. Converts a string reference to an `std::string` object.
*/ */
operator std::basic_string<Char>() const operator std::basic_string<Char>() const {
{
return std::basic_string<Char>(data_, size()); return std::basic_string<Char>(data_, size());
} }
/** /**
Returns the pointer to a C string. Returns the pointer to a C string.
*/ */
const Char *c_str() const const Char *c_str() const {
{
return data_; return data_;
} }
/** /**
Returns the string size. Returns the string size.
*/ */
std::size_t size() const std::size_t size() const {
{
return size_; return size_;
} }
friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) {
{
return lhs.data_ == rhs.data_; return lhs.data_ == rhs.data_;
} }
friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) {
{
return lhs.data_ != rhs.data_; return lhs.data_ != rhs.data_;
} }
}; };
...@@ -234,15 +281,13 @@ typedef BasicStringRef<wchar_t> WStringRef; ...@@ -234,15 +281,13 @@ typedef BasicStringRef<wchar_t> WStringRef;
/** /**
A formatting error such as invalid format string. A formatting error such as invalid format string.
*/ */
class FormatError : public std::runtime_error class FormatError : public std::runtime_error {
{
public: public:
explicit FormatError(StringRef message) explicit FormatError(StringRef message)
: std::runtime_error(message.c_str()) {} : std::runtime_error(message.c_str()) {}
}; };
namespace internal namespace internal {
{
// The number of characters to store in the MemoryBuffer object itself // The number of characters to store in the MemoryBuffer object itself
// to avoid dynamic memory allocation. // to avoid dynamic memory allocation.
...@@ -251,22 +296,19 @@ enum { INLINE_BUFFER_SIZE = 500 }; ...@@ -251,22 +296,19 @@ enum { INLINE_BUFFER_SIZE = 500 };
#if _SECURE_SCL #if _SECURE_SCL
// Use checked iterator to avoid warnings on MSVC. // Use checked iterator to avoid warnings on MSVC.
template <typename T> template <typename T>
inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) inline stdext::checked_array_iterator<T*> make_ptr(T *ptr, std::size_t size) {
{
return stdext::checked_array_iterator<T*>(ptr, size); return stdext::checked_array_iterator<T*>(ptr, size);
} }
#else #else
template <typename T> template <typename T>
inline T *make_ptr(T *ptr, std::size_t) inline T *make_ptr(T *ptr, std::size_t) {
{
return ptr; return ptr;
} }
#endif #endif
// A buffer for POD types. It supports a subset of std::vector's operations. // A buffer for POD types. It supports a subset of std::vector's operations.
template <typename T> template <typename T>
class Buffer class Buffer {
{
private: private:
FMT_DISALLOW_COPY_AND_ASSIGN(Buffer); FMT_DISALLOW_COPY_AND_ASSIGN(Buffer);
...@@ -284,39 +326,31 @@ public: ...@@ -284,39 +326,31 @@ public:
virtual ~Buffer() {} virtual ~Buffer() {}
// Returns the size of this buffer. // Returns the size of this buffer.
std::size_t size() const std::size_t size() const {
{
return size_; return size_;
} }
// Returns the capacity of this buffer. // Returns the capacity of this buffer.
std::size_t capacity() const std::size_t capacity() const {
{
return capacity_; return capacity_;
} }
// Resizes the buffer. If T is a POD type new elements are not initialized. // Resizes the buffer. If T is a POD type new elements are not initialized.
void resize(std::size_t new_size) void resize(std::size_t new_size) {
{
if (new_size > capacity_) if (new_size > capacity_)
grow(new_size); grow(new_size);
size_ = new_size; size_ = new_size;
} }
// Reserves space to store at least capacity elements. // Reserves space to store at least capacity elements.
void reserve(std::size_t capacity) void reserve(std::size_t capacity) {
{
if (capacity > capacity_) if (capacity > capacity_)
grow(capacity); grow(capacity);
} }
void clear() FMT_NOEXCEPT(true) void clear() FMT_NOEXCEPT{ size_ = 0; }
{
size_ = 0;
}
void push_back(const T &value) void push_back(const T &value) {
{
if (size_ == capacity_) if (size_ == capacity_)
grow(size_ + 1); grow(size_ + 1);
ptr_[size_++] = value; ptr_[size_++] = value;
...@@ -325,19 +359,16 @@ public: ...@@ -325,19 +359,16 @@ public:
// Appends data to the end of the buffer. // Appends data to the end of the buffer.
void append(const T *begin, const T *end); void append(const T *begin, const T *end);
T &operator[](std::size_t index) T &operator[](std::size_t index) {
{
return ptr_[index]; return ptr_[index];
} }
const T &operator[](std::size_t index) const const T &operator[](std::size_t index) const {
{
return ptr_[index]; return ptr_[index];
} }
}; };
template <typename T> template <typename T>
void Buffer<T>::append(const T *begin, const T *end) void Buffer<T>::append(const T *begin, const T *end) {
{
std::ptrdiff_t num_elements = end - begin; std::ptrdiff_t num_elements = end - begin;
if (size_ + num_elements > capacity_) if (size_ + num_elements > capacity_)
grow(size_ + num_elements); grow(size_ + num_elements);
...@@ -348,14 +379,12 @@ void Buffer<T>::append(const T *begin, const T *end) ...@@ -348,14 +379,12 @@ void Buffer<T>::append(const T *begin, const T *end)
// A memory buffer for POD types with the first SIZE elements stored in // A memory buffer for POD types with the first SIZE elements stored in
// the object itself. // the object itself.
template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> > template <typename T, std::size_t SIZE, typename Allocator = std::allocator<T> >
class MemoryBuffer : private Allocator, public Buffer<T> class MemoryBuffer : private Allocator, public Buffer<T> {
{
private: private:
T data_[SIZE]; T data_[SIZE];
// Free memory allocated by the buffer. // Free memory allocated by the buffer.
void free() void free() {
{
if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_);
} }
...@@ -365,28 +394,24 @@ protected: ...@@ -365,28 +394,24 @@ protected:
public: public:
explicit MemoryBuffer(const Allocator &alloc = Allocator()) explicit MemoryBuffer(const Allocator &alloc = Allocator())
: Allocator(alloc), Buffer<T>(data_, SIZE) {} : Allocator(alloc), Buffer<T>(data_, SIZE) {}
~MemoryBuffer() ~MemoryBuffer() {
{
free(); free();
} }
#if FMT_USE_RVALUE_REFERENCES #if FMT_USE_RVALUE_REFERENCES
private: private:
// Move data from other to this buffer. // Move data from other to this buffer.
void move(MemoryBuffer &other) void move(MemoryBuffer &other) {
{
Allocator &this_alloc = *this, &other_alloc = other; Allocator &this_alloc = *this, &other_alloc = other;
this_alloc = std::move(other_alloc); this_alloc = std::move(other_alloc);
this->size_ = other.size_; this->size_ = other.size_;
this->capacity_ = other.capacity_; this->capacity_ = other.capacity_;
if (other.ptr_ == other.data_) if (other.ptr_ == other.data_) {
{
this->ptr_ = data_; this->ptr_ = data_;
std::copy(other.data_, std::copy(other.data_,
other.data_ + this->size_, make_ptr(data_, this->capacity_)); other.data_ + this->size_, make_ptr(data_, this->capacity_));
} }
else else {
{
this->ptr_ = other.ptr_; this->ptr_ = other.ptr_;
// Set pointer to the inline array so that delete is not called // Set pointer to the inline array so that delete is not called
// when freeing. // when freeing.
...@@ -395,13 +420,11 @@ private: ...@@ -395,13 +420,11 @@ private:
} }
public: public:
MemoryBuffer(MemoryBuffer &&other) MemoryBuffer(MemoryBuffer &&other) {
{
move(other); move(other);
} }
MemoryBuffer &operator=(MemoryBuffer &&other) MemoryBuffer &operator=(MemoryBuffer &&other) {
{
assert(this != &other); assert(this != &other);
free(); free();
move(other); move(other);
...@@ -410,15 +433,13 @@ public: ...@@ -410,15 +433,13 @@ public:
#endif #endif
// Returns a copy of the allocator associated with this buffer. // Returns a copy of the allocator associated with this buffer.
Allocator get_allocator() const Allocator get_allocator() const {
{
return *this; return *this;
} }
}; };
template <typename T, std::size_t SIZE, typename Allocator> template <typename T, std::size_t SIZE, typename Allocator>
void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
{
std::size_t new_capacity = std::size_t new_capacity =
(std::max)(size, this->capacity_ + this->capacity_ / 2); (std::max)(size, this->capacity_ + this->capacity_ / 2);
T *new_ptr = this->allocate(new_capacity); T *new_ptr = this->allocate(new_capacity);
...@@ -438,8 +459,7 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) ...@@ -438,8 +459,7 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size)
#ifndef _MSC_VER #ifndef _MSC_VER
// Portable version of signbit. // Portable version of signbit.
inline int getsign(double x) inline int getsign(double x) {
{
// When compiled in C++11 mode signbit is no longer a macro but a function // When compiled in C++11 mode signbit is no longer a macro but a function
// defined in namespace std and the macro is undefined. // defined in namespace std and the macro is undefined.
# ifdef signbit # ifdef signbit
...@@ -451,27 +471,22 @@ inline int getsign(double x) ...@@ -451,27 +471,22 @@ inline int getsign(double x)
// Portable version of isinf. // Portable version of isinf.
# ifdef isinf # ifdef isinf
inline int isinfinity(double x) inline int isinfinity(double x) {
{
return isinf(x); return isinf(x);
} }
inline int isinfinity(long double x) inline int isinfinity(long double x) {
{
return isinf(x); return isinf(x);
} }
# else # else
inline int isinfinity(double x) inline int isinfinity(double x) {
{
return std::isinf(x); return std::isinf(x);
} }
inline int isinfinity(long double x) inline int isinfinity(long double x) {
{
return std::isinf(x); return std::isinf(x);
} }
# endif # endif
#else #else
inline int getsign(double value) inline int getsign(double value) {
{
if (value < 0) return 1; if (value < 0) return 1;
if (value == value) return 0; if (value == value) return 0;
int dec = 0, sign = 0; int dec = 0, sign = 0;
...@@ -479,27 +494,16 @@ inline int getsign(double value) ...@@ -479,27 +494,16 @@ inline int getsign(double value)
_ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign); _ecvt_s(buffer, sizeof(buffer), value, 0, &dec, &sign);
return sign; return sign;
} }
inline int isinfinity(double x) inline int isinfinity(double x) {
{
return !_finite(x); return !_finite(x);
} }
inline int isinfinity(long double x) {
return !_finite(static_cast<double>(x));
}
#endif #endif
template <typename T>
struct IsLongDouble
{
enum { VALUE = 0 };
};
template <>
struct IsLongDouble<long double>
{
enum { VALUE = 1 };
};
template <typename Char> template <typename Char>
class BasicCharTraits class BasicCharTraits {
{
public: public:
#if _SECURE_SCL #if _SECURE_SCL
typedef stdext::checked_array_iterator<Char*> CharPtr; typedef stdext::checked_array_iterator<Char*> CharPtr;
...@@ -512,17 +516,13 @@ template <typename Char> ...@@ -512,17 +516,13 @@ template <typename Char>
class CharTraits; class CharTraits;
template <> template <>
class CharTraits<char> : public BasicCharTraits<char> class CharTraits<char> : public BasicCharTraits<char> {
{
private: private:
// Conversion from wchar_t to char is not allowed. // Conversion from wchar_t to char is not allowed.
static char convert(wchar_t); static char convert(wchar_t);
public: public:
typedef const wchar_t *UnsupportedStrType; static char convert(char value) {
static char convert(char value)
{
return value; return value;
} }
...@@ -533,17 +533,12 @@ public: ...@@ -533,17 +533,12 @@ public:
}; };
template <> template <>
class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> class CharTraits<wchar_t> : public BasicCharTraits<wchar_t> {
{
public: public:
typedef const char *UnsupportedStrType; static wchar_t convert(char value) {
static wchar_t convert(char value)
{
return value; return value;
} }
static wchar_t convert(wchar_t value) static wchar_t convert(wchar_t value) {
{
return value; return value;
} }
...@@ -554,21 +549,17 @@ public: ...@@ -554,21 +549,17 @@ public:
// Checks if a number is negative - used to avoid warnings. // Checks if a number is negative - used to avoid warnings.
template <bool IsSigned> template <bool IsSigned>
struct SignChecker struct SignChecker {
{
template <typename T> template <typename T>
static bool is_negative(T value) static bool is_negative(T value) {
{
return value < 0; return value < 0;
} }
}; };
template <> template <>
struct SignChecker<false> struct SignChecker<false> {
{
template <typename T> template <typename T>
static bool is_negative(T) static bool is_negative(T) {
{
return false; return false;
} }
}; };
...@@ -576,27 +567,23 @@ struct SignChecker<false> ...@@ -576,27 +567,23 @@ struct SignChecker<false>
// Returns true if value is negative, false otherwise. // Returns true if value is negative, false otherwise.
// Same as (value < 0) but doesn't produce warnings if T is an unsigned type. // Same as (value < 0) but doesn't produce warnings if T is an unsigned type.
template <typename T> template <typename T>
inline bool is_negative(T value) inline bool is_negative(T value) {
{
return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value); return SignChecker<std::numeric_limits<T>::is_signed>::is_negative(value);
} }
// Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise. // Selects uint32_t if FitsIn32Bits is true, uint64_t otherwise.
template <bool FitsIn32Bits> template <bool FitsIn32Bits>
struct TypeSelector struct TypeSelector {
{
typedef uint32_t Type; typedef uint32_t Type;
}; };
template <> template <>
struct TypeSelector<false> struct TypeSelector<false> {
{
typedef uint64_t Type; typedef uint64_t Type;
}; };
template <typename T> template <typename T>
struct IntTraits struct IntTraits {
{
// Smallest of uint32_t and uint64_t that is large enough to represent // Smallest of uint32_t and uint64_t that is large enough to represent
// all values of T. // all values of T.
typedef typename typedef typename
...@@ -605,8 +592,7 @@ struct IntTraits ...@@ -605,8 +592,7 @@ struct IntTraits
// MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T. // MakeUnsigned<T>::Type gives an unsigned type corresponding to integer type T.
template <typename T> template <typename T>
struct MakeUnsigned struct MakeUnsigned {
{
typedef T Type; typedef T Type;
}; };
...@@ -626,8 +612,7 @@ void report_unknown_type(char code, const char *type); ...@@ -626,8 +612,7 @@ void report_unknown_type(char code, const char *type);
// Static data is placed in this class template to allow header-only // Static data is placed in this class template to allow header-only
// configuration. // configuration.
template <typename T = void> template <typename T = void>
struct BasicData struct BasicData {
{
static const uint32_t POWERS_OF_10_32[]; static const uint32_t POWERS_OF_10_32[];
static const uint64_t POWERS_OF_10_64[]; static const uint64_t POWERS_OF_10_64[];
static const char DIGITS[]; static const char DIGITS[];
...@@ -635,31 +620,28 @@ struct BasicData ...@@ -635,31 +620,28 @@ struct BasicData
typedef BasicData<> Data; typedef BasicData<> Data;
#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
# define FMT_BUILTIN_CLZ(n) __builtin_clz(n)
#endif
#if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll) #if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clzll)
# define FMT_BUILTIN_CLZLL(n) __builtin_clzll(n)
#endif
#ifdef FMT_BUILTIN_CLZLL
// Returns the number of decimal digits in n. Leading zeros are not counted // Returns the number of decimal digits in n. Leading zeros are not counted
// except for n == 0 in which case count_digits returns 1. // except for n == 0 in which case count_digits returns 1.
inline unsigned count_digits(uint64_t n) inline unsigned count_digits(uint64_t n) {
{
// Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10 // Based on http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
// and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits. // and the benchmark https://github.com/localvoid/cxx-benchmark-count-digits.
unsigned t = (64 - __builtin_clzll(n | 1)) * 1233 >> 12; unsigned t = (64 - FMT_BUILTIN_CLZLL(n | 1)) * 1233 >> 12;
return t - (n < Data::POWERS_OF_10_64[t]) + 1; return t - (n < Data::POWERS_OF_10_64[t]) + 1;
} }
# if FMT_GCC_VERSION >= 400 || FMT_HAS_BUILTIN(__builtin_clz)
// Optional version of count_digits for better performance on 32-bit platforms.
inline unsigned count_digits(uint32_t n)
{
uint32_t t = (32 - __builtin_clz(n | 1)) * 1233 >> 12;
return t - (n < Data::POWERS_OF_10_32[t]) + 1;
}
# endif
#else #else
// Fallback version of count_digits used when __builtin_clz is not available. // Fallback version of count_digits used when __builtin_clz is not available.
inline unsigned count_digits(uint64_t n) inline unsigned count_digits(uint64_t n) {
{
unsigned count = 1; unsigned count = 1;
for (;;) for (;;) {
{
// Integer division is slow so do it for a group of four digits instead // Integer division is slow so do it for a group of four digits instead
// of for every digit. The idea comes from the talk by Alexandrescu // of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison. // "Three Optimization Tips for C++". See speed-test for a comparison.
...@@ -673,13 +655,19 @@ inline unsigned count_digits(uint64_t n) ...@@ -673,13 +655,19 @@ inline unsigned count_digits(uint64_t n)
} }
#endif #endif
#ifdef FMT_BUILTIN_CLZ
// Optional version of count_digits for better performance on 32-bit platforms.
inline unsigned count_digits(uint32_t n) {
uint32_t t = (32 - FMT_BUILTIN_CLZ(n | 1)) * 1233 >> 12;
return t - (n < Data::POWERS_OF_10_32[t]) + 1;
}
#endif
// Formats a decimal unsigned integer value writing into buffer. // Formats a decimal unsigned integer value writing into buffer.
template <typename UInt, typename Char> template <typename UInt, typename Char>
inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
{
--num_digits; --num_digits;
while (value >= 100) while (value >= 100) {
{
// Integer division is slow so do it for a group of two digits instead // Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu // of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison. // "Three Optimization Tips for C++". See speed-test for a comparison.
...@@ -689,8 +677,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) ...@@ -689,8 +677,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
buffer[num_digits - 1] = Data::DIGITS[index]; buffer[num_digits - 1] = Data::DIGITS[index];
num_digits -= 2; num_digits -= 2;
} }
if (value < 10) if (value < 10) {
{
*buffer = static_cast<char>('0' + value); *buffer = static_cast<char>('0' + value);
return; return;
} }
...@@ -702,55 +689,45 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) ...@@ -702,55 +689,45 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits)
#ifdef _WIN32 #ifdef _WIN32
// A converter from UTF-8 to UTF-16. // A converter from UTF-8 to UTF-16.
// It is only provided for Windows since other systems support UTF-8 natively. // It is only provided for Windows since other systems support UTF-8 natively.
class UTF8ToUTF16 class UTF8ToUTF16 {
{
private: private:
MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_; MemoryBuffer<wchar_t, INLINE_BUFFER_SIZE> buffer_;
public: public:
explicit UTF8ToUTF16(StringRef s); explicit UTF8ToUTF16(StringRef s);
operator WStringRef() const operator WStringRef() const {
{
return WStringRef(&buffer_[0], size()); return WStringRef(&buffer_[0], size());
} }
size_t size() const size_t size() const {
{
return buffer_.size() - 1; return buffer_.size() - 1;
} }
const wchar_t *c_str() const const wchar_t *c_str() const {
{
return &buffer_[0]; return &buffer_[0];
} }
std::wstring str() const std::wstring str() const {
{
return std::wstring(&buffer_[0], size()); return std::wstring(&buffer_[0], size());
} }
}; };
// A converter from UTF-16 to UTF-8. // A converter from UTF-16 to UTF-8.
// It is only provided for Windows since other systems support UTF-8 natively. // It is only provided for Windows since other systems support UTF-8 natively.
class UTF16ToUTF8 class UTF16ToUTF8 {
{
private: private:
MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_; MemoryBuffer<char, INLINE_BUFFER_SIZE> buffer_;
public: public:
UTF16ToUTF8() {} UTF16ToUTF8() {}
explicit UTF16ToUTF8(WStringRef s); explicit UTF16ToUTF8(WStringRef s);
operator StringRef() const operator StringRef() const {
{
return StringRef(&buffer_[0], size()); return StringRef(&buffer_[0], size());
} }
size_t size() const size_t size() const {
{
return buffer_.size() - 1; return buffer_.size() - 1;
} }
const char *c_str() const const char *c_str() const {
{
return &buffer_[0]; return &buffer_[0];
} }
std::string str() const std::string str() const {
{
return std::string(&buffer_[0], size()); return std::string(&buffer_[0], size());
} }
...@@ -762,34 +739,30 @@ public: ...@@ -762,34 +739,30 @@ public:
#endif #endif
void format_system_error(fmt::Writer &out, int error_code, void format_system_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT(true); fmt::StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32 #ifdef _WIN32
void format_windows_error(fmt::Writer &out, int error_code, void format_windows_error(fmt::Writer &out, int error_code,
fmt::StringRef message) FMT_NOEXCEPT(true); fmt::StringRef message) FMT_NOEXCEPT;
#endif #endif
// Computes max(Arg, 1) at compile time. It is used to avoid errors about // Computes max(Arg, 1) at compile time. It is used to avoid errors about
// allocating an array of 0 size. // allocating an array of 0 size.
template <unsigned Arg> template <unsigned Arg>
struct NonZero struct NonZero {
{
enum { VALUE = Arg }; enum { VALUE = Arg };
}; };
template <> template <>
struct NonZero<0> struct NonZero<0> {
{
enum { VALUE = 1 }; enum { VALUE = 1 };
}; };
// The value of a formatting argument. It is a POD type to allow storage in // The value of a formatting argument. It is a POD type to allow storage in
// internal::MemoryBuffer. // internal::MemoryBuffer.
struct Value struct Value {
{
template <typename Char> template <typename Char>
struct StringValue struct StringValue {
{
const Char *value; const Char *value;
std::size_t size; std::size_t size;
}; };
...@@ -797,14 +770,12 @@ struct Value ...@@ -797,14 +770,12 @@ struct Value
typedef void(*FormatFunc)( typedef void(*FormatFunc)(
void *formatter, const void *arg, void *format_str_ptr); void *formatter, const void *arg, void *format_str_ptr);
struct CustomValue struct CustomValue {
{
const void *value; const void *value;
FormatFunc format; FormatFunc format;
}; };
union union {
{
int int_value; int int_value;
unsigned uint_value; unsigned uint_value;
LongLong long_long_value; LongLong long_long_value;
...@@ -820,10 +791,8 @@ struct Value ...@@ -820,10 +791,8 @@ struct Value
}; };
}; };
struct Arg : Value struct Arg : Value {
{ enum Type {
enum Type
{
NONE, NONE,
// Integer types should go first, // Integer types should go first,
INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR, INT, UINT, LONG_LONG, ULONG_LONG, CHAR, LAST_INTEGER_TYPE = CHAR,
...@@ -834,10 +803,26 @@ struct Arg : Value ...@@ -834,10 +803,26 @@ struct Arg : Value
Type type; Type type;
}; };
template <typename T>
struct None {};
// A helper class template to enable or disable overloads taking wide
// characters and strings in MakeValue.
template <typename T, typename Char>
struct WCharHelper {
typedef None<T> Supported;
typedef T Unsupported;
};
template <typename T>
struct WCharHelper<T, wchar_t> {
typedef T Supported;
typedef None<T> Unsupported;
};
// Makes a Value object from any type. // Makes a Value object from any type.
template <typename Char> template <typename Char>
class MakeValue : public Value class MakeValue : public Value {
{
private: private:
// The following two methods are private to disallow formatting of // The following two methods are private to disallow formatting of
// arbitrary pointers. If you want to output a pointer cast it to // arbitrary pointers. If you want to output a pointer cast it to
...@@ -849,15 +834,22 @@ private: ...@@ -849,15 +834,22 @@ private:
template <typename T> template <typename T>
MakeValue(T *value); MakeValue(T *value);
void set_string(StringRef str) // The following methods are private to disallow formatting of wide
{ // characters and strings into narrow strings as in
// fmt::format("{}", L"test");
// To fix this, use a wide format string: fmt::format(L"{}", L"test").
MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported);
MakeValue(typename WCharHelper<wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
MakeValue(typename WCharHelper<WStringRef, Char>::Unsupported);
void set_string(StringRef str) {
string.value = str.c_str(); string.value = str.c_str();
string.size = str.size(); string.size = str.size();
} }
void set_string(WStringRef str) void set_string(WStringRef str) {
{
CharTraits<Char>::convert(wchar_t());
wstring.value = str.c_str(); wstring.value = str.c_str();
wstring.size = str.size(); wstring.size = str.size();
} }
...@@ -865,8 +857,7 @@ private: ...@@ -865,8 +857,7 @@ private:
// Formats an argument of a custom type, such as a user-defined class. // Formats an argument of a custom type, such as a user-defined class.
template <typename T> template <typename T>
static void format_custom_arg( static void format_custom_arg(
void *formatter, const void *arg, void *format_str_ptr) void *formatter, const void *arg, void *format_str_ptr) {
{
format(*static_cast<BasicFormatter<Char>*>(formatter), format(*static_cast<BasicFormatter<Char>*>(formatter),
*static_cast<const Char**>(format_str_ptr), *static_cast<const Char**>(format_str_ptr),
*static_cast<const T*>(arg)); *static_cast<const T*>(arg));
...@@ -885,8 +876,7 @@ public: ...@@ -885,8 +876,7 @@ public:
FMT_MAKE_VALUE(int, int_value, INT) FMT_MAKE_VALUE(int, int_value, INT)
FMT_MAKE_VALUE(unsigned, uint_value, UINT) FMT_MAKE_VALUE(unsigned, uint_value, UINT)
MakeValue(long value) MakeValue(long value) {
{
// To minimize the number of types we need to deal with, long is // To minimize the number of types we need to deal with, long is
// translated either to int or to long long depending on its size. // translated either to int or to long long depending on its size.
if (sizeof(long) == sizeof(int)) if (sizeof(long) == sizeof(int))
...@@ -894,20 +884,17 @@ public: ...@@ -894,20 +884,17 @@ public:
else else
long_long_value = value; long_long_value = value;
} }
static uint64_t type(long) static uint64_t type(long) {
{
return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG; return sizeof(long) == sizeof(int) ? Arg::INT : Arg::LONG_LONG;
} }
MakeValue(unsigned long value) MakeValue(unsigned long value) {
{
if (sizeof(unsigned long) == sizeof(unsigned)) if (sizeof(unsigned long) == sizeof(unsigned))
uint_value = static_cast<unsigned>(value); uint_value = static_cast<unsigned>(value);
else else
ulong_long_value = value; ulong_long_value = value;
} }
static uint64_t type(unsigned long) static uint64_t type(unsigned long) {
{
return sizeof(unsigned long) == sizeof(unsigned) ? return sizeof(unsigned long) == sizeof(unsigned) ?
Arg::UINT : Arg::ULONG_LONG; Arg::UINT : Arg::ULONG_LONG;
} }
...@@ -921,12 +908,10 @@ public: ...@@ -921,12 +908,10 @@ public:
FMT_MAKE_VALUE(unsigned char, int_value, CHAR) FMT_MAKE_VALUE(unsigned char, int_value, CHAR)
FMT_MAKE_VALUE(char, int_value, CHAR) FMT_MAKE_VALUE(char, int_value, CHAR)
MakeValue(wchar_t value) MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
{ int_value = value;
int_value = internal::CharTraits<Char>::convert(value);
} }
static uint64_t type(wchar_t) static uint64_t type(wchar_t) {
{
return Arg::CHAR; return Arg::CHAR;
} }
...@@ -941,23 +926,27 @@ public: ...@@ -941,23 +926,27 @@ public:
FMT_MAKE_STR_VALUE(const std::string &, STRING) FMT_MAKE_STR_VALUE(const std::string &, STRING)
FMT_MAKE_STR_VALUE(StringRef, STRING) FMT_MAKE_STR_VALUE(StringRef, STRING)
FMT_MAKE_STR_VALUE(wchar_t *, WSTRING) #define FMT_MAKE_WSTR_VALUE(Type, TYPE) \
FMT_MAKE_STR_VALUE(const wchar_t *, WSTRING) MakeValue(typename WCharHelper<Type, Char>::Supported value) { \
FMT_MAKE_STR_VALUE(const std::wstring &, WSTRING) set_string(value); \
FMT_MAKE_STR_VALUE(WStringRef, WSTRING) } \
static uint64_t type(Type) { return Arg::TYPE; }
FMT_MAKE_WSTR_VALUE(wchar_t *, WSTRING)
FMT_MAKE_WSTR_VALUE(const wchar_t *, WSTRING)
FMT_MAKE_WSTR_VALUE(const std::wstring &, WSTRING)
FMT_MAKE_WSTR_VALUE(WStringRef, WSTRING)
FMT_MAKE_VALUE(void *, pointer, POINTER) FMT_MAKE_VALUE(void *, pointer, POINTER)
FMT_MAKE_VALUE(const void *, pointer, POINTER) FMT_MAKE_VALUE(const void *, pointer, POINTER)
template <typename T> template <typename T>
MakeValue(const T &value) MakeValue(const T &value) {
{
custom.value = &value; custom.value = &value;
custom.format = &format_custom_arg<T>; custom.format = &format_custom_arg<T>;
} }
template <typename T> template <typename T>
static uint64_t type(const T &) static uint64_t type(const T &) {
{
return Arg::CUSTOM; return Arg::CUSTOM;
} }
}; };
...@@ -985,78 +974,61 @@ public: ...@@ -985,78 +974,61 @@ public:
// ArgVisitor uses the curiously recurring template pattern: // ArgVisitor uses the curiously recurring template pattern:
// http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern // http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
template <typename Impl, typename Result> template <typename Impl, typename Result>
class ArgVisitor class ArgVisitor {
{
public: public:
Result visit_unhandled_arg() Result visit_unhandled_arg() {
{
return Result(); return Result();
} }
Result visit_int(int value) Result visit_int(int value) {
{
return FMT_DISPATCH(visit_any_int(value)); return FMT_DISPATCH(visit_any_int(value));
} }
Result visit_long_long(LongLong value) Result visit_long_long(LongLong value) {
{
return FMT_DISPATCH(visit_any_int(value)); return FMT_DISPATCH(visit_any_int(value));
} }
Result visit_uint(unsigned value) Result visit_uint(unsigned value) {
{
return FMT_DISPATCH(visit_any_int(value)); return FMT_DISPATCH(visit_any_int(value));
} }
Result visit_ulong_long(ULongLong value) Result visit_ulong_long(ULongLong value) {
{
return FMT_DISPATCH(visit_any_int(value)); return FMT_DISPATCH(visit_any_int(value));
} }
Result visit_char(int value) Result visit_char(int value) {
{
return FMT_DISPATCH(visit_any_int(value)); return FMT_DISPATCH(visit_any_int(value));
} }
template <typename T> template <typename T>
Result visit_any_int(T) Result visit_any_int(T) {
{
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_double(double value) Result visit_double(double value) {
{
return FMT_DISPATCH(visit_any_double(value)); return FMT_DISPATCH(visit_any_double(value));
} }
Result visit_long_double(long double value) Result visit_long_double(long double value) {
{
return FMT_DISPATCH(visit_any_double(value)); return FMT_DISPATCH(visit_any_double(value));
} }
template <typename T> template <typename T>
Result visit_any_double(T) Result visit_any_double(T) {
{
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_string(Arg::StringValue<char>) Result visit_string(Arg::StringValue<char>) {
{
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_wstring(Arg::StringValue<wchar_t>) Result visit_wstring(Arg::StringValue<wchar_t>) {
{
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_pointer(const void *) Result visit_pointer(const void *) {
{
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit_custom(Arg::CustomValue) Result visit_custom(Arg::CustomValue) {
{
return FMT_DISPATCH(visit_unhandled_arg()); return FMT_DISPATCH(visit_unhandled_arg());
} }
Result visit(const Arg &arg) Result visit(const Arg &arg) {
{ switch (arg.type) {
switch (arg.type)
{
default: default:
assert(false); assert(false);
// Fall through. return Result();
case Arg::INT: case Arg::INT:
return FMT_DISPATCH(visit_int(arg.int_value)); return FMT_DISPATCH(visit_int(arg.int_value));
case Arg::UINT: case Arg::UINT:
...@@ -1071,8 +1043,7 @@ public: ...@@ -1071,8 +1043,7 @@ public:
return FMT_DISPATCH(visit_long_double(arg.long_double_value)); return FMT_DISPATCH(visit_long_double(arg.long_double_value));
case Arg::CHAR: case Arg::CHAR:
return FMT_DISPATCH(visit_char(arg.int_value)); return FMT_DISPATCH(visit_char(arg.int_value));
case Arg::CSTRING: case Arg::CSTRING: {
{
Value::StringValue<char> str = arg.string; Value::StringValue<char> str = arg.string;
str.size = 0; str.size = 0;
return FMT_DISPATCH(visit_string(str)); return FMT_DISPATCH(visit_string(str));
...@@ -1089,8 +1060,7 @@ public: ...@@ -1089,8 +1060,7 @@ public:
} }
}; };
class RuntimeError : public std::runtime_error class RuntimeError : public std::runtime_error {
{
protected: protected:
RuntimeError() : std::runtime_error("") {} RuntimeError() : std::runtime_error("") {}
}; };
...@@ -1102,8 +1072,7 @@ class ArgFormatter; ...@@ -1102,8 +1072,7 @@ class ArgFormatter;
/** /**
An argument list. An argument list.
*/ */
class ArgList class ArgList {
{
private: private:
uint64_t types_; uint64_t types_;
const internal::Value *values_; const internal::Value *values_;
...@@ -1119,12 +1088,10 @@ public: ...@@ -1119,12 +1088,10 @@ public:
/** /**
Returns the argument at specified index. Returns the argument at specified index.
*/ */
internal::Arg operator[](unsigned index) const internal::Arg operator[](unsigned index) const {
{
using internal::Arg; using internal::Arg;
Arg arg; Arg arg;
if (index >= MAX_ARGS) if (index >= MAX_ARGS) {
{
arg.type = Arg::NONE; arg.type = Arg::NONE;
return arg; return arg;
} }
...@@ -1133,8 +1100,7 @@ public: ...@@ -1133,8 +1100,7 @@ public:
Arg::Type type = Arg::Type type =
static_cast<Arg::Type>((types_ & (mask << shift)) >> shift); static_cast<Arg::Type>((types_ & (mask << shift)) >> shift);
arg.type = type; arg.type = type;
if (type != Arg::NONE) if (type != Arg::NONE) {
{
internal::Value &value = arg; internal::Value &value = arg;
value = values_[index]; value = values_[index];
} }
...@@ -1144,11 +1110,9 @@ public: ...@@ -1144,11 +1110,9 @@ public:
struct FormatSpec; struct FormatSpec;
namespace internal namespace internal {
{
class FormatterBase class FormatterBase {
{
private: private:
ArgList args_; ArgList args_;
int next_arg_index_; int next_arg_index_;
...@@ -1157,8 +1121,7 @@ private: ...@@ -1157,8 +1121,7 @@ private:
Arg do_get_arg(unsigned arg_index, const char *&error); Arg do_get_arg(unsigned arg_index, const char *&error);
protected: protected:
void set_args(const ArgList &args) void set_args(const ArgList &args) {
{
args_ = args; args_ = args;
next_arg_index_ = 0; next_arg_index_ = 0;
} }
...@@ -1171,8 +1134,7 @@ protected: ...@@ -1171,8 +1134,7 @@ protected:
Arg get_arg(unsigned arg_index, const char *&error); Arg get_arg(unsigned arg_index, const char *&error);
template <typename Char> template <typename Char>
void write(BasicWriter<Char> &w, const Char *start, const Char *end) void write(BasicWriter<Char> &w, const Char *start, const Char *end) {
{
if (start != end) if (start != end)
w << BasicStringRef<Char>(start, end - start); w << BasicStringRef<Char>(start, end - start);
} }
...@@ -1180,8 +1142,7 @@ protected: ...@@ -1180,8 +1142,7 @@ protected:
// A printf formatter. // A printf formatter.
template <typename Char> template <typename Char>
class PrintfFormatter : private FormatterBase class PrintfFormatter : private FormatterBase {
{
private: private:
void parse_flags(FormatSpec &spec, const Char *&s); void parse_flags(FormatSpec &spec, const Char *&s);
...@@ -1195,26 +1156,26 @@ private: ...@@ -1195,26 +1156,26 @@ private:
public: public:
void format(BasicWriter<Char> &writer, void format(BasicWriter<Char> &writer,
BasicStringRef<Char> format, const ArgList &args); BasicStringRef<Char> format_str, const ArgList &args);
}; };
} // namespace internal } // namespace internal
// A formatter. // A formatter.
template <typename Char> template <typename Char>
class BasicFormatter : private internal::FormatterBase class BasicFormatter : private internal::FormatterBase {
{
private: private:
BasicWriter<Char> &writer_; BasicWriter<Char> &writer_;
const Char *start_; const Char *start_;
FMT_DISALLOW_COPY_AND_ASSIGN(BasicFormatter);
// Parses argument index and returns corresponding argument. // Parses argument index and returns corresponding argument.
internal::Arg parse_arg_index(const Char *&s); internal::Arg parse_arg_index(const Char *&s);
public: public:
explicit BasicFormatter(BasicWriter<Char> &w) : writer_(w) {} explicit BasicFormatter(BasicWriter<Char> &w) : writer_(w) {}
BasicWriter<Char> &writer() BasicWriter<Char> &writer() {
{
return writer_; return writer_;
} }
...@@ -1223,14 +1184,12 @@ public: ...@@ -1223,14 +1184,12 @@ public:
const Char *format(const Char *&format_str, const internal::Arg &arg); const Char *format(const Char *&format_str, const internal::Arg &arg);
}; };
enum Alignment enum Alignment {
{
ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC ALIGN_DEFAULT, ALIGN_LEFT, ALIGN_RIGHT, ALIGN_CENTER, ALIGN_NUMERIC
}; };
// Flags. // Flags.
enum enum {
{
SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8, SIGN_FLAG = 1, PLUS_FLAG = 2, MINUS_FLAG = 4, HASH_FLAG = 8,
CHAR_FLAG = 0x10 // Argument has char type - used in error reporting. CHAR_FLAG = 0x10 // Argument has char type - used in error reporting.
}; };
...@@ -1240,37 +1199,29 @@ struct EmptySpec {}; ...@@ -1240,37 +1199,29 @@ struct EmptySpec {};
// A type specifier. // A type specifier.
template <char TYPE> template <char TYPE>
struct TypeSpec : EmptySpec struct TypeSpec : EmptySpec {
{ Alignment align() const {
Alignment align() const
{
return ALIGN_DEFAULT; return ALIGN_DEFAULT;
} }
unsigned width() const unsigned width() const {
{
return 0; return 0;
} }
int precision() const int precision() const {
{
return -1; return -1;
} }
bool flag(unsigned) const bool flag(unsigned) const {
{
return false; return false;
} }
char type() const char type() const {
{
return TYPE; return TYPE;
} }
char fill() const char fill() const {
{
return ' '; return ' ';
} }
}; };
// A width specifier. // A width specifier.
struct WidthSpec struct WidthSpec {
{
unsigned width_; unsigned width_;
// Fill is always wchar_t and cast to char if necessary to avoid having // Fill is always wchar_t and cast to char if necessary to avoid having
// two specialization of WidthSpec and its subclasses. // two specialization of WidthSpec and its subclasses.
...@@ -1278,54 +1229,45 @@ struct WidthSpec ...@@ -1278,54 +1229,45 @@ struct WidthSpec
WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {} WidthSpec(unsigned width, wchar_t fill) : width_(width), fill_(fill) {}
unsigned width() const unsigned width() const {
{
return width_; return width_;
} }
wchar_t fill() const wchar_t fill() const {
{
return fill_; return fill_;
} }
}; };
// An alignment specifier. // An alignment specifier.
struct AlignSpec : WidthSpec struct AlignSpec : WidthSpec {
{
Alignment align_; Alignment align_;
AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT) AlignSpec(unsigned width, wchar_t fill, Alignment align = ALIGN_DEFAULT)
: WidthSpec(width, fill), align_(align) {} : WidthSpec(width, fill), align_(align) {}
Alignment align() const Alignment align() const {
{
return align_; return align_;
} }
int precision() const int precision() const {
{
return -1; return -1;
} }
}; };
// An alignment and type specifier. // An alignment and type specifier.
template <char TYPE> template <char TYPE>
struct AlignTypeSpec : AlignSpec struct AlignTypeSpec : AlignSpec {
{
AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {} AlignTypeSpec(unsigned width, wchar_t fill) : AlignSpec(width, fill) {}
bool flag(unsigned) const bool flag(unsigned) const {
{
return false; return false;
} }
char type() const char type() const {
{
return TYPE; return TYPE;
} }
}; };
// A full format specifier. // A full format specifier.
struct FormatSpec : AlignSpec struct FormatSpec : AlignSpec {
{
unsigned flags_; unsigned flags_;
int precision_; int precision_;
char type_; char type_;
...@@ -1334,41 +1276,35 @@ struct FormatSpec : AlignSpec ...@@ -1334,41 +1276,35 @@ struct FormatSpec : AlignSpec
unsigned width = 0, char type = 0, wchar_t fill = ' ') unsigned width = 0, char type = 0, wchar_t fill = ' ')
: AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {} : AlignSpec(width, fill), flags_(0), precision_(-1), type_(type) {}
bool flag(unsigned f) const bool flag(unsigned f) const {
{
return (flags_ & f) != 0; return (flags_ & f) != 0;
} }
int precision() const int precision() const {
{
return precision_; return precision_;
} }
char type() const char type() const {
{
return type_; return type_;
} }
}; };
// An integer format specifier. // An integer format specifier.
template <typename T, typename SpecT = TypeSpec<0>, typename Char = char> template <typename T, typename SpecT = TypeSpec<0>, typename Char = char>
class IntFormatSpec : public SpecT class IntFormatSpec : public SpecT {
{
private: private:
T value_; T value_;
public: public:
IntFormatSpec(T value, const SpecT &spec = SpecT()) IntFormatSpec(T val, const SpecT &spec = SpecT())
: SpecT(spec), value_(value) {} : SpecT(spec), value_(val) {}
T value() const T value() const {
{
return value_; return value_;
} }
}; };
// A string format specifier. // A string format specifier.
template <typename T> template <typename T>
class StrFormatSpec : public AlignSpec class StrFormatSpec : public AlignSpec {
{
private: private:
const T *str_; const T *str_;
...@@ -1376,8 +1312,7 @@ public: ...@@ -1376,8 +1312,7 @@ public:
StrFormatSpec(const T *str, unsigned width, wchar_t fill) StrFormatSpec(const T *str, unsigned width, wchar_t fill)
: AlignSpec(width, fill), str_(str) {} : AlignSpec(width, fill), str_(str) {}
const T *str() const const T *str() const {
{
return str_; return str_;
} }
}; };
...@@ -1492,14 +1427,12 @@ std::string s = str(MemoryWriter() << pad("abc", 8)); ...@@ -1492,14 +1427,12 @@ std::string s = str(MemoryWriter() << pad("abc", 8));
*/ */
template <typename Char> template <typename Char>
inline StrFormatSpec<Char> pad( inline StrFormatSpec<Char> pad(
const Char *str, unsigned width, Char fill = ' ') const Char *str, unsigned width, Char fill = ' ') {
{
return StrFormatSpec<Char>(str, width, fill); return StrFormatSpec<Char>(str, width, fill);
} }
inline StrFormatSpec<wchar_t> pad( inline StrFormatSpec<wchar_t> pad(
const wchar_t *str, unsigned width, char fill = ' ') const wchar_t *str, unsigned width, char fill = ' ') {
{
return StrFormatSpec<wchar_t>(str, width, fill); return StrFormatSpec<wchar_t>(str, width, fill);
} }
...@@ -1522,29 +1455,24 @@ inline StrFormatSpec<wchar_t> pad( ...@@ -1522,29 +1455,24 @@ inline StrFormatSpec<wchar_t> pad(
# define FMT_GEN14(f) FMT_GEN13(f), f(13) # define FMT_GEN14(f) FMT_GEN13(f), f(13)
# define FMT_GEN15(f) FMT_GEN14(f), f(14) # define FMT_GEN15(f) FMT_GEN14(f), f(14)
namespace internal namespace internal {
{ inline uint64_t make_type() {
inline uint64_t make_type()
{
return 0; return 0;
} }
template <typename T> template <typename T>
inline uint64_t make_type(const T &arg) inline uint64_t make_type(const T &arg) {
{
return MakeValue<char>::type(arg); return MakeValue<char>::type(arg);
} }
#if FMT_USE_VARIADIC_TEMPLATES #if FMT_USE_VARIADIC_TEMPLATES
template <typename Arg, typename... Args> template <typename Arg, typename... Args>
inline uint64_t make_type(const Arg &first, const Args & ... tail) inline uint64_t make_type(const Arg &first, const Args & ... tail) {
{
return make_type(first) | (make_type(tail...) << 4); return make_type(first) | (make_type(tail...) << 4);
} }
#else #else
struct ArgType struct ArgType {
{
uint64_t type; uint64_t type;
ArgType() : type(0) {} ArgType() : type(0) {}
...@@ -1555,8 +1483,7 @@ struct ArgType ...@@ -1555,8 +1483,7 @@ struct ArgType
# define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType() # define FMT_ARG_TYPE_DEFAULT(n) ArgType t##n = ArgType()
inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) {
{
return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) | return t0.type | (t1.type << 4) | (t2.type << 8) | (t3.type << 12) |
(t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) | (t4.type << 16) | (t5.type << 20) | (t6.type << 24) | (t7.type << 28) |
(t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) | (t8.type << 32) | (t9.type << 36) | (t10.type << 40) | (t11.type << 44) |
...@@ -1612,6 +1539,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) ...@@ -1612,6 +1539,7 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
// Emulates a variadic function returning void on a pre-C++11 compiler. // Emulates a variadic function returning void on a pre-C++11 compiler.
# define FMT_VARIADIC_VOID(func, arg_type) \ # define FMT_VARIADIC_VOID(func, arg_type) \
inline void func(arg_type arg) { func(arg, fmt::ArgList()); } \
FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \ FMT_WRAP1(func, arg_type, 1) FMT_WRAP1(func, arg_type, 2) \
FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \ FMT_WRAP1(func, arg_type, 3) FMT_WRAP1(func, arg_type, 4) \
FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \ FMT_WRAP1(func, arg_type, 5) FMT_WRAP1(func, arg_type, 6) \
...@@ -1666,10 +1594,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT)) ...@@ -1666,10 +1594,9 @@ inline uint64_t make_type(FMT_GEN15(FMT_ARG_TYPE_DEFAULT))
An error returned by an operating system or a language runtime, An error returned by an operating system or a language runtime,
for example a file opening error. for example a file opening error.
*/ */
class SystemError : public internal::RuntimeError class SystemError : public internal::RuntimeError {
{
private: private:
void init(int error_code, StringRef format_str, ArgList args); void init(int err_code, StringRef format_str, ArgList args);
protected: protected:
int error_code_; int error_code_;
...@@ -1681,21 +1608,35 @@ protected: ...@@ -1681,21 +1608,35 @@ protected:
public: public:
/** /**
\rst \rst
Constructs a :cpp:class:`fmt::SystemError` object with the description Constructs a :class:`fmt::SystemError` object with the description
of the form "*<message>*: *<system-message>*", where *<message>* is the of the form
formatted message and *<system-message>* is the system message corresponding
to the error code. .. parsed-literal::
*<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is
the system message corresponding to the error code.
*error_code* is a system error code as given by ``errno``. *error_code* is a system error code as given by ``errno``.
If *error_code* is not a valid error code such as -1, the system message
may look like "Unknown error -1" and is platform-dependent.
**Example**::
// This throws a SystemError with the description
// cannot open file 'madeup': No such file or directory
// or similar (system message may vary).
const char *filename = "madeup";
std::FILE *file = std::fopen(filename, "r");
if (!file)
throw fmt::SystemError(errno, "cannot open file '{}'", filename);
\endrst \endrst
*/ */
SystemError(int error_code, StringRef message) SystemError(int error_code, StringRef message) {
{
init(error_code, message, ArgList()); init(error_code, message, ArgList());
} }
FMT_VARIADIC_CTOR(SystemError, init, int, StringRef) FMT_VARIADIC_CTOR(SystemError, init, int, StringRef)
int error_code() const int error_code() const {
{
return error_code_; return error_code_;
} }
}; };
...@@ -1704,7 +1645,7 @@ public: ...@@ -1704,7 +1645,7 @@ public:
\rst \rst
This template provides operations for formatting and writing data into This template provides operations for formatting and writing data into
a character stream. The output is stored in a buffer provided by a subclass a character stream. The output is stored in a buffer provided by a subclass
such as :cpp:class:`fmt::BasicMemoryWriter`. such as :class:`fmt::BasicMemoryWriter`.
You can use one of the following typedefs for common character types: You can use one of the following typedefs for common character types:
...@@ -1719,8 +1660,7 @@ You can use one of the following typedefs for common character types: ...@@ -1719,8 +1660,7 @@ You can use one of the following typedefs for common character types:
\endrst \endrst
*/ */
template <typename Char> template <typename Char>
class BasicWriter class BasicWriter {
{
private: private:
// Output buffer. // Output buffer.
internal::Buffer<Char> &buffer_; internal::Buffer<Char> &buffer_;
...@@ -1731,13 +1671,11 @@ private: ...@@ -1731,13 +1671,11 @@ private:
#if _SECURE_SCL #if _SECURE_SCL
// Returns pointer value. // Returns pointer value.
static Char *get(CharPtr p) static Char *get(CharPtr p) {
{
return p.base(); return p.base();
} }
#else #else
static Char *get(Char *p) static Char *get(Char *p) {
{
return p; return p;
} }
#endif #endif
...@@ -1749,8 +1687,7 @@ private: ...@@ -1749,8 +1687,7 @@ private:
// Grows the buffer by n characters and returns a pointer to the newly // Grows the buffer by n characters and returns a pointer to the newly
// allocated area. // allocated area.
CharPtr grow_buffer(std::size_t n) CharPtr grow_buffer(std::size_t n) {
{
std::size_t size = buffer_.size(); std::size_t size = buffer_.size();
buffer_.resize(size + n); buffer_.resize(size + n);
return internal::make_ptr(&buffer_[size], n); return internal::make_ptr(&buffer_[size], n);
...@@ -1758,8 +1695,7 @@ private: ...@@ -1758,8 +1695,7 @@ private:
// Prepare a buffer for integer formatting. // Prepare a buffer for integer formatting.
CharPtr prepare_int_buffer(unsigned num_digits, CharPtr prepare_int_buffer(unsigned num_digits,
const EmptySpec &, const char *prefix, unsigned prefix_size) const EmptySpec &, const char *prefix, unsigned prefix_size) {
{
unsigned size = prefix_size + num_digits; unsigned size = prefix_size + num_digits;
CharPtr p = grow_buffer(size); CharPtr p = grow_buffer(size);
std::copy(prefix, prefix + prefix_size, p); std::copy(prefix, prefix + prefix_size, p);
...@@ -1787,11 +1723,22 @@ private: ...@@ -1787,11 +1723,22 @@ private:
void write_str( void write_str(
const internal::Arg::StringValue<StrChar> &str, const FormatSpec &spec); const internal::Arg::StringValue<StrChar> &str, const FormatSpec &spec);
// This method is private to disallow writing a wide string to a // This following methods are private to disallow writing wide characters
// char stream and vice versa. If you want to print a wide string // and strings to a char stream. If you want to print a wide string as a
// as a pointer as std::ostream does, cast it to const void*. // pointer as std::ostream does, cast it to const void*.
// Do not implement! // Do not implement!
void operator<<(typename internal::CharTraits<Char>::UnsupportedStrType); void operator<<(typename internal::WCharHelper<wchar_t, Char>::Unsupported);
void operator<<(
typename internal::WCharHelper<const wchar_t *, Char>::Unsupported);
// Appends floating-point length specifier to the format string.
// The second argument is only used for overload resolution.
void append_float_length(Char *&format_ptr, long double) {
*format_ptr++ = 'L';
}
template<typename T>
void append_float_length(Char *&, T) {}
friend class internal::ArgFormatter<Char>; friend class internal::ArgFormatter<Char>;
friend class internal::PrintfFormatter<Char>; friend class internal::PrintfFormatter<Char>;
...@@ -1811,8 +1758,7 @@ public: ...@@ -1811,8 +1758,7 @@ public:
/** /**
Returns the total number of characters written. Returns the total number of characters written.
*/ */
std::size_t size() const std::size_t size() const {
{
return buffer_.size(); return buffer_.size();
} }
...@@ -1820,8 +1766,7 @@ public: ...@@ -1820,8 +1766,7 @@ public:
Returns a pointer to the output buffer content. No terminating null Returns a pointer to the output buffer content. No terminating null
character is appended. character is appended.
*/ */
const Char *data() const FMT_NOEXCEPT(true) const Char *data() const FMT_NOEXCEPT {
{
return &buffer_[0]; return &buffer_[0];
} }
...@@ -1829,8 +1774,7 @@ public: ...@@ -1829,8 +1774,7 @@ public:
Returns a pointer to the output buffer content with terminating null Returns a pointer to the output buffer content with terminating null
character appended. character appended.
*/ */
const Char *c_str() const const Char *c_str() const {
{
std::size_t size = buffer_.size(); std::size_t size = buffer_.size();
buffer_.reserve(size + 1); buffer_.reserve(size + 1);
buffer_[size] = '\0'; buffer_[size] = '\0';
...@@ -1840,8 +1784,7 @@ public: ...@@ -1840,8 +1784,7 @@ public:
/** /**
Returns the content of the output buffer as an `std::string`. Returns the content of the output buffer as an `std::string`.
*/ */
std::basic_string<Char> str() const std::basic_string<Char> str() const {
{
return std::basic_string<Char>(&buffer_[0], buffer_.size()); return std::basic_string<Char>(&buffer_[0], buffer_.size());
} }
...@@ -1864,49 +1807,41 @@ public: ...@@ -1864,49 +1807,41 @@ public:
Current point: Current point:
(-3.140000, +3.140000) (-3.140000, +3.140000)
The output can be accessed using :meth:`data`, :meth:`c_str` or :meth:`str` The output can be accessed using :func:`data()`, :func:`c_str` or
methods. :func:`str` methods.
See also :ref:`syntax`. See also :ref:`syntax`.
\endrst \endrst
*/ */
void write(BasicStringRef<Char> format, ArgList args) void write(BasicStringRef<Char> format, ArgList args) {
{
BasicFormatter<Char>(*this).format(format, args); BasicFormatter<Char>(*this).format(format, args);
} }
FMT_VARIADIC_VOID(write, BasicStringRef<Char>) FMT_VARIADIC_VOID(write, BasicStringRef<Char>)
BasicWriter &operator<<(int value) BasicWriter &operator<<(int value) {
{
return *this << IntFormatSpec<int>(value); return *this << IntFormatSpec<int>(value);
} }
BasicWriter &operator<<(unsigned value) BasicWriter &operator<<(unsigned value) {
{
return *this << IntFormatSpec<unsigned>(value); return *this << IntFormatSpec<unsigned>(value);
} }
BasicWriter &operator<<(long value) BasicWriter &operator<<(long value) {
{
return *this << IntFormatSpec<long>(value); return *this << IntFormatSpec<long>(value);
} }
BasicWriter &operator<<(unsigned long value) BasicWriter &operator<<(unsigned long value) {
{
return *this << IntFormatSpec<unsigned long>(value); return *this << IntFormatSpec<unsigned long>(value);
} }
BasicWriter &operator<<(LongLong value) BasicWriter &operator<<(LongLong value) {
{
return *this << IntFormatSpec<LongLong>(value); return *this << IntFormatSpec<LongLong>(value);
} }
/** /**
Formats *value* and writes it to the stream. Formats *value* and writes it to the stream.
*/ */
BasicWriter &operator<<(ULongLong value) BasicWriter &operator<<(ULongLong value) {
{
return *this << IntFormatSpec<ULongLong>(value); return *this << IntFormatSpec<ULongLong>(value);
} }
BasicWriter &operator<<(double value) BasicWriter &operator<<(double value) {
{
write_double(value, FormatSpec()); write_double(value, FormatSpec());
return *this; return *this;
} }
...@@ -1915,8 +1850,7 @@ public: ...@@ -1915,8 +1850,7 @@ public:
Formats *value* using the general format for floating-point numbers Formats *value* using the general format for floating-point numbers
(``'g'``) and writes it to the stream. (``'g'``) and writes it to the stream.
*/ */
BasicWriter &operator<<(long double value) BasicWriter &operator<<(long double value) {
{
write_double(value, FormatSpec()); write_double(value, FormatSpec());
return *this; return *this;
} }
...@@ -1924,77 +1858,64 @@ public: ...@@ -1924,77 +1858,64 @@ public:
/** /**
Writes a character to the stream. Writes a character to the stream.
*/ */
BasicWriter &operator<<(char value) BasicWriter &operator<<(char value) {
{
buffer_.push_back(value); buffer_.push_back(value);
return *this; return *this;
} }
BasicWriter &operator<<(wchar_t value) BasicWriter &operator<<(
{ typename internal::WCharHelper<wchar_t, Char>::Supported value) {
buffer_.push_back(internal::CharTraits<Char>::convert(value)); buffer_.push_back(value);
return *this; return *this;
} }
/** /**
Writes *value* to the stream. Writes *value* to the stream.
*/ */
BasicWriter &operator<<(fmt::BasicStringRef<Char> value) BasicWriter &operator<<(fmt::BasicStringRef<Char> value) {
{
const Char *str = value.c_str(); const Char *str = value.c_str();
buffer_.append(str, str + value.size()); buffer_.append(str, str + value.size());
return *this; return *this;
} }
template <typename T, typename Spec, typename FillChar> template <typename T, typename Spec, typename FillChar>
BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) BasicWriter &operator<<(IntFormatSpec<T, Spec, FillChar> spec) {
{
internal::CharTraits<Char>::convert(FillChar()); internal::CharTraits<Char>::convert(FillChar());
write_int(spec.value(), spec); write_int(spec.value(), spec);
return *this; return *this;
} }
template <typename StrChar> template <typename StrChar>
BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) BasicWriter &operator<<(const StrFormatSpec<StrChar> &spec) {
{
const StrChar *s = spec.str(); const StrChar *s = spec.str();
// TODO: error if fill is not convertible to Char // TODO: error if fill is not convertible to Char
write_str(s, std::char_traits<Char>::length(s), spec); write_str(s, std::char_traits<Char>::length(s), spec);
return *this; return *this;
} }
void clear() FMT_NOEXCEPT(true) void clear() FMT_NOEXCEPT{ buffer_.clear(); }
{
buffer_.clear();
}
}; };
template <typename Char> template <typename Char>
template <typename StrChar> template <typename StrChar>
typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str( typename BasicWriter<Char>::CharPtr BasicWriter<Char>::write_str(
const StrChar *s, std::size_t size, const AlignSpec &spec) const StrChar *s, std::size_t size, const AlignSpec &spec) {
{
CharPtr out = CharPtr(); CharPtr out = CharPtr();
if (spec.width() > size) if (spec.width() > size) {
{
out = grow_buffer(spec.width()); out = grow_buffer(spec.width());
Char fill = static_cast<Char>(spec.fill()); Char fill = static_cast<Char>(spec.fill());
if (spec.align() == ALIGN_RIGHT) if (spec.align() == ALIGN_RIGHT) {
{
std::fill_n(out, spec.width() - size, fill); std::fill_n(out, spec.width() - size, fill);
out += spec.width() - size; out += spec.width() - size;
} }
else if (spec.align() == ALIGN_CENTER) else if (spec.align() == ALIGN_CENTER) {
{
out = fill_padding(out, spec.width(), size, fill); out = fill_padding(out, spec.width(), size, fill);
} }
else else {
{
std::fill_n(out + size, spec.width() - size, fill); std::fill_n(out + size, spec.width() - size, fill);
} }
} }
else else {
{
out = grow_buffer(size); out = grow_buffer(size);
} }
std::copy(s, s + size, out); std::copy(s, s + size, out);
...@@ -2005,8 +1926,7 @@ template <typename Char> ...@@ -2005,8 +1926,7 @@ template <typename Char>
typename BasicWriter<Char>::CharPtr typename BasicWriter<Char>::CharPtr
BasicWriter<Char>::fill_padding( BasicWriter<Char>::fill_padding(
CharPtr buffer, unsigned total_size, CharPtr buffer, unsigned total_size,
std::size_t content_size, wchar_t fill) std::size_t content_size, wchar_t fill) {
{
std::size_t padding = total_size - content_size; std::size_t padding = total_size - content_size;
std::size_t left_padding = padding / 2; std::size_t left_padding = padding / 2;
Char fill_char = static_cast<Char>(fill); Char fill_char = static_cast<Char>(fill);
...@@ -2022,13 +1942,11 @@ template <typename Spec> ...@@ -2022,13 +1942,11 @@ template <typename Spec>
typename BasicWriter<Char>::CharPtr typename BasicWriter<Char>::CharPtr
BasicWriter<Char>::prepare_int_buffer( BasicWriter<Char>::prepare_int_buffer(
unsigned num_digits, const Spec &spec, unsigned num_digits, const Spec &spec,
const char *prefix, unsigned prefix_size) const char *prefix, unsigned prefix_size) {
{
unsigned width = spec.width(); unsigned width = spec.width();
Alignment align = spec.align(); Alignment align = spec.align();
Char fill = static_cast<Char>(spec.fill()); Char fill = static_cast<Char>(spec.fill());
if (spec.precision() > static_cast<int>(num_digits)) if (spec.precision() > static_cast<int>(num_digits)) {
{
// Octal prefix '0' is counted as a digit, so ignore it if precision // Octal prefix '0' is counted as a digit, so ignore it if precision
// is specified. // is specified.
if (prefix_size > 0 && prefix[prefix_size - 1] == '0') if (prefix_size > 0 && prefix[prefix_size - 1] == '0')
...@@ -2039,53 +1957,44 @@ BasicWriter<Char>::prepare_int_buffer( ...@@ -2039,53 +1957,44 @@ BasicWriter<Char>::prepare_int_buffer(
return prepare_int_buffer(num_digits, subspec, prefix, prefix_size); return prepare_int_buffer(num_digits, subspec, prefix, prefix_size);
buffer_.reserve(width); buffer_.reserve(width);
unsigned fill_size = width - number_size; unsigned fill_size = width - number_size;
if (align != ALIGN_LEFT) if (align != ALIGN_LEFT) {
{
CharPtr p = grow_buffer(fill_size); CharPtr p = grow_buffer(fill_size);
std::fill(p, p + fill_size, fill); std::fill(p, p + fill_size, fill);
} }
CharPtr result = prepare_int_buffer( CharPtr result = prepare_int_buffer(
num_digits, subspec, prefix, prefix_size); num_digits, subspec, prefix, prefix_size);
if (align == ALIGN_LEFT) if (align == ALIGN_LEFT) {
{
CharPtr p = grow_buffer(fill_size); CharPtr p = grow_buffer(fill_size);
std::fill(p, p + fill_size, fill); std::fill(p, p + fill_size, fill);
} }
return result; return result;
} }
unsigned size = prefix_size + num_digits; unsigned size = prefix_size + num_digits;
if (width <= size) if (width <= size) {
{
CharPtr p = grow_buffer(size); CharPtr p = grow_buffer(size);
std::copy(prefix, prefix + prefix_size, p); std::copy(prefix, prefix + prefix_size, p);
return p + size - 1; return p + size - 1;
} }
CharPtr p = grow_buffer(width); CharPtr p = grow_buffer(width);
CharPtr end = p + width; CharPtr end = p + width;
if (align == ALIGN_LEFT) if (align == ALIGN_LEFT) {
{
std::copy(prefix, prefix + prefix_size, p); std::copy(prefix, prefix + prefix_size, p);
p += size; p += size;
std::fill(p, end, fill); std::fill(p, end, fill);
} }
else if (align == ALIGN_CENTER) else if (align == ALIGN_CENTER) {
{
p = fill_padding(p, width, size, fill); p = fill_padding(p, width, size, fill);
std::copy(prefix, prefix + prefix_size, p); std::copy(prefix, prefix + prefix_size, p);
p += size; p += size;
} }
else else {
{ if (align == ALIGN_NUMERIC) {
if (align == ALIGN_NUMERIC) if (prefix_size != 0) {
{
if (prefix_size != 0)
{
p = std::copy(prefix, prefix + prefix_size, p); p = std::copy(prefix, prefix + prefix_size, p);
size -= prefix_size; size -= prefix_size;
} }
} }
else else {
{
std::copy(prefix, prefix + prefix_size, end - size); std::copy(prefix, prefix + prefix_size, end - size);
} }
std::fill(p, end - size, fill); std::fill(p, end - size, fill);
...@@ -2096,28 +2005,23 @@ BasicWriter<Char>::prepare_int_buffer( ...@@ -2096,28 +2005,23 @@ BasicWriter<Char>::prepare_int_buffer(
template <typename Char> template <typename Char>
template <typename T, typename Spec> template <typename T, typename Spec>
void BasicWriter<Char>::write_int(T value, Spec spec) void BasicWriter<Char>::write_int(T value, Spec spec) {
{
unsigned prefix_size = 0; unsigned prefix_size = 0;
typedef typename internal::IntTraits<T>::MainType UnsignedType; typedef typename internal::IntTraits<T>::MainType UnsignedType;
UnsignedType abs_value = value; UnsignedType abs_value = value;
char prefix[4] = ""; char prefix[4] = "";
if (internal::is_negative(value)) if (internal::is_negative(value)) {
{
prefix[0] = '-'; prefix[0] = '-';
++prefix_size; ++prefix_size;
abs_value = 0 - abs_value; abs_value = 0 - abs_value;
} }
else if (spec.flag(SIGN_FLAG)) else if (spec.flag(SIGN_FLAG)) {
{
prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' '; prefix[0] = spec.flag(PLUS_FLAG) ? '+' : ' ';
++prefix_size; ++prefix_size;
} }
switch (spec.type()) switch (spec.type()) {
{
case 0: case 0:
case 'd': case 'd': {
{
unsigned num_digits = internal::count_digits(abs_value); unsigned num_digits = internal::count_digits(abs_value);
CharPtr p = prepare_int_buffer( CharPtr p = prepare_int_buffer(
num_digits, spec, prefix, prefix_size) + 1 - num_digits; num_digits, spec, prefix, prefix_size) + 1 - num_digits;
...@@ -2125,74 +2029,57 @@ void BasicWriter<Char>::write_int(T value, Spec spec) ...@@ -2125,74 +2029,57 @@ void BasicWriter<Char>::write_int(T value, Spec spec)
break; break;
} }
case 'x': case 'x':
case 'X': case 'X': {
{
UnsignedType n = abs_value; UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG)) if (spec.flag(HASH_FLAG)) {
{
prefix[prefix_size++] = '0'; prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type(); prefix[prefix_size++] = spec.type();
} }
unsigned num_digits = 0; unsigned num_digits = 0;
do do {
{
++num_digits; ++num_digits;
} } while ((n >>= 4) != 0);
while ((n >>= 4) != 0);
Char *p = get(prepare_int_buffer( Char *p = get(prepare_int_buffer(
num_digits, spec, prefix, prefix_size)); num_digits, spec, prefix, prefix_size));
n = abs_value; n = abs_value;
const char *digits = spec.type() == 'x' ? const char *digits = spec.type() == 'x' ?
"0123456789abcdef" : "0123456789ABCDEF"; "0123456789abcdef" : "0123456789ABCDEF";
do do {
{
*p-- = digits[n & 0xf]; *p-- = digits[n & 0xf];
} } while ((n >>= 4) != 0);
while ((n >>= 4) != 0);
break; break;
} }
case 'b': case 'b':
case 'B': case 'B': {
{
UnsignedType n = abs_value; UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG)) if (spec.flag(HASH_FLAG)) {
{
prefix[prefix_size++] = '0'; prefix[prefix_size++] = '0';
prefix[prefix_size++] = spec.type(); prefix[prefix_size++] = spec.type();
} }
unsigned num_digits = 0; unsigned num_digits = 0;
do do {
{
++num_digits; ++num_digits;
} } while ((n >>= 1) != 0);
while ((n >>= 1) != 0);
Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
n = abs_value; n = abs_value;
do do {
{
*p-- = '0' + (n & 1); *p-- = '0' + (n & 1);
} } while ((n >>= 1) != 0);
while ((n >>= 1) != 0);
break; break;
} }
case 'o': case 'o': {
{
UnsignedType n = abs_value; UnsignedType n = abs_value;
if (spec.flag(HASH_FLAG)) if (spec.flag(HASH_FLAG))
prefix[prefix_size++] = '0'; prefix[prefix_size++] = '0';
unsigned num_digits = 0; unsigned num_digits = 0;
do do {
{
++num_digits; ++num_digits;
} } while ((n >>= 3) != 0);
while ((n >>= 3) != 0);
Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size)); Char *p = get(prepare_int_buffer(num_digits, spec, prefix, prefix_size));
n = abs_value; n = abs_value;
do do {
{
*p-- = '0' + (n & 7); *p-- = '0' + (n & 7);
} } while ((n >>= 3) != 0);
while ((n >>= 3) != 0);
break; break;
} }
default: default:
...@@ -2205,13 +2092,11 @@ void BasicWriter<Char>::write_int(T value, Spec spec) ...@@ -2205,13 +2092,11 @@ void BasicWriter<Char>::write_int(T value, Spec spec)
template <typename Char> template <typename Char>
template <typename T> template <typename T>
void BasicWriter<Char>::write_double( void BasicWriter<Char>::write_double(
T value, const FormatSpec &spec) T value, const FormatSpec &spec) {
{
// Check type. // Check type.
char type = spec.type(); char type = spec.type();
bool upper = false; bool upper = false;
switch (type) switch (type) {
{
case 0: case 0:
type = 'g'; type = 'g';
break; break;
...@@ -2225,7 +2110,7 @@ void BasicWriter<Char>::write_double( ...@@ -2225,7 +2110,7 @@ void BasicWriter<Char>::write_double(
// MSVC's printf doesn't support 'F'. // MSVC's printf doesn't support 'F'.
type = 'f'; type = 'f';
#endif #endif
// Fall through. // Fall through.
case 'E': case 'E':
case 'G': case 'G':
case 'A': case 'A':
...@@ -2239,45 +2124,39 @@ void BasicWriter<Char>::write_double( ...@@ -2239,45 +2124,39 @@ void BasicWriter<Char>::write_double(
char sign = 0; char sign = 0;
// Use getsign instead of value < 0 because the latter is always // Use getsign instead of value < 0 because the latter is always
// false for NaN. // false for NaN.
if (internal::getsign(static_cast<double>(value))) if (internal::getsign(static_cast<double>(value))) {
{
sign = '-'; sign = '-';
value = -value; value = -value;
} }
else if (spec.flag(SIGN_FLAG)) else if (spec.flag(SIGN_FLAG)) {
{
sign = spec.flag(PLUS_FLAG) ? '+' : ' '; sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
} }
if (value != value) if (value != value) {
{
// Format NaN ourselves because sprintf's output is not consistent // Format NaN ourselves because sprintf's output is not consistent
// across platforms. // across platforms.
std::size_t size = 4; std::size_t nan_size = 4;
const char *nan = upper ? " NAN" : " nan"; const char *nan = upper ? " NAN" : " nan";
if (!sign) if (!sign) {
{ --nan_size;
--size;
++nan; ++nan;
} }
CharPtr out = write_str(nan, size, spec); CharPtr out = write_str(nan, nan_size, spec);
if (sign) if (sign)
*out = sign; *out = sign;
return; return;
} }
if (internal::isinfinity(value)) if (internal::isinfinity(value)) {
{
// Format infinity ourselves because sprintf's output is not consistent // Format infinity ourselves because sprintf's output is not consistent
// across platforms. // across platforms.
std::size_t size = 4; std::size_t inf_size = 4;
const char *inf = upper ? " INF" : " inf"; const char *inf = upper ? " INF" : " inf";
if (!sign) if (!sign) {
{ --inf_size;
--size;
++inf; ++inf;
} }
CharPtr out = write_str(inf, size, spec); CharPtr out = write_str(inf, inf_size, spec);
if (sign) if (sign)
*out = sign; *out = sign;
return; return;
...@@ -2285,8 +2164,7 @@ void BasicWriter<Char>::write_double( ...@@ -2285,8 +2164,7 @@ void BasicWriter<Char>::write_double(
std::size_t offset = buffer_.size(); std::size_t offset = buffer_.size();
unsigned width = spec.width(); unsigned width = spec.width();
if (sign) if (sign) {
{
buffer_.reserve(buffer_.size() + (std::max)(width, 1u)); buffer_.reserve(buffer_.size() + (std::max)(width, 1u));
if (width > 0) if (width > 0)
--width; --width;
...@@ -2301,72 +2179,61 @@ void BasicWriter<Char>::write_double( ...@@ -2301,72 +2179,61 @@ void BasicWriter<Char>::write_double(
unsigned width_for_sprintf = width; unsigned width_for_sprintf = width;
if (spec.flag(HASH_FLAG)) if (spec.flag(HASH_FLAG))
*format_ptr++ = '#'; *format_ptr++ = '#';
if (spec.align() == ALIGN_CENTER) if (spec.align() == ALIGN_CENTER) {
{
width_for_sprintf = 0; width_for_sprintf = 0;
} }
else else {
{
if (spec.align() == ALIGN_LEFT) if (spec.align() == ALIGN_LEFT)
*format_ptr++ = '-'; *format_ptr++ = '-';
if (width != 0) if (width != 0)
*format_ptr++ = '*'; *format_ptr++ = '*';
} }
if (spec.precision() >= 0) if (spec.precision() >= 0) {
{
*format_ptr++ = '.'; *format_ptr++ = '.';
*format_ptr++ = '*'; *format_ptr++ = '*';
} }
if (internal::IsLongDouble<T>::VALUE)
*format_ptr++ = 'L'; append_float_length(format_ptr, value);
*format_ptr++ = type; *format_ptr++ = type;
*format_ptr = '\0'; *format_ptr = '\0';
// Format using snprintf. // Format using snprintf.
Char fill = static_cast<Char>(spec.fill()); Char fill = static_cast<Char>(spec.fill());
for (;;) for (;;) {
{ std::size_t buffer_size = buffer_.capacity() - offset;
std::size_t size = buffer_.capacity() - offset;
#if _MSC_VER #if _MSC_VER
// MSVC's vsnprintf_s doesn't work with zero size, so reserve // MSVC's vsnprintf_s doesn't work with zero size, so reserve
// space for at least one extra character to make the size non-zero. // space for at least one extra character to make the size non-zero.
// Note that the buffer's capacity will increase by more than 1. // Note that the buffer's capacity will increase by more than 1.
if (size == 0) if (buffer_size == 0) {
{
buffer_.reserve(offset + 1); buffer_.reserve(offset + 1);
size = buffer_.capacity() - offset; buffer_size = buffer_.capacity() - offset;
} }
#endif #endif
Char *start = &buffer_[offset]; Char *start = &buffer_[offset];
int n = internal::CharTraits<Char>::format_float( int n = internal::CharTraits<Char>::format_float(
start, size, format, width_for_sprintf, spec.precision(), value); start, buffer_size, format, width_for_sprintf, spec.precision(), value);
if (n >= 0 && offset + n < buffer_.capacity()) if (n >= 0 && offset + n < buffer_.capacity()) {
{ if (sign) {
if (sign)
{
if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) || if ((spec.align() != ALIGN_RIGHT && spec.align() != ALIGN_DEFAULT) ||
*start != ' ') *start != ' ') {
{
*(start - 1) = sign; *(start - 1) = sign;
sign = 0; sign = 0;
} }
else else {
{
*(start - 1) = fill; *(start - 1) = fill;
} }
++n; ++n;
} }
if (spec.align() == ALIGN_CENTER && if (spec.align() == ALIGN_CENTER &&
spec.width() > static_cast<unsigned>(n)) spec.width() > static_cast<unsigned>(n)) {
{ width = spec.width();
unsigned width = spec.width();
CharPtr p = grow_buffer(width); CharPtr p = grow_buffer(width);
std::copy(p, p + n, p + (width - n) / 2); std::copy(p, p + n, p + (width - n) / 2);
fill_padding(p, spec.width(), n, fill); fill_padding(p, spec.width(), n, fill);
return; return;
} }
if (spec.fill() != ' ' || sign) if (spec.fill() != ' ' || sign) {
{
while (*start == ' ') while (*start == ' ')
*start++ = fill; *start++ = fill;
if (sign) if (sign)
...@@ -2416,8 +2283,7 @@ accessed as a C string with ``out.c_str()``. ...@@ -2416,8 +2283,7 @@ accessed as a C string with ``out.c_str()``.
\endrst \endrst
*/ */
template <typename Char, typename Allocator = std::allocator<Char> > template <typename Char, typename Allocator = std::allocator<Char> >
class BasicMemoryWriter : public BasicWriter<Char> class BasicMemoryWriter : public BasicWriter<Char> {
{
private: private:
internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_; internal::MemoryBuffer<Char, internal::INLINE_BUFFER_SIZE, Allocator> buffer_;
...@@ -2427,19 +2293,17 @@ public: ...@@ -2427,19 +2293,17 @@ public:
#if FMT_USE_RVALUE_REFERENCES #if FMT_USE_RVALUE_REFERENCES
/** /**
Constructs a ``BasicMemoryWriter`` object moving the content of the other Constructs a :class:`fmt::BasicMemoryWriter` object moving the content
object to it. of the other object to it.
*/ */
BasicMemoryWriter(BasicMemoryWriter &&other) BasicMemoryWriter(BasicMemoryWriter &&other)
: BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) : BasicWriter<Char>(buffer_), buffer_(std::move(other.buffer_)) {
{
} }
/** /**
Moves the content of the other ``BasicMemoryWriter`` object to this one. Moves the content of the other ``BasicMemoryWriter`` object to this one.
*/ */
BasicMemoryWriter &operator=(BasicMemoryWriter &&other) BasicMemoryWriter &operator=(BasicMemoryWriter &&other) {
{
buffer_ = std::move(other.buffer_); buffer_ = std::move(other.buffer_);
return *this; return *this;
} }
...@@ -2451,44 +2315,59 @@ typedef BasicMemoryWriter<wchar_t> WMemoryWriter; ...@@ -2451,44 +2315,59 @@ typedef BasicMemoryWriter<wchar_t> WMemoryWriter;
// Formats a value. // Formats a value.
template <typename Char, typename T> template <typename Char, typename T>
void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) void format(BasicFormatter<Char> &f, const Char *&format_str, const T &value) {
{
std::basic_ostringstream<Char> os; std::basic_ostringstream<Char> os;
os << value; os << value;
internal::Arg arg; internal::Arg arg;
internal::Value &arg_value = arg; internal::Value &arg_value = arg;
std::basic_string<Char> str = os.str(); std::basic_string<Char> str = os.str();
arg_value = internal::MakeValue<Char>(str); arg_value = internal::MakeValue<Char>(str);
arg.type = internal::Arg::STRING; arg.type = static_cast<internal::Arg::Type>(
internal::MakeValue<Char>::type(str));
format_str = f.format(format_str, arg); format_str = f.format(format_str, arg);
} }
// Reports a system error without throwing an exception. // Reports a system error without throwing an exception.
// Can be used to report errors from destructors. // Can be used to report errors from destructors.
void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT(true); void report_system_error(int error_code, StringRef message) FMT_NOEXCEPT;
#ifdef _WIN32 #ifdef _WIN32
/** /** A Windows error. */
A Windows error. class WindowsError : public SystemError {
*/
class WindowsError : public SystemError
{
private: private:
void init(int error_code, StringRef format_str, ArgList args); void init(int error_code, StringRef format_str, ArgList args);
public: public:
/** /**
\rst \rst
Constructs a :cpp:class:`fmt::WindowsError` object with the description Constructs a :class:`fmt::WindowsError` object with the description
of the form "*<message>*: *<system-message>*", where *<message>* is the of the form
formatted message and *<system-message>* is the system message corresponding
to the error code. .. parsed-literal::
*<message>*: *<system-message>*
where *<message>* is the formatted message and *<system-message>* is the
system message corresponding to the error code.
*error_code* is a Windows error code as given by ``GetLastError``. *error_code* is a Windows error code as given by ``GetLastError``.
If *error_code* is not a valid error code such as -1, the system message
will look like "error -1".
**Example**::
// This throws a WindowsError with the description
// cannot open file 'madeup': The system cannot find the file specified.
// or similar (system message may vary).
const char *filename = "madeup";
LPOFSTRUCT of = LPOFSTRUCT();
HFILE file = OpenFile(filename, &of, OF_READ);
if (file == HFILE_ERROR) {
throw fmt::WindowsError(GetLastError(),
"cannot open file '{}'", filename);
}
\endrst \endrst
*/ */
WindowsError(int error_code, StringRef message) WindowsError(int error_code, StringRef message) {
{
init(error_code, message, ArgList()); init(error_code, message, ArgList());
} }
FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef) FMT_VARIADIC_CTOR(WindowsError, init, int, StringRef)
...@@ -2496,7 +2375,7 @@ public: ...@@ -2496,7 +2375,7 @@ public:
// Reports a Windows error without throwing an exception. // Reports a Windows error without throwing an exception.
// Can be used to report errors from destructors. // Can be used to report errors from destructors.
void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT(true); void report_windows_error(int error_code, StringRef message) FMT_NOEXCEPT;
#endif #endif
...@@ -2519,15 +2398,13 @@ Formats arguments and returns the result as a string. ...@@ -2519,15 +2398,13 @@ Formats arguments and returns the result as a string.
std::string message = format("The answer is {}", 42); std::string message = format("The answer is {}", 42);
\endrst \endrst
*/ */
inline std::string format(StringRef format_str, ArgList args) inline std::string format(StringRef format_str, ArgList args) {
{
MemoryWriter w; MemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
return w.str(); return w.str();
} }
inline std::wstring format(WStringRef format_str, ArgList args) inline std::wstring format(WStringRef format_str, ArgList args) {
{
WMemoryWriter w; WMemoryWriter w;
w.write(format_str, args); w.write(format_str, args);
return w.str(); return w.str();
...@@ -2567,8 +2444,7 @@ print(cerr, "Don't {}!", "panic"); ...@@ -2567,8 +2444,7 @@ print(cerr, "Don't {}!", "panic");
void print(std::ostream &os, StringRef format_str, ArgList args); void print(std::ostream &os, StringRef format_str, ArgList args);
template <typename Char> template <typename Char>
void printf(BasicWriter<Char> &w, BasicStringRef<Char> format, ArgList args) void printf(BasicWriter<Char> &w, BasicStringRef<Char> format, ArgList args) {
{
internal::PrintfFormatter<Char>().format(w, format, args); internal::PrintfFormatter<Char>().format(w, format, args);
} }
...@@ -2581,8 +2457,7 @@ Formats arguments and returns the result as a string. ...@@ -2581,8 +2457,7 @@ Formats arguments and returns the result as a string.
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(StringRef format, ArgList args) inline std::string sprintf(StringRef format, ArgList args) {
{
MemoryWriter w; MemoryWriter w;
printf(w, format, args); printf(w, format, args);
return w.str(); return w.str();
...@@ -2608,16 +2483,14 @@ Prints formatted data to ``stdout``. ...@@ -2608,16 +2483,14 @@ Prints formatted data to ``stdout``.
fmt::printf("Elapsed time: %.2f seconds", 1.23); fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst \endrst
*/ */
inline int printf(StringRef format, ArgList args) inline int printf(StringRef format, ArgList args) {
{
return fprintf(stdout, format, args); return fprintf(stdout, format, args);
} }
/** /**
Fast integer formatter. Fast integer formatter.
*/ */
class FormatInt class FormatInt {
{
private: private:
// Buffer should be large enough to hold all digits (digits10 + 1), // Buffer should be large enough to hold all digits (digits10 + 1),
// a sign and a null character. // a sign and a null character.
...@@ -2626,11 +2499,9 @@ private: ...@@ -2626,11 +2499,9 @@ private:
char *str_; char *str_;
// Formats value in reverse and returns the number of digits. // Formats value in reverse and returns the number of digits.
char *format_decimal(ULongLong value) char *format_decimal(ULongLong value) {
{
char *buffer_end = buffer_ + BUFFER_SIZE - 1; char *buffer_end = buffer_ + BUFFER_SIZE - 1;
while (value >= 100) while (value >= 100) {
{
// Integer division is slow so do it for a group of two digits instead // Integer division is slow so do it for a group of two digits instead
// of for every digit. The idea comes from the talk by Alexandrescu // of for every digit. The idea comes from the talk by Alexandrescu
// "Three Optimization Tips for C++". See speed-test for a comparison. // "Three Optimization Tips for C++". See speed-test for a comparison.
...@@ -2639,8 +2510,7 @@ private: ...@@ -2639,8 +2510,7 @@ private:
*--buffer_end = internal::Data::DIGITS[index + 1]; *--buffer_end = internal::Data::DIGITS[index + 1];
*--buffer_end = internal::Data::DIGITS[index]; *--buffer_end = internal::Data::DIGITS[index];
} }
if (value < 10) if (value < 10) {
{
*--buffer_end = static_cast<char>('0' + value); *--buffer_end = static_cast<char>('0' + value);
return buffer_end; return buffer_end;
} }
...@@ -2650,8 +2520,7 @@ private: ...@@ -2650,8 +2520,7 @@ private:
return buffer_end; return buffer_end;
} }
void FormatSigned(LongLong value) void FormatSigned(LongLong value) {
{
ULongLong abs_value = static_cast<ULongLong>(value); ULongLong abs_value = static_cast<ULongLong>(value);
bool negative = value < 0; bool negative = value < 0;
if (negative) if (negative)
...@@ -2662,16 +2531,13 @@ private: ...@@ -2662,16 +2531,13 @@ private:
} }
public: public:
explicit FormatInt(int value) explicit FormatInt(int value) {
{
FormatSigned(value); FormatSigned(value);
} }
explicit FormatInt(long value) explicit FormatInt(long value) {
{
FormatSigned(value); FormatSigned(value);
} }
explicit FormatInt(LongLong value) explicit FormatInt(LongLong value) {
{
FormatSigned(value); FormatSigned(value);
} }
explicit FormatInt(unsigned value) : str_(format_decimal(value)) {} explicit FormatInt(unsigned value) : str_(format_decimal(value)) {}
...@@ -2681,8 +2547,7 @@ public: ...@@ -2681,8 +2547,7 @@ public:
/** /**
Returns the number of characters written to the output buffer. Returns the number of characters written to the output buffer.
*/ */
std::size_t size() const std::size_t size() const {
{
return buffer_ - str_ + BUFFER_SIZE - 1; return buffer_ - str_ + BUFFER_SIZE - 1;
} }
...@@ -2690,8 +2555,7 @@ public: ...@@ -2690,8 +2555,7 @@ public:
Returns a pointer to the output buffer content. No terminating null Returns a pointer to the output buffer content. No terminating null
character is appended. character is appended.
*/ */
const char *data() const const char *data() const {
{
return str_; return str_;
} }
...@@ -2699,8 +2563,7 @@ public: ...@@ -2699,8 +2563,7 @@ public:
Returns a pointer to the output buffer content with terminating null Returns a pointer to the output buffer content with terminating null
character appended. character appended.
*/ */
const char *c_str() const const char *c_str() const {
{
buffer_[BUFFER_SIZE - 1] = '\0'; buffer_[BUFFER_SIZE - 1] = '\0';
return str_; return str_;
} }
...@@ -2708,8 +2571,7 @@ public: ...@@ -2708,8 +2571,7 @@ public:
/** /**
Returns the content of the output buffer as an `std::string`. Returns the content of the output buffer as an `std::string`.
*/ */
std::string str() const std::string str() const {
{
return std::string(str_, size()); return std::string(str_, size());
} }
}; };
...@@ -2718,18 +2580,14 @@ public: ...@@ -2718,18 +2580,14 @@ public:
// a pointer to the end of the formatted string. This function doesn't // a pointer to the end of the formatted string. This function doesn't
// write a terminating null character. // write a terminating null character.
template <typename T> template <typename T>
inline void format_decimal(char *&buffer, T value) inline void format_decimal(char *&buffer, T value) {
{
typename internal::IntTraits<T>::MainType abs_value = value; typename internal::IntTraits<T>::MainType abs_value = value;
if (internal::is_negative(value)) if (internal::is_negative(value)) {
{
*buffer++ = '-'; *buffer++ = '-';
abs_value = 0 - abs_value; abs_value = 0 - abs_value;
} }
if (abs_value < 100) if (abs_value < 100) {
{ if (abs_value < 10) {
if (abs_value < 10)
{
*buffer++ = static_cast<char>('0' + abs_value); *buffer++ = static_cast<char>('0' + abs_value);
return; return;
} }
...@@ -2742,9 +2600,7 @@ inline void format_decimal(char *&buffer, T value) ...@@ -2742,9 +2600,7 @@ inline void format_decimal(char *&buffer, T value)
internal::format_decimal(buffer, abs_value, num_digits); internal::format_decimal(buffer, abs_value, num_digits);
buffer += num_digits; buffer += num_digits;
} }
} // ns fmt }
} // ns deatils
} // ns spdlog
#if FMT_GCC_VERSION #if FMT_GCC_VERSION
// Use the system_header pragma to suppress warnings about variadic macros // Use the system_header pragma to suppress warnings about variadic macros
...@@ -2851,12 +2707,7 @@ fmt::print(format, args...); ...@@ -2851,12 +2707,7 @@ fmt::print(format, args...);
#define FMT_VARIADIC_W(ReturnType, func, ...) \ #define FMT_VARIADIC_W(ReturnType, func, ...) \
FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__) FMT_VARIADIC_(wchar_t, ReturnType, func, return func, __VA_ARGS__)
namespace spdlog namespace fmt {
{
namespace details
{
namespace fmt
{
FMT_VARIADIC(std::string, format, StringRef) FMT_VARIADIC(std::string, format, StringRef)
FMT_VARIADIC_W(std::wstring, format, WStringRef) FMT_VARIADIC_W(std::wstring, format, WStringRef)
FMT_VARIADIC(void, print, StringRef) FMT_VARIADIC(void, print, StringRef)
...@@ -2867,20 +2718,17 @@ FMT_VARIADIC(std::string, sprintf, StringRef) ...@@ -2867,20 +2718,17 @@ FMT_VARIADIC(std::string, sprintf, StringRef)
FMT_VARIADIC(int, printf, StringRef) FMT_VARIADIC(int, printf, StringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, StringRef) FMT_VARIADIC(int, fprintf, std::FILE *, StringRef)
} }
}
}
// Restore warnings. // Restore warnings.
#if FMT_GCC_VERSION >= 406 #if FMT_GCC_VERSION >= 406
# pragma GCC diagnostic pop # pragma GCC diagnostic pop
#endif #endif
#ifdef __clang__
#define FMT_HEADER_ONLY # pragma clang diagnostic pop
#endif
#ifdef FMT_HEADER_ONLY
# include "format.cc" # include "format.cc"
#ifdef __GNUC__
# pragma GCC diagnostic pop //pop -Wshadow warnings ignore
#endif #endif
#endif // SPDLOG_FMT_FORMAT_H_ #endif // FMT_FORMAT_H_
\ No newline at end of file
...@@ -478,7 +478,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag) ...@@ -478,7 +478,7 @@ inline void spdlog::pattern_formatter::handle_flag(char flag)
{ {
switch (flag) switch (flag)
{ {
// logger name // logger name
case 'n': case 'n':
_formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter())); _formatters.push_back(std::unique_ptr<details::flag_formatter>(new details::name_formatter()));
break; break;
...@@ -610,8 +610,8 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg) ...@@ -610,8 +610,8 @@ inline void spdlog::pattern_formatter::format(details::log_msg& msg)
//write eol //write eol
msg.formatted << details::os::eol(); msg.formatted << details::os::eol();
} }
catch(const details::fmt::FormatError& e) catch(const fmt::FormatError& e)
{ {
throw spdlog_ex(details::fmt::format("formatting error while processing format string: {}", e.what())); throw spdlog_ex(fmt::format("formatting error while processing format string: {}", e.what()));
} }
} }
...@@ -99,7 +99,7 @@ protected: ...@@ -99,7 +99,7 @@ protected:
private: private:
static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension) static std::string calc_filename(const std::string& filename, std::size_t index, const std::string& extension)
{ {
details::fmt::MemoryWriter w; fmt::MemoryWriter w;
if (index) if (index)
w.write("{}.{}.{}", filename, index, extension); w.write("{}.{}.{}", filename, index, extension);
else else
...@@ -207,7 +207,7 @@ private: ...@@ -207,7 +207,7 @@ private:
static std::string calc_filename(const std::string& basename, const std::string& extension) static std::string calc_filename(const std::string& basename, const std::string& extension)
{ {
std::tm tm = spdlog::details::os::localtime(); std::tm tm = spdlog::details::os::localtime();
details::fmt::MemoryWriter w; fmt::MemoryWriter w;
w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension); w.write("{}_{:04d}-{:02d}-{:02d}_{:02d}-{:02d}.{}", basename, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, extension);
return w.str(); return w.str();
} }
......
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