Updated cppformat lib

This commit is contained in:
gabime 2015-11-05 15:33:27 +02:00
parent f15ed2373b
commit f36622553c
2 changed files with 206 additions and 52 deletions

View File

@ -52,10 +52,10 @@
using fmt::internal::Arg; using fmt::internal::Arg;
// Check if exceptions are disabled. // Check if exceptions are disabled.
#if __GNUC__ && !__EXCEPTIONS #if defined(__GNUC__) && !defined(__EXCEPTIONS)
# define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
#endif #endif
#if _MSC_VER && !_HAS_EXCEPTIONS #if defined(_MSC_VER) && !_HAS_EXCEPTIONS
# define FMT_EXCEPTIONS 0 # define FMT_EXCEPTIONS 0
#endif #endif
#ifndef FMT_EXCEPTIONS #ifndef FMT_EXCEPTIONS
@ -84,7 +84,7 @@ using fmt::internal::Arg;
# define FMT_FUNC # define FMT_FUNC
#endif #endif
#if _MSC_VER #ifdef _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 # pragma warning(disable: 4702) // unreachable code
@ -142,6 +142,7 @@ struct IntChecker<true> {
static bool fits_in_int(T value) { static bool fits_in_int(T value) {
return value >= INT_MIN && value <= INT_MAX; return value >= INT_MIN && value <= INT_MAX;
} }
static bool fits_in_int(int) { return true; }
}; };
const char RESET_COLOR[] = "\x1b[0m"; const char RESET_COLOR[] = "\x1b[0m";
@ -443,18 +444,20 @@ class BasicArgFormatter : public ArgVisitor<Impl, void> {
typedef typename BasicWriter<Char>::CharPtr CharPtr; typedef typename BasicWriter<Char>::CharPtr CharPtr;
Char fill = internal::CharTraits<Char>::cast(spec_.fill()); Char fill = internal::CharTraits<Char>::cast(spec_.fill());
CharPtr out = CharPtr(); CharPtr out = CharPtr();
if (spec_.width_ > 1) { const unsigned CHAR_WIDTH = 1;
if (spec_.width_ > CHAR_WIDTH) {
out = writer_.grow_buffer(spec_.width_); out = writer_.grow_buffer(spec_.width_);
if (spec_.align_ == ALIGN_RIGHT) { if (spec_.align_ == ALIGN_RIGHT) {
std::fill_n(out, spec_.width_ - 1, fill); std::fill_n(out, spec_.width_ - CHAR_WIDTH, fill);
out += spec_.width_ - 1; out += spec_.width_ - CHAR_WIDTH;
} else if (spec_.align_ == ALIGN_CENTER) { } else if (spec_.align_ == ALIGN_CENTER) {
out = writer_.fill_padding(out, spec_.width_, 1, fill); out = writer_.fill_padding(out, spec_.width_,
internal::check(CHAR_WIDTH), fill);
} else { } else {
std::fill_n(out + 1, spec_.width_ - 1, fill); std::fill_n(out + CHAR_WIDTH, spec_.width_ - CHAR_WIDTH, fill);
} }
} else { } else {
out = writer_.grow_buffer(1); out = writer_.grow_buffer(CHAR_WIDTH);
} }
*out = internal::CharTraits<Char>::cast(value); *out = internal::CharTraits<Char>::cast(value);
} }
@ -523,6 +526,13 @@ class PrintfArgFormatter :
} }
*out = static_cast<Char>(value); *out = static_cast<Char>(value);
} }
void visit_custom(Arg::CustomValue c) {
BasicFormatter<Char> formatter(ArgList(), this->writer());
const Char format_str[] = {'}', 0};
const Char *format = format_str;
c.format(&formatter, c.value, &format);
}
}; };
} // namespace internal } // namespace internal
} // namespace fmt } // namespace fmt
@ -773,8 +783,10 @@ void fmt::BasicWriter<Char>::write_str(
const StrChar *str_value = s.value; const StrChar *str_value = s.value;
std::size_t str_size = s.size; std::size_t str_size = s.size;
if (str_size == 0) { if (str_size == 0) {
if (!str_value) if (!str_value) {
FMT_THROW(FormatError("string pointer is null")); FMT_THROW(FormatError("string pointer is null"));
return;
}
if (*str_value) if (*str_value)
str_size = std::char_traits<StrChar>::length(str_value); str_size = std::char_traits<StrChar>::length(str_value);
} }
@ -1253,7 +1265,7 @@ FMT_FUNC void fmt::print(std::ostream &os, CStringRef format_str, ArgList args)
FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) { FMT_FUNC void fmt::print_colored(Color c, CStringRef format, ArgList args) {
char escape[] = "\x1b[30m"; char escape[] = "\x1b[30m";
escape[3] = '0' + static_cast<char>(c); escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout); std::fputs(escape, stdout);
print(format, args); print(format, args);
std::fputs(RESET_COLOR, stdout); std::fputs(RESET_COLOR, stdout);
@ -1313,6 +1325,6 @@ template int fmt::internal::CharTraits<wchar_t>::format_float(
#endif // FMT_HEADER_ONLY #endif // FMT_HEADER_ONLY
#if _MSC_VER #ifdef _MSC_VER
# pragma warning(pop) # pragma warning(pop)
#endif #endif

View File

@ -39,10 +39,23 @@
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <sstream>
#include <map> #include <map>
#if _SECURE_SCL #ifndef FMT_USE_IOSTREAMS
# define FMT_USE_IOSTREAMS 1
#endif
#if FMT_USE_IOSTREAMS
# include <sstream>
#endif
#ifdef _SECURE_SCL
# define FMT_SECURE_SCL _SECURE_SCL
#else
# define FMT_SECURE_SCL 0
#endif
#if FMT_SECURE_SCL
# include <iterator> # include <iterator>
#endif #endif
@ -93,6 +106,9 @@ inline uint32_t clzll(uint64_t x) {
// Disable the warning about declaration shadowing because it affects too // Disable the warning about declaration shadowing because it affects too
// many valid cases. // many valid cases.
# pragma GCC diagnostic ignored "-Wshadow" # pragma GCC diagnostic ignored "-Wshadow"
// Disable the warning about implicit conversions that may change the sign of
// an integer; silencing it otherwise would require many explicit casts.
# pragma GCC diagnostic ignored "-Wsign-conversion"
# endif # endif
# if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__ # if __cplusplus >= 201103L || defined __GXX_EXPERIMENTAL_CXX0X__
# define FMT_HAS_GXX_CXX11 1 # define FMT_HAS_GXX_CXX11 1
@ -154,9 +170,14 @@ inline uint32_t clzll(uint64_t x) {
#endif #endif
// 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).
#ifndef FMT_USE_NOEXCEPT
# define FMT_USE_NOEXCEPT 0
#endif
#ifndef FMT_NOEXCEPT #ifndef FMT_NOEXCEPT
# if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \ # if FMT_USE_NOEXCEPT || FMT_HAS_FEATURE(cxx_noexcept) || \
(FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) (FMT_GCC_VERSION >= 408 && FMT_HAS_GXX_CXX11) || \
_MSC_VER >= 1900
# define FMT_NOEXCEPT noexcept # define FMT_NOEXCEPT noexcept
# else # else
# define FMT_NOEXCEPT throw() # define FMT_NOEXCEPT throw()
@ -165,6 +186,10 @@ inline uint32_t clzll(uint64_t x) {
// 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
#ifndef FMT_USE_DELETED_FUNCTIONS
# define FMT_USE_DELETED_FUNCTIONS 0
#endif
#if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \ #if FMT_USE_DELETED_FUNCTIONS || FMT_HAS_FEATURE(cxx_deleted_functions) || \
(FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800 (FMT_GCC_VERSION >= 404 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1800
# define FMT_DELETED_OR_UNDEFINED = delete # define FMT_DELETED_OR_UNDEFINED = delete
@ -178,6 +203,16 @@ inline uint32_t clzll(uint64_t x) {
TypeName& operator=(const TypeName&) TypeName& operator=(const TypeName&)
#endif #endif
#ifndef FMT_USE_USER_DEFINED_LITERALS
// All compilers which support UDLs also support variadic templates. This
// makes the fmt::literals implementation easier. However, an explicit check
// for variadic templates is added here just in case.
# define FMT_USE_USER_DEFINED_LITERALS \
FMT_USE_VARIADIC_TEMPLATES && \
(FMT_HAS_FEATURE(cxx_user_literals) || \
(FMT_GCC_VERSION >= 407 && FMT_HAS_GXX_CXX11) || _MSC_VER >= 1900)
#endif
#ifndef FMT_ASSERT #ifndef FMT_ASSERT
# define FMT_ASSERT(condition, message) assert((condition) && message) # define FMT_ASSERT(condition, message) assert((condition) && message)
#endif #endif
@ -271,22 +306,38 @@ class BasicStringRef {
/** Returns the string size. */ /** Returns the string size. */
std::size_t size() const { return size_; } std::size_t size() const { return size_; }
// Lexicographically compare this string reference to other.
int compare(BasicStringRef other) const {
std::size_t size = std::min(size_, other.size_);
int result = std::char_traits<Char>::compare(data_, other.data_, size);
if (result == 0)
result = size_ == other.size_ ? 0 : (size_ < other.size_ ? -1 : 1);
return result;
}
friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) { friend bool operator==(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.data_ == rhs.data_; return lhs.compare(rhs) == 0;
} }
friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) { friend bool operator!=(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.data_ != rhs.data_; return lhs.compare(rhs) != 0;
} }
friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) { friend bool operator<(BasicStringRef lhs, BasicStringRef rhs) {
return std::lexicographical_compare( return lhs.compare(rhs) < 0;
lhs.data_, lhs.data_ + lhs.size_, rhs.data_, rhs.data_ + rhs.size_); }
friend bool operator<=(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.compare(rhs) <= 0;
}
friend bool operator>(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.compare(rhs) > 0;
}
friend bool operator>=(BasicStringRef lhs, BasicStringRef rhs) {
return lhs.compare(rhs) >= 0;
} }
}; };
typedef BasicStringRef<char> StringRef; typedef BasicStringRef<char> StringRef;
typedef BasicStringRef<wchar_t> WStringRef; typedef BasicStringRef<wchar_t> WStringRef;
/** /**
\rst \rst
A reference to a null terminated string. It can be constructed from a C A reference to a null terminated string. It can be constructed from a C
@ -349,7 +400,7 @@ namespace internal {
// to avoid dynamic memory allocation. // to avoid dynamic memory allocation.
enum { INLINE_BUFFER_SIZE = 500 }; enum { INLINE_BUFFER_SIZE = 500 };
#if _SECURE_SCL #if FMT_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) {
@ -450,9 +501,9 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
private: private:
T data_[SIZE]; T data_[SIZE];
// Free memory allocated by the buffer. // Deallocate memory allocated by the buffer.
void free() { void deallocate() {
if (this->ptr_ != data_) this->deallocate(this->ptr_, this->capacity_); if (this->ptr_ != data_) Allocator::deallocate(this->ptr_, this->capacity_);
} }
protected: protected:
@ -461,7 +512,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
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() { free(); } ~MemoryBuffer() { deallocate(); }
#if FMT_USE_RVALUE_REFERENCES #if FMT_USE_RVALUE_REFERENCES
private: private:
@ -478,7 +529,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
} 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 deallocating.
other.ptr_ = other.data_; other.ptr_ = other.data_;
} }
} }
@ -490,7 +541,7 @@ class MemoryBuffer : private Allocator, public Buffer<T> {
MemoryBuffer &operator=(MemoryBuffer &&other) { MemoryBuffer &operator=(MemoryBuffer &&other) {
assert(this != &other); assert(this != &other);
free(); deallocate();
move(other); move(other);
return *this; return *this;
} }
@ -516,7 +567,7 @@ void MemoryBuffer<T, SIZE, Allocator>::grow(std::size_t size) {
// the buffer already uses the new storage and will deallocate it in case // the buffer already uses the new storage and will deallocate it in case
// of exception. // of exception.
if (old_ptr != data_) if (old_ptr != data_)
this->deallocate(old_ptr, old_capacity); Allocator::deallocate(old_ptr, old_capacity);
} }
// A fixed-size buffer. // A fixed-size buffer.
@ -549,6 +600,15 @@ inline int isinfinity(long double x) { return isinf(x); }
inline int isinfinity(double x) { return std::isinf(x); } inline int isinfinity(double x) { return std::isinf(x); }
inline int isinfinity(long double x) { return std::isinf(x); } inline int isinfinity(long double x) { return std::isinf(x); }
# endif # endif
// Portable version of isnan.
# ifdef isnan
inline int isnotanumber(double x) { return isnan(x); }
inline int isnotanumber(long double x) { return isnan(x); }
# else
inline int isnotanumber(double x) { return std::isnan(x); }
inline int isnotanumber(long double x) { return std::isnan(x); }
# endif
#else #else
inline int getsign(double value) { inline int getsign(double value) {
if (value < 0) return 1; if (value < 0) return 1;
@ -562,12 +622,16 @@ inline int isinfinity(double x) { return !_finite(x); }
inline int isinfinity(long double x) { inline int isinfinity(long double x) {
return !_finite(static_cast<double>(x)); return !_finite(static_cast<double>(x));
} }
inline int isnotanumber(double x) { return _isnan(x); }
inline int isnotanumber(long double x) {
return _isnan(static_cast<double>(x));
}
#endif #endif
template <typename Char> template <typename Char>
class BasicCharTraits { class BasicCharTraits {
public: public:
#if _SECURE_SCL #if FMT_SECURE_SCL
typedef stdext::checked_array_iterator<Char*> CharPtr; typedef stdext::checked_array_iterator<Char*> CharPtr;
#else #else
typedef Char *CharPtr; typedef Char *CharPtr;
@ -718,7 +782,7 @@ inline void format_decimal(Char *buffer, UInt value, unsigned num_digits) {
// 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.
unsigned index = (value % 100) * 2; unsigned index = static_cast<unsigned>((value % 100) * 2);
value /= 100; value /= 100;
*--buffer = Data::DIGITS[index + 1]; *--buffer = Data::DIGITS[index + 1];
*--buffer = Data::DIGITS[index]; *--buffer = Data::DIGITS[index];
@ -851,7 +915,7 @@ struct WCharHelper<T, wchar_t> {
template <typename T> template <typename T>
class IsConvertibleToInt { class IsConvertibleToInt {
private: protected:
typedef char yes[1]; typedef char yes[1];
typedef char no[2]; typedef char no[2];
@ -890,7 +954,8 @@ struct Conditional<false, T, F> { typedef F type; };
// A helper function to suppress bogus "conditional expression is constant" // A helper function to suppress bogus "conditional expression is constant"
// warnings. // warnings.
inline bool check(bool value) { return value; } template <typename T>
inline T check(T value) { return value; }
// Makes an Arg object from any type. // Makes an Arg object from any type.
template <typename Char> template <typename Char>
@ -910,7 +975,9 @@ class MakeValue : public Arg {
// characters and strings into narrow strings as in // characters and strings into narrow strings as in
// fmt::format("{}", L"test"); // fmt::format("{}", L"test");
// To fix this, use a wide format string: fmt::format(L"{}", L"test"). // To fix this, use a wide format string: fmt::format(L"{}", L"test").
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported); MakeValue(typename WCharHelper<wchar_t, Char>::Unsupported);
#endif
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 wchar_t *, Char>::Unsupported);
MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported); MakeValue(typename WCharHelper<const std::wstring &, Char>::Unsupported);
@ -983,10 +1050,12 @@ class MakeValue : public Arg {
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)
#if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED)
MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) { MakeValue(typename WCharHelper<wchar_t, Char>::Supported value) {
int_value = value; int_value = value;
} }
static uint64_t type(wchar_t) { return Arg::CHAR; } static uint64_t type(wchar_t) { return Arg::CHAR; }
#endif
#define FMT_MAKE_STR_VALUE(Type, TYPE) \ #define FMT_MAKE_STR_VALUE(Type, TYPE) \
MakeValue(Type value) { set_string(value); } \ MakeValue(Type value) { set_string(value); } \
@ -1047,7 +1116,7 @@ struct NamedArg : Arg {
template <typename T> template <typename T>
NamedArg(BasicStringRef<Char> argname, const T &value) NamedArg(BasicStringRef<Char> argname, const T &value)
: name(argname), Arg(MakeValue<Char>(value)) { : Arg(MakeValue<Char>(value)), name(argname) {
type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value)); type = static_cast<internal::Arg::Type>(MakeValue<Char>::type(value));
} }
}; };
@ -1847,7 +1916,7 @@ class BasicWriter {
typedef typename internal::CharTraits<Char>::CharPtr CharPtr; typedef typename internal::CharTraits<Char>::CharPtr CharPtr;
#if _SECURE_SCL #if FMT_SECURE_SCL
// Returns pointer value. // Returns pointer value.
static Char *get(CharPtr p) { return p.base(); } static Char *get(CharPtr p) { return p.base(); }
#else #else
@ -2265,7 +2334,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
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-- = static_cast<Char>('0' + (n & 1));
} while ((n >>= 1) != 0); } while ((n >>= 1) != 0);
break; break;
} }
@ -2280,7 +2349,7 @@ void BasicWriter<Char>::write_int(T value, Spec spec) {
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-- = static_cast<Char>('0' + (n & 7));
} while ((n >>= 3) != 0); } while ((n >>= 3) != 0);
break; break;
} }
@ -2328,7 +2397,7 @@ void BasicWriter<Char>::write_double(
sign = spec.flag(PLUS_FLAG) ? '+' : ' '; sign = spec.flag(PLUS_FLAG) ? '+' : ' ';
} }
if (value != value) { if (internal::isnotanumber(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 nan_size = 4; std::size_t nan_size = 4;
@ -2396,7 +2465,7 @@ void BasicWriter<Char>::write_double(
Char fill = internal::CharTraits<Char>::cast(spec.fill()); Char fill = internal::CharTraits<Char>::cast(spec.fill());
for (;;) { for (;;) {
std::size_t buffer_size = buffer_.capacity() - offset; std::size_t buffer_size = buffer_.capacity() - offset;
#if _MSC_VER #ifdef _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.
@ -2677,17 +2746,6 @@ void print(std::FILE *f, CStringRef format_str, ArgList args);
*/ */
void print(CStringRef format_str, ArgList args); void print(CStringRef format_str, ArgList args);
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
void print(std::ostream &os, CStringRef format_str, ArgList args);
template <typename Char> template <typename Char>
void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) { void printf(BasicWriter<Char> &w, BasicCStringRef<Char> format, ArgList args) {
internal::PrintfFormatter<Char>(args).format(w, format); internal::PrintfFormatter<Char>(args).format(w, format);
@ -2708,6 +2766,12 @@ inline std::string sprintf(CStringRef format, ArgList args) {
return w.str(); return w.str();
} }
inline std::wstring sprintf(WCStringRef format, ArgList args) {
WMemoryWriter w;
printf(w, format, args);
return w.str();
}
/** /**
\rst \rst
Prints formatted data to the file *f*. Prints formatted data to the file *f*.
@ -2750,7 +2814,7 @@ class FormatInt {
// 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.
unsigned index = (value % 100) * 2; unsigned index = static_cast<unsigned>((value % 100) * 2);
value /= 100; value /= 100;
*--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];
@ -2993,12 +3057,90 @@ FMT_VARIADIC(std::string, format, CStringRef)
FMT_VARIADIC_W(std::wstring, format, WCStringRef) FMT_VARIADIC_W(std::wstring, format, WCStringRef)
FMT_VARIADIC(void, print, CStringRef) FMT_VARIADIC(void, print, CStringRef)
FMT_VARIADIC(void, print, std::FILE *, CStringRef) FMT_VARIADIC(void, print, std::FILE *, CStringRef)
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
FMT_VARIADIC(void, print_colored, Color, CStringRef) FMT_VARIADIC(void, print_colored, Color, CStringRef)
FMT_VARIADIC(std::string, sprintf, CStringRef) FMT_VARIADIC(std::string, sprintf, CStringRef)
FMT_VARIADIC_W(std::wstring, sprintf, WCStringRef)
FMT_VARIADIC(int, printf, CStringRef) FMT_VARIADIC(int, printf, CStringRef)
FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef) FMT_VARIADIC(int, fprintf, std::FILE *, CStringRef)
}
#if FMT_USE_IOSTREAMS
/**
\rst
Prints formatted data to the stream *os*.
**Example**::
print(cerr, "Don't {}!", "panic");
\endrst
*/
void print(std::ostream &os, CStringRef format_str, ArgList args);
FMT_VARIADIC(void, print, std::ostream &, CStringRef)
#endif
} // namespace fmt
#if FMT_USE_USER_DEFINED_LITERALS
namespace fmt {
namespace internal {
template <typename Char>
struct UdlFormat {
const Char *str;
template <typename... Args>
auto operator()(Args && ... args) const
-> decltype(format(str, std::forward<Args>(args)...)) {
return format(str, std::forward<Args>(args)...);
}
};
template <typename Char>
struct UdlArg {
const Char *str;
template <typename T>
NamedArg<Char> operator=(T &&value) const {
return {str, std::forward<T>(value)};
}
};
} // namespace internal
inline namespace literals {
/**
\rst
C++11 literal equivalent of :func:`fmt::format`.
**Example**::
using namespace fmt::literals;
std::string message = "The answer is {}"_format(42);
\endrst
*/
inline internal::UdlFormat<char>
operator"" _format(const char *s, std::size_t) { return {s}; }
inline internal::UdlFormat<wchar_t>
operator"" _format(const wchar_t *s, std::size_t) { return {s}; }
/**
\rst
C++11 literal equivalent of :func:`fmt::arg`.
**Example**::
using namespace fmt::literals;
print("Elapsed time: {s:.2f} seconds", "s"_a=1.23);
\endrst
*/
inline internal::UdlArg<char>
operator"" _a(const char *s, std::size_t) { return {s}; }
inline internal::UdlArg<wchar_t>
operator"" _a(const wchar_t *s, std::size_t) { return {s}; }
} // inline namespace literals
} // namespace fmt
#endif // FMT_USE_USER_DEFINED_LITERALS
// Restore warnings. // Restore warnings.
#if FMT_GCC_VERSION >= 406 #if FMT_GCC_VERSION >= 406