Upgraded to fmt ver 5.2.0

This commit is contained in:
gabime 2018-09-17 14:40:52 +03:00
parent f4ac67ae1c
commit 3771d12992
9 changed files with 5899 additions and 6772 deletions

View File

@ -0,0 +1,278 @@
// Formatting library for C++ - color support
//
// Copyright (c) 2018 - present, Victor Zverovich and fmt contributors
// All rights reserved.
//
// For the license information refer to format.h.
#ifndef FMT_COLOR_H_
#define FMT_COLOR_H_
#include "format.h"
FMT_BEGIN_NAMESPACE
#ifdef FMT_DEPRECATED_COLORS
// color and (v)print_colored are deprecated.
enum color { black, red, green, yellow, blue, magenta, cyan, white };
FMT_API void vprint_colored(color c, string_view format, format_args args);
FMT_API void vprint_colored(color c, wstring_view format, wformat_args args);
template <typename... Args>
inline void print_colored(color c, string_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args(args...));
}
template <typename... Args>
inline void print_colored(color c, wstring_view format_str,
const Args & ... args) {
vprint_colored(c, format_str, make_format_args<wformat_context>(args...));
}
inline void vprint_colored(color c, string_view format, format_args args) {
char escape[] = "\x1b[30m";
escape[3] = static_cast<char>('0' + c);
std::fputs(escape, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
inline void vprint_colored(color c, wstring_view format, wformat_args args) {
wchar_t escape[] = L"\x1b[30m";
escape[3] = static_cast<wchar_t>('0' + c);
std::fputws(escape, stdout);
vprint(format, args);
std::fputws(internal::data::WRESET_COLOR, stdout);
}
#else
// Experimental color support.
enum class color : uint32_t {
alice_blue = 0xF0F8FF, // rgb(240,248,255)
antique_white = 0xFAEBD7, // rgb(250,235,215)
aqua = 0x00FFFF, // rgb(0,255,255)
aquamarine = 0x7FFFD4, // rgb(127,255,212)
azure = 0xF0FFFF, // rgb(240,255,255)
beige = 0xF5F5DC, // rgb(245,245,220)
bisque = 0xFFE4C4, // rgb(255,228,196)
black = 0x000000, // rgb(0,0,0)
blanched_almond = 0xFFEBCD, // rgb(255,235,205)
blue = 0x0000FF, // rgb(0,0,255)
blue_violet = 0x8A2BE2, // rgb(138,43,226)
brown = 0xA52A2A, // rgb(165,42,42)
burly_wood = 0xDEB887, // rgb(222,184,135)
cadet_blue = 0x5F9EA0, // rgb(95,158,160)
chartreuse = 0x7FFF00, // rgb(127,255,0)
chocolate = 0xD2691E, // rgb(210,105,30)
coral = 0xFF7F50, // rgb(255,127,80)
cornflower_blue = 0x6495ED, // rgb(100,149,237)
cornsilk = 0xFFF8DC, // rgb(255,248,220)
crimson = 0xDC143C, // rgb(220,20,60)
cyan = 0x00FFFF, // rgb(0,255,255)
dark_blue = 0x00008B, // rgb(0,0,139)
dark_cyan = 0x008B8B, // rgb(0,139,139)
dark_golden_rod = 0xB8860B, // rgb(184,134,11)
dark_gray = 0xA9A9A9, // rgb(169,169,169)
dark_green = 0x006400, // rgb(0,100,0)
dark_khaki = 0xBDB76B, // rgb(189,183,107)
dark_magenta = 0x8B008B, // rgb(139,0,139)
dark_olive_green = 0x556B2F, // rgb(85,107,47)
dark_orange = 0xFF8C00, // rgb(255,140,0)
dark_orchid = 0x9932CC, // rgb(153,50,204)
dark_red = 0x8B0000, // rgb(139,0,0)
dark_salmon = 0xE9967A, // rgb(233,150,122)
dark_sea_green = 0x8FBC8F, // rgb(143,188,143)
dark_slate_blue = 0x483D8B, // rgb(72,61,139)
dark_slate_gray = 0x2F4F4F, // rgb(47,79,79)
dark_turquoise = 0x00CED1, // rgb(0,206,209)
dark_violet = 0x9400D3, // rgb(148,0,211)
deep_pink = 0xFF1493, // rgb(255,20,147)
deep_sky_blue = 0x00BFFF, // rgb(0,191,255)
dim_gray = 0x696969, // rgb(105,105,105)
dodger_blue = 0x1E90FF, // rgb(30,144,255)
fire_brick = 0xB22222, // rgb(178,34,34)
floral_white = 0xFFFAF0, // rgb(255,250,240)
forest_green = 0x228B22, // rgb(34,139,34)
fuchsia = 0xFF00FF, // rgb(255,0,255)
gainsboro = 0xDCDCDC, // rgb(220,220,220)
ghost_white = 0xF8F8FF, // rgb(248,248,255)
gold = 0xFFD700, // rgb(255,215,0)
golden_rod = 0xDAA520, // rgb(218,165,32)
gray = 0x808080, // rgb(128,128,128)
green = 0x008000, // rgb(0,128,0)
green_yellow = 0xADFF2F, // rgb(173,255,47)
honey_dew = 0xF0FFF0, // rgb(240,255,240)
hot_pink = 0xFF69B4, // rgb(255,105,180)
indian_red = 0xCD5C5C, // rgb(205,92,92)
indigo = 0x4B0082, // rgb(75,0,130)
ivory = 0xFFFFF0, // rgb(255,255,240)
khaki = 0xF0E68C, // rgb(240,230,140)
lavender = 0xE6E6FA, // rgb(230,230,250)
lavender_blush = 0xFFF0F5, // rgb(255,240,245)
lawn_green = 0x7CFC00, // rgb(124,252,0)
lemon_chiffon = 0xFFFACD, // rgb(255,250,205)
light_blue = 0xADD8E6, // rgb(173,216,230)
light_coral = 0xF08080, // rgb(240,128,128)
light_cyan = 0xE0FFFF, // rgb(224,255,255)
light_golden_rod_yellow = 0xFAFAD2, // rgb(250,250,210)
light_gray = 0xD3D3D3, // rgb(211,211,211)
light_green = 0x90EE90, // rgb(144,238,144)
light_pink = 0xFFB6C1, // rgb(255,182,193)
light_salmon = 0xFFA07A, // rgb(255,160,122)
light_sea_green = 0x20B2AA, // rgb(32,178,170)
light_sky_blue = 0x87CEFA, // rgb(135,206,250)
light_slate_gray = 0x778899, // rgb(119,136,153)
light_steel_blue = 0xB0C4DE, // rgb(176,196,222)
light_yellow = 0xFFFFE0, // rgb(255,255,224)
lime = 0x00FF00, // rgb(0,255,0)
lime_green = 0x32CD32, // rgb(50,205,50)
linen = 0xFAF0E6, // rgb(250,240,230)
magenta = 0xFF00FF, // rgb(255,0,255)
maroon = 0x800000, // rgb(128,0,0)
medium_aquamarine = 0x66CDAA, // rgb(102,205,170)
medium_blue = 0x0000CD, // rgb(0,0,205)
medium_orchid = 0xBA55D3, // rgb(186,85,211)
medium_purple = 0x9370DB, // rgb(147,112,219)
medium_sea_green = 0x3CB371, // rgb(60,179,113)
medium_slate_blue = 0x7B68EE, // rgb(123,104,238)
medium_spring_green = 0x00FA9A, // rgb(0,250,154)
medium_turquoise = 0x48D1CC, // rgb(72,209,204)
medium_violet_red = 0xC71585, // rgb(199,21,133)
midnight_blue = 0x191970, // rgb(25,25,112)
mint_cream = 0xF5FFFA, // rgb(245,255,250)
misty_rose = 0xFFE4E1, // rgb(255,228,225)
moccasin = 0xFFE4B5, // rgb(255,228,181)
navajo_white = 0xFFDEAD, // rgb(255,222,173)
navy = 0x000080, // rgb(0,0,128)
old_lace = 0xFDF5E6, // rgb(253,245,230)
olive = 0x808000, // rgb(128,128,0)
olive_drab = 0x6B8E23, // rgb(107,142,35)
orange = 0xFFA500, // rgb(255,165,0)
orange_red = 0xFF4500, // rgb(255,69,0)
orchid = 0xDA70D6, // rgb(218,112,214)
pale_golden_rod = 0xEEE8AA, // rgb(238,232,170)
pale_green = 0x98FB98, // rgb(152,251,152)
pale_turquoise = 0xAFEEEE, // rgb(175,238,238)
pale_violet_red = 0xDB7093, // rgb(219,112,147)
papaya_whip = 0xFFEFD5, // rgb(255,239,213)
peach_puff = 0xFFDAB9, // rgb(255,218,185)
peru = 0xCD853F, // rgb(205,133,63)
pink = 0xFFC0CB, // rgb(255,192,203)
plum = 0xDDA0DD, // rgb(221,160,221)
powder_blue = 0xB0E0E6, // rgb(176,224,230)
purple = 0x800080, // rgb(128,0,128)
rebecca_purple = 0x663399, // rgb(102,51,153)
red = 0xFF0000, // rgb(255,0,0)
rosy_brown = 0xBC8F8F, // rgb(188,143,143)
royal_blue = 0x4169E1, // rgb(65,105,225)
saddle_brown = 0x8B4513, // rgb(139,69,19)
salmon = 0xFA8072, // rgb(250,128,114)
sandy_brown = 0xF4A460, // rgb(244,164,96)
sea_green = 0x2E8B57, // rgb(46,139,87)
sea_shell = 0xFFF5EE, // rgb(255,245,238)
sienna = 0xA0522D, // rgb(160,82,45)
silver = 0xC0C0C0, // rgb(192,192,192)
sky_blue = 0x87CEEB, // rgb(135,206,235)
slate_blue = 0x6A5ACD, // rgb(106,90,205)
slate_gray = 0x708090, // rgb(112,128,144)
snow = 0xFFFAFA, // rgb(255,250,250)
spring_green = 0x00FF7F, // rgb(0,255,127)
steel_blue = 0x4682B4, // rgb(70,130,180)
tan = 0xD2B48C, // rgb(210,180,140)
teal = 0x008080, // rgb(0,128,128)
thistle = 0xD8BFD8, // rgb(216,191,216)
tomato = 0xFF6347, // rgb(255,99,71)
turquoise = 0x40E0D0, // rgb(64,224,208)
violet = 0xEE82EE, // rgb(238,130,238)
wheat = 0xF5DEB3, // rgb(245,222,179)
white = 0xFFFFFF, // rgb(255,255,255)
white_smoke = 0xF5F5F5, // rgb(245,245,245)
yellow = 0xFFFF00, // rgb(255,255,0)
yellow_green = 0x9ACD32, // rgb(154,205,50)
}; // enum class color
// rgb is a struct for red, green and blue colors.
// We use rgb as name because some editors will show it as color direct in the
// editor.
struct rgb {
FMT_CONSTEXPR_DECL rgb() : r(0), g(0), b(0) {}
FMT_CONSTEXPR_DECL rgb(uint8_t r_, uint8_t g_, uint8_t b_)
: r(r_), g(g_), b(b_) {}
FMT_CONSTEXPR_DECL rgb(uint32_t hex)
: r((hex >> 16) & 0xFF), g((hex >> 8) & 0xFF), b((hex) & 0xFF) {}
FMT_CONSTEXPR_DECL rgb(color hex)
: r((uint32_t(hex) >> 16) & 0xFF), g((uint32_t(hex) >> 8) & 0xFF),
b(uint32_t(hex) & 0xFF) {}
uint8_t r;
uint8_t g;
uint8_t b;
};
void vprint_rgb(rgb fd, string_view format, format_args args);
void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args);
/**
Formats a string and prints it to stdout using ANSI escape sequences to
specify foreground color 'fd'.
Example:
fmt::print(fmt::color::red, "Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename... Args>
inline void print(rgb fd, string_view format_str, const Args & ... args) {
vprint_rgb(fd, format_str, make_format_args(args...));
}
/**
Formats a string and prints it to stdout using ANSI escape sequences to
specify foreground color 'fd' and background color 'bg'.
Example:
fmt::print(fmt::color::red, fmt::color::black,
"Elapsed time: {0:.2f} seconds", 1.23);
*/
template <typename... Args>
inline void print(rgb fd, rgb bg, string_view format_str,
const Args & ... args) {
vprint_rgb(fd, bg, format_str, make_format_args(args...));
}
namespace internal {
FMT_CONSTEXPR void to_esc(uint8_t c, char out[], int offset) {
out[offset + 0] = static_cast<char>('0' + c / 100);
out[offset + 1] = static_cast<char>('0' + c / 10 % 10);
out[offset + 2] = static_cast<char>('0' + c % 10);
}
} // namespace internal
inline void vprint_rgb(rgb fd, string_view format, format_args args) {
char escape_fd[] = "\x1b[38;2;000;000;000m";
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
std::fputs(escape_fd, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
inline void vprint_rgb(rgb fd, rgb bg, string_view format, format_args args) {
char escape_fd[] = "\x1b[38;2;000;000;000m"; // foreground color
char escape_bg[] = "\x1b[48;2;000;000;000m"; // background color
internal::to_esc(fd.r, escape_fd, 7);
internal::to_esc(fd.g, escape_fd, 11);
internal::to_esc(fd.b, escape_fd, 15);
internal::to_esc(bg.r, escape_bg, 7);
internal::to_esc(bg.g, escape_bg, 11);
internal::to_esc(bg.b, escape_bg, 15);
std::fputs(escape_fd, stdout);
std::fputs(escape_bg, stdout);
vprint(format, args);
std::fputs(internal::data::RESET_COLOR, stdout);
}
#endif
FMT_END_NAMESPACE
#endif // FMT_COLOR_H_

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -14,22 +14,18 @@
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace internal { namespace internal {
template<class Char> template <class Char>
class formatbuf : public std::basic_streambuf<Char> class formatbuf : public std::basic_streambuf<Char> {
{ private:
private:
typedef typename std::basic_streambuf<Char>::int_type int_type; typedef typename std::basic_streambuf<Char>::int_type int_type;
typedef typename std::basic_streambuf<Char>::traits_type traits_type; typedef typename std::basic_streambuf<Char>::traits_type traits_type;
basic_buffer<Char> &buffer_; basic_buffer<Char> &buffer_;
public: public:
formatbuf(basic_buffer<Char> &buffer) formatbuf(basic_buffer<Char> &buffer) : buffer_(buffer) {}
: buffer_(buffer)
{
}
protected: protected:
// The put-area is actually always empty. This makes the implementation // The put-area is actually always empty. This makes the implementation
// simpler and has the advantage that the streambuf and the buffer are always // simpler and has the advantage that the streambuf and the buffer are always
// in sync and sputc never writes into uninitialized memory. The obvious // in sync and sputc never writes into uninitialized memory. The obvious
@ -37,69 +33,53 @@ protected:
// to overflow. There is no disadvantage here for sputn since this always // to overflow. There is no disadvantage here for sputn since this always
// results in a call to xsputn. // results in a call to xsputn.
int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE int_type overflow(int_type ch = traits_type::eof()) FMT_OVERRIDE {
{
if (!traits_type::eq_int_type(ch, traits_type::eof())) if (!traits_type::eq_int_type(ch, traits_type::eof()))
buffer_.push_back(static_cast<Char>(ch)); buffer_.push_back(static_cast<Char>(ch));
return ch; return ch;
} }
std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE std::streamsize xsputn(const Char *s, std::streamsize count) FMT_OVERRIDE {
{
buffer_.append(s, s + count); buffer_.append(s, s + count);
return count; return count;
} }
}; };
template<typename Char> template <typename Char>
struct test_stream : std::basic_ostream<Char> struct test_stream : std::basic_ostream<Char> {
{ private:
private:
struct null; struct null;
// Hide all operator<< from std::basic_ostream<Char>. // Hide all operator<< from std::basic_ostream<Char>.
void operator<<(null); void operator<<(null);
}; };
// Checks if T has a user-defined operator<< (e.g. not a member of // Checks if T has a user-defined operator<< (e.g. not a member of std::ostream).
// std::ostream). template <typename T, typename Char>
template<typename T, typename Char> class is_streamable {
class is_streamable private:
{ template <typename U>
private: static decltype(
template<typename U> internal::declval<test_stream<Char>&>()
static decltype(internal::declval<test_stream<Char> &>() << internal::declval<U>(), std::true_type()) test(int); << internal::declval<U>(), std::true_type()) test(int);
template<typename> template <typename>
static std::false_type test(...); static std::false_type test(...);
typedef decltype(test<T>(0)) result; typedef decltype(test<T>(0)) result;
public: public:
// std::string operator<< is not considered user-defined because we handle static const bool value = result::value;
// strings
// specially.
static const bool value = result::value && !std::is_same<T, std::string>::value;
};
// Disable conversion to int if T has an overloaded operator<< which is a free
// function (not a member of std::ostream).
template<typename T, typename Char>
class convert_to_int<T, Char, true>
{
public:
static const bool value = convert_to_int<T, Char, false>::value && !is_streamable<T, Char>::value;
}; };
// Write the content of buf to os. // Write the content of buf to os.
template<typename Char> template <typename Char>
void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf) {
{
const Char *data = buf.data(); const Char *data = buf.data();
typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize; typedef std::make_unsigned<std::streamsize>::type UnsignedStreamSize;
UnsignedStreamSize size = buf.size(); UnsignedStreamSize size = buf.size();
UnsignedStreamSize max_size = internal::to_unsigned((std::numeric_limits<std::streamsize>::max)()); UnsignedStreamSize max_size =
do internal::to_unsigned((std::numeric_limits<std::streamsize>::max)());
{ do {
UnsignedStreamSize n = size <= max_size ? size : max_size; UnsignedStreamSize n = size <= max_size ? size : max_size;
os.write(data, static_cast<std::streamsize>(n)); os.write(data, static_cast<std::streamsize>(n));
data += n; data += n;
@ -107,43 +87,47 @@ void write(std::basic_ostream<Char> &os, basic_buffer<Char> &buf)
} while (size != 0); } while (size != 0);
} }
template<typename Char, typename T> template <typename Char, typename T>
void format_value(basic_buffer<Char> &buffer, const T &value) void format_value(basic_buffer<Char> &buffer, const T &value) {
{
internal::formatbuf<Char> format_buf(buffer); internal::formatbuf<Char> format_buf(buffer);
std::basic_ostream<Char> output(&format_buf); std::basic_ostream<Char> output(&format_buf);
output.exceptions(std::ios_base::failbit | std::ios_base::badbit); output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
output << value; output << value;
buffer.resize(buffer.size()); buffer.resize(buffer.size());
} }
// Disable builtin formatting of enums and use operator<< instead.
template<typename T>
struct format_enum<T, typename std::enable_if<std::is_enum<T>::value>::type> : std::false_type
{
};
} // namespace internal } // namespace internal
// Formats an object of type T that has an overloaded ostream operator<<. // Disable conversion to int if T has an overloaded operator<< which is a free
template<typename T, typename Char> // function (not a member of std::ostream).
struct formatter<T, Char, typename std::enable_if<internal::is_streamable<T, Char>::value>::type> : formatter<basic_string_view<Char>, Char> template <typename T, typename Char>
{ struct convert_to_int<T, Char, void> {
static const bool value =
convert_to_int<T, Char, int>::value &&
!internal::is_streamable<T, Char>::value;
};
template<typename Context> // Formats an object of type T that has an overloaded ostream operator<<.
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) template <typename T, typename Char>
{ struct formatter<T, Char,
typename std::enable_if<
internal::is_streamable<T, Char>::value &&
!internal::format_type<
typename buffer_context<Char>::type, T>::value>::type>
: formatter<basic_string_view<Char>, Char> {
template <typename Context>
auto format(const T &value, Context &ctx) -> decltype(ctx.out()) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
internal::format_value(buffer, value); internal::format_value(buffer, value);
basic_string_view<Char> str(buffer.data(), buffer.size()); basic_string_view<Char> str(buffer.data(), buffer.size());
formatter<basic_string_view<Char>, Char>::format(str, ctx); return formatter<basic_string_view<Char>, Char>::format(str, ctx);
return ctx.out();
} }
}; };
template<typename Char> template <typename Char>
inline void vprint( inline void vprint(std::basic_ostream<Char> &os,
std::basic_ostream<Char> &os, basic_string_view<Char> format_str, basic_format_args<typename buffer_context<Char>::type> args) basic_string_view<Char> format_str,
{ basic_format_args<typename buffer_context<Char>::type> args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
vformat_to(buffer, format_str, args); vformat_to(buffer, format_str, args);
internal::write(os, buffer); internal::write(os, buffer);
@ -157,15 +141,15 @@ inline void vprint(
fmt::print(cerr, "Don't {}!", "panic"); fmt::print(cerr, "Don't {}!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline void print(std::ostream &os, string_view format_str, const Args &... args) inline void print(std::ostream &os, string_view format_str,
{ const Args & ... args) {
vprint<char>(os, format_str, make_format_args<format_context>(args...)); vprint<char>(os, format_str, make_format_args<format_context>(args...));
} }
template<typename... Args> template <typename... Args>
inline void print(std::wostream &os, wstring_view format_str, const Args &... args) inline void print(std::wostream &os, wstring_view format_str,
{ const Args & ... args) {
vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...)); vprint<wchar_t>(os, format_str, make_format_args<wformat_context>(args...));
} }
FMT_END_NAMESPACE FMT_END_NAMESPACE

View File

@ -10,7 +10,7 @@
#if defined(__MINGW32__) || defined(__CYGWIN__) #if defined(__MINGW32__) || defined(__CYGWIN__)
// Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/. // Workaround MinGW bug https://sourceforge.net/p/mingw/bugs/2024/.
#undef __STRICT_ANSI__ # undef __STRICT_ANSI__
#endif #endif
#include <errno.h> #include <errno.h>
@ -22,43 +22,42 @@
#include <cstddef> #include <cstddef>
#if defined __APPLE__ || defined(__FreeBSD__) #if defined __APPLE__ || defined(__FreeBSD__)
#include <xlocale.h> // for LC_NUMERIC_MASK on OS X # include <xlocale.h> // for LC_NUMERIC_MASK on OS X
#endif #endif
#include "format.h" #include "format.h"
#ifndef FMT_POSIX #ifndef FMT_POSIX
#if defined(_WIN32) && !defined(__MINGW32__) # if defined(_WIN32) && !defined(__MINGW32__)
// Fix warnings about deprecated symbols. // Fix warnings about deprecated symbols.
#define FMT_POSIX(call) _##call # define FMT_POSIX(call) _##call
#else # else
#define FMT_POSIX(call) call # define FMT_POSIX(call) call
#endif # endif
#endif #endif
// Calls to system functions are wrapped in FMT_SYSTEM for testability. // Calls to system functions are wrapped in FMT_SYSTEM for testability.
#ifdef FMT_SYSTEM #ifdef FMT_SYSTEM
#define FMT_POSIX_CALL(call) FMT_SYSTEM(call) # define FMT_POSIX_CALL(call) FMT_SYSTEM(call)
#else #else
#define FMT_SYSTEM(call) call # define FMT_SYSTEM(call) call
#ifdef _WIN32 # ifdef _WIN32
// Fix warnings about deprecated symbols. // Fix warnings about deprecated symbols.
#define FMT_POSIX_CALL(call) ::_##call # define FMT_POSIX_CALL(call) ::_##call
#else # else
#define FMT_POSIX_CALL(call) ::call # define FMT_POSIX_CALL(call) ::call
#endif # endif
#endif #endif
// Retries the expression while it evaluates to error_result and errno // Retries the expression while it evaluates to error_result and errno
// equals to EINTR. // equals to EINTR.
#ifndef _WIN32 #ifndef _WIN32
#define FMT_RETRY_VAL(result, expression, error_result) \ # define FMT_RETRY_VAL(result, expression, error_result) \
do \ do { \
{ \
result = (expression); \ result = (expression); \
} while (result == error_result && errno == EINTR) } while (result == error_result && errno == EINTR)
#else #else
#define FMT_RETRY_VAL(result, expression, error_result) result = (expression) # define FMT_RETRY_VAL(result, expression, error_result) result = (expression)
#endif #endif
#define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1) #define FMT_RETRY(result, expression) FMT_RETRY_VAL(result, expression, -1)
@ -90,141 +89,73 @@ FMT_BEGIN_NAMESPACE
format(std::string("{}"), 42); format(std::string("{}"), 42);
\endrst \endrst
*/ */
template<typename Char> template <typename Char>
class basic_cstring_view class basic_cstring_view {
{ private:
private:
const Char *data_; const Char *data_;
public: public:
/** Constructs a string reference object from a C string. */ /** Constructs a string reference object from a C string. */
basic_cstring_view(const Char *s) basic_cstring_view(const Char *s) : data_(s) {}
: data_(s)
{
}
/** /**
\rst \rst
Constructs a string reference from an ``std::string`` object. Constructs a string reference from an ``std::string`` object.
\endrst \endrst
*/ */
basic_cstring_view(const std::basic_string<Char> &s) basic_cstring_view(const std::basic_string<Char> &s) : data_(s.c_str()) {}
: data_(s.c_str())
{
}
/** 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_;
}
}; };
typedef basic_cstring_view<char> cstring_view; typedef basic_cstring_view<char> cstring_view;
typedef basic_cstring_view<wchar_t> wcstring_view; typedef basic_cstring_view<wchar_t> wcstring_view;
// An error code. // An error code.
class error_code class error_code {
{ private:
private:
int value_; int value_;
public: public:
explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {} explicit error_code(int value = 0) FMT_NOEXCEPT : value_(value) {}
int get() const FMT_NOEXCEPT int get() const FMT_NOEXCEPT { return value_; }
{
return value_;
}
}; };
// A buffered file. // A buffered file.
class buffered_file class buffered_file {
{ private:
private:
FILE *file_; FILE *file_;
friend class file; friend class file;
explicit buffered_file(FILE *f) explicit buffered_file(FILE *f) : file_(f) {}
: file_(f)
{
}
public: public:
// Constructs a buffered_file object which doesn't represent any file. // Constructs a buffered_file object which doesn't represent any file.
buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {} buffered_file() FMT_NOEXCEPT : file_(FMT_NULL) {}
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT; FMT_API ~buffered_file() FMT_DTOR_NOEXCEPT;
#if !FMT_USE_RVALUE_REFERENCES private:
// Emulate a move constructor and a move assignment operator if rvalue buffered_file(const buffered_file &) = delete;
// references are not supported. void operator=(const buffered_file &) = delete;
private:
// A proxy object to emulate a move constructor.
// It is private to make it impossible call operator Proxy directly.
struct Proxy
{
FILE *file;
};
public: public:
// A "move constructor" for moving from a temporary. buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_) {
buffered_file(Proxy p) FMT_NOEXCEPT : file_(p.file) {} other.file_ = FMT_NULL;
// A "move constructor" for moving from an lvalue.
buffered_file(buffered_file &f) FMT_NOEXCEPT : file_(f.file_)
{
f.file_ = FMT_NULL;
} }
// A "move assignment operator" for moving from a temporary. buffered_file& operator=(buffered_file &&other) {
buffered_file &operator=(Proxy p)
{
close();
file_ = p.file;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
buffered_file &operator=(buffered_file &other)
{
close(); close();
file_ = other.file_; file_ = other.file_;
other.file_ = FMT_NULL; other.file_ = FMT_NULL;
return *this; return *this;
} }
// Returns a proxy object for moving from a temporary:
// buffered_file file = buffered_file(...);
operator Proxy() FMT_NOEXCEPT
{
Proxy p = {file_};
file_ = FMT_NULL;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(buffered_file);
public:
buffered_file(buffered_file &&other) FMT_NOEXCEPT : file_(other.file_)
{
other.file_ = FMT_NULL;
}
buffered_file &operator=(buffered_file &&other)
{
close();
file_ = other.file_;
other.file_ = FMT_NULL;
return *this;
}
#endif
// Opens a file. // Opens a file.
FMT_API buffered_file(cstring_view filename, cstring_view mode); FMT_API buffered_file(cstring_view filename, cstring_view mode);
@ -232,23 +163,18 @@ public:
FMT_API void close(); FMT_API void close();
// Returns the pointer to a FILE object representing this file. // Returns the pointer to a FILE object representing this file.
FILE *get() const FMT_NOEXCEPT FILE *get() const FMT_NOEXCEPT { return file_; }
{
return file_;
}
// We place parentheses around fileno to workaround a bug in some versions // We place parentheses around fileno to workaround a bug in some versions
// of MinGW that define fileno as a macro. // of MinGW that define fileno as a macro.
FMT_API int(fileno)() const; FMT_API int (fileno)() const;
void vprint(string_view format_str, format_args args) void vprint(string_view format_str, format_args args) {
{
fmt::vprint(file_, format_str, args); fmt::vprint(file_, format_str, args);
} }
template<typename... Args> template <typename... Args>
inline void print(string_view format_str, const Args &... args) inline void print(string_view format_str, const Args & ... args) {
{
vprint(format_str, make_format_args(args...)); vprint(format_str, make_format_args(args...));
} }
}; };
@ -259,21 +185,16 @@ public:
// closing the file multiple times will cause a crash on Windows rather // closing the file multiple times will cause a crash on Windows rather
// than an exception. You can get standard behavior by overriding the // than an exception. You can get standard behavior by overriding the
// invalid parameter handler with _set_invalid_parameter_handler. // invalid parameter handler with _set_invalid_parameter_handler.
class file class file {
{ private:
private:
int fd_; // File descriptor. int fd_; // File descriptor.
// Constructs a file object with a given descriptor. // Constructs a file object with a given descriptor.
explicit file(int fd) explicit file(int fd) : fd_(fd) {}
: fd_(fd)
{
}
public: public:
// Possible values for the oflag argument to the constructor. // Possible values for the oflag argument to the constructor.
enum enum {
{
RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only. RDONLY = FMT_POSIX(O_RDONLY), // Open for reading only.
WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only. WRONLY = FMT_POSIX(O_WRONLY), // Open for writing only.
RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing. RDWR = FMT_POSIX(O_RDWR) // Open for reading and writing.
@ -285,81 +206,27 @@ public:
// Opens a file and constructs a file object representing this file. // Opens a file and constructs a file object representing this file.
FMT_API file(cstring_view path, int oflag); FMT_API file(cstring_view path, int oflag);
#if !FMT_USE_RVALUE_REFERENCES private:
// Emulate a move constructor and a move assignment operator if rvalue file(const file &) = delete;
// references are not supported. void operator=(const file &) = delete;
private: public:
// A proxy object to emulate a move constructor. file(file &&other) FMT_NOEXCEPT : fd_(other.fd_) {
// It is private to make it impossible call operator Proxy directly.
struct Proxy
{
int fd;
};
public:
// A "move constructor" for moving from a temporary.
file(Proxy p) FMT_NOEXCEPT : fd_(p.fd) {}
// A "move constructor" for moving from an lvalue.
file(file &other) FMT_NOEXCEPT : fd_(other.fd_)
{
other.fd_ = -1; other.fd_ = -1;
} }
// A "move assignment operator" for moving from a temporary. file& operator=(file &&other) {
file &operator=(Proxy p)
{
close();
fd_ = p.fd;
return *this;
}
// A "move assignment operator" for moving from an lvalue.
file &operator=(file &other)
{
close(); close();
fd_ = other.fd_; fd_ = other.fd_;
other.fd_ = -1; other.fd_ = -1;
return *this; return *this;
} }
// Returns a proxy object for moving from a temporary:
// file f = file(...);
operator Proxy() FMT_NOEXCEPT
{
Proxy p = {fd_};
fd_ = -1;
return p;
}
#else
private:
FMT_DISALLOW_COPY_AND_ASSIGN(file);
public:
file(file &&other) FMT_NOEXCEPT : fd_(other.fd_)
{
other.fd_ = -1;
}
file &operator=(file &&other)
{
close();
fd_ = other.fd_;
other.fd_ = -1;
return *this;
}
#endif
// Destroys the object closing the file it represents if any. // Destroys the object closing the file it represents if any.
FMT_API ~file() FMT_DTOR_NOEXCEPT; FMT_API ~file() FMT_DTOR_NOEXCEPT;
// Returns the file descriptor. // Returns the file descriptor.
int descriptor() const FMT_NOEXCEPT int descriptor() const FMT_NOEXCEPT { return fd_; }
{
return fd_;
}
// Closes the file. // Closes the file.
FMT_API void close(); FMT_API void close();
@ -398,66 +265,53 @@ public:
// Returns the memory page size. // Returns the memory page size.
long getpagesize(); long getpagesize();
#if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) #if (defined(LC_NUMERIC_MASK) || defined(_MSC_VER)) && \
#define FMT_LOCALE !defined(__ANDROID__) && !defined(__CYGWIN__) && !defined(__OpenBSD__) && \
!defined(__NEWLIB_H__)
# define FMT_LOCALE
#endif #endif
#ifdef FMT_LOCALE #ifdef FMT_LOCALE
// A "C" numeric locale. // A "C" numeric locale.
class Locale class Locale {
{ private:
private: # ifdef _MSC_VER
#ifdef _MSC_VER
typedef _locale_t locale_t; typedef _locale_t locale_t;
enum enum { LC_NUMERIC_MASK = LC_NUMERIC };
{
LC_NUMERIC_MASK = LC_NUMERIC
};
static locale_t newlocale(int category_mask, const char *locale, locale_t) static locale_t newlocale(int category_mask, const char *locale, locale_t) {
{
return _create_locale(category_mask, locale); return _create_locale(category_mask, locale);
} }
static void freelocale(locale_t locale) static void freelocale(locale_t locale) {
{
_free_locale(locale); _free_locale(locale);
} }
static double strtod_l(const char *nptr, char **endptr, _locale_t locale) static double strtod_l(const char *nptr, char **endptr, _locale_t locale) {
{
return _strtod_l(nptr, endptr, locale); return _strtod_l(nptr, endptr, locale);
} }
#endif # endif
locale_t locale_; locale_t locale_;
FMT_DISALLOW_COPY_AND_ASSIGN(Locale); Locale(const Locale &) = delete;
void operator=(const Locale &) = delete;
public: public:
typedef locale_t Type; typedef locale_t Type;
Locale() Locale() : locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL)) {
: locale_(newlocale(LC_NUMERIC_MASK, "C", FMT_NULL))
{
if (!locale_) if (!locale_)
FMT_THROW(system_error(errno, "cannot create locale")); FMT_THROW(system_error(errno, "cannot create locale"));
} }
~Locale() ~Locale() { freelocale(locale_); }
{
freelocale(locale_);
}
Type get() const Type get() const { return locale_; }
{
return locale_;
}
// Converts string to floating-point number and advances str past the end // Converts string to floating-point number and advances str past the end
// of the parsed input. // of the parsed input.
double strtod(const char *&str) const double strtod(const char *&str) const {
{
char *end = FMT_NULL; char *end = FMT_NULL;
double result = strtod_l(str, &end, locale_); double result = strtod_l(str, &end, locale_);
str = end; str = end;
@ -467,18 +321,4 @@ public:
#endif // FMT_LOCALE #endif // FMT_LOCALE
FMT_END_NAMESPACE FMT_END_NAMESPACE
#if !FMT_USE_RVALUE_REFERENCES
namespace std {
// For compatibility with C++98.
inline fmt::buffered_file &move(fmt::buffered_file &f)
{
return f;
}
inline fmt::file &move(fmt::file &f)
{
return f;
}
} // namespace std
#endif
#endif // FMT_POSIX_H_ #endif // FMT_POSIX_H_

View File

@ -18,141 +18,111 @@ namespace internal {
// Checks if a value fits in int - used to avoid warnings about comparing // Checks if a value fits in int - used to avoid warnings about comparing
// signed and unsigned integers. // signed and unsigned integers.
template<bool IsSigned> template <bool IsSigned>
struct int_checker struct int_checker {
{ template <typename T>
template<typename T> static bool fits_in_int(T value) {
static bool fits_in_int(T value)
{
unsigned max = std::numeric_limits<int>::max(); unsigned max = std::numeric_limits<int>::max();
return value <= max; return value <= max;
} }
static bool fits_in_int(bool) static bool fits_in_int(bool) { return true; }
{
return true;
}
}; };
template<> template <>
struct int_checker<true> struct int_checker<true> {
{ template <typename T>
template<typename T> static bool fits_in_int(T value) {
static bool fits_in_int(T value) return value >= std::numeric_limits<int>::min() &&
{ value <= std::numeric_limits<int>::max();
return value >= std::numeric_limits<int>::min() && value <= std::numeric_limits<int>::max();
}
static bool fits_in_int(int)
{
return true;
} }
static bool fits_in_int(int) { return true; }
}; };
class printf_precision_handler : public function<int> class printf_precision_handler: public function<int> {
{ public:
public: template <typename T>
template<typename T> typename std::enable_if<std::is_integral<T>::value, int>::type
typename std::enable_if<std::is_integral<T>::value, int>::type operator()(T value) operator()(T value) {
{
if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value)) if (!int_checker<std::numeric_limits<T>::is_signed>::fits_in_int(value))
FMT_THROW(format_error("number is too big")); FMT_THROW(format_error("number is too big"));
return static_cast<int>(value); return static_cast<int>(value);
} }
template<typename T> template <typename T>
typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) typename std::enable_if<!std::is_integral<T>::value, int>::type operator()(T) {
{
FMT_THROW(format_error("precision is not integer")); FMT_THROW(format_error("precision is not integer"));
return 0; return 0;
} }
}; };
// An argument visitor that returns true iff arg is a zero integer. // An argument visitor that returns true iff arg is a zero integer.
class is_zero_int : public function<bool> class is_zero_int: public function<bool> {
{ public:
public: template <typename T>
template<typename T> typename std::enable_if<std::is_integral<T>::value, bool>::type
typename std::enable_if<std::is_integral<T>::value, bool>::type operator()(T value) operator()(T value) { return value == 0; }
{
return value == 0;
}
template<typename T> template <typename T>
typename std::enable_if<!std::is_integral<T>::value, bool>::type operator()(T) typename std::enable_if<!std::is_integral<T>::value, bool>::type
{ operator()(T) { return false; }
return false;
}
}; };
template<typename T> template <typename T>
struct make_unsigned_or_bool : std::make_unsigned<T> struct make_unsigned_or_bool : std::make_unsigned<T> {};
{
};
template<> template <>
struct make_unsigned_or_bool<bool> struct make_unsigned_or_bool<bool> {
{
typedef bool type; typedef bool type;
}; };
template<typename T, typename Context> template <typename T, typename Context>
class arg_converter : public function<void> class arg_converter: public function<void> {
{ private:
private:
typedef typename Context::char_type Char; typedef typename Context::char_type Char;
basic_format_arg<Context> &arg_; basic_format_arg<Context> &arg_;
typename Context::char_type type_; typename Context::char_type type_;
public: public:
arg_converter(basic_format_arg<Context> &arg, Char type) arg_converter(basic_format_arg<Context> &arg, Char type)
: arg_(arg) : arg_(arg), type_(type) {}
, type_(type)
{
}
void operator()(bool value) void operator()(bool value) {
{
if (type_ != 's') if (type_ != 's')
operator()<bool>(value); operator()<bool>(value);
} }
template<typename U> template <typename U>
typename std::enable_if<std::is_integral<U>::value>::type operator()(U value) typename std::enable_if<std::is_integral<U>::value>::type
{ operator()(U value) {
bool is_signed = type_ == 'd' || type_ == 'i'; bool is_signed = type_ == 'd' || type_ == 'i';
typedef typename std::conditional<std::is_same<T, void>::value, U, T>::type TargetType; typedef typename std::conditional<
if (const_check(sizeof(TargetType) <= sizeof(int))) std::is_same<T, void>::value, U, T>::type TargetType;
{ if (const_check(sizeof(TargetType) <= sizeof(int))) {
// Extra casts are used to silence warnings. // Extra casts are used to silence warnings.
if (is_signed) if (is_signed) {
{ arg_ = internal::make_arg<Context>(
arg_ = internal::make_arg<Context>(static_cast<int>(static_cast<TargetType>(value))); static_cast<int>(static_cast<TargetType>(value)));
} } else {
else
{
typedef typename make_unsigned_or_bool<TargetType>::type Unsigned; typedef typename make_unsigned_or_bool<TargetType>::type Unsigned;
arg_ = internal::make_arg<Context>(static_cast<unsigned>(static_cast<Unsigned>(value))); arg_ = internal::make_arg<Context>(
static_cast<unsigned>(static_cast<Unsigned>(value)));
} }
} } else {
else if (is_signed) {
{
if (is_signed)
{
// glibc's printf doesn't sign extend arguments of smaller types: // glibc's printf doesn't sign extend arguments of smaller types:
// std::printf("%lld", -42); // prints "4294967254" // std::printf("%lld", -42); // prints "4294967254"
// but we don't have to do the same because it's a UB. // but we don't have to do the same because it's a UB.
arg_ = internal::make_arg<Context>(static_cast<long long>(value)); arg_ = internal::make_arg<Context>(static_cast<long long>(value));
} } else {
else arg_ = internal::make_arg<Context>(
{ static_cast<typename make_unsigned_or_bool<U>::type>(value));
arg_ = internal::make_arg<Context>(static_cast<typename make_unsigned_or_bool<U>::type>(value));
} }
} }
} }
template<typename U> template <typename U>
typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) typename std::enable_if<!std::is_integral<U>::value>::type operator()(U) {
{
// No coversion needed for non-integral types. // No coversion needed for non-integral types.
} }
}; };
@ -161,66 +131,51 @@ public:
// If T is void, the argument is converted to corresponding signed or unsigned // If T is void, the argument is converted to corresponding signed or unsigned
// type depending on the type specifier: 'd' and 'i' - signed, other - // type depending on the type specifier: 'd' and 'i' - signed, other -
// unsigned). // unsigned).
template<typename T, typename Context, typename Char> template <typename T, typename Context, typename Char>
void convert_arg(basic_format_arg<Context> &arg, Char type) void convert_arg(basic_format_arg<Context> &arg, Char type) {
{
visit(arg_converter<T, Context>(arg, type), arg); visit(arg_converter<T, Context>(arg, type), arg);
} }
// Converts an integer argument to char for printf. // Converts an integer argument to char for printf.
template<typename Context> template <typename Context>
class char_converter : public function<void> class char_converter: public function<void> {
{ private:
private:
basic_format_arg<Context> &arg_; basic_format_arg<Context> &arg_;
FMT_DISALLOW_COPY_AND_ASSIGN(char_converter); public:
explicit char_converter(basic_format_arg<Context> &arg) : arg_(arg) {}
public: template <typename T>
explicit char_converter(basic_format_arg<Context> &arg) typename std::enable_if<std::is_integral<T>::value>::type
: arg_(arg) operator()(T value) {
{
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value>::type operator()(T value)
{
typedef typename Context::char_type Char; typedef typename Context::char_type Char;
arg_ = internal::make_arg<Context>(static_cast<Char>(value)); arg_ = internal::make_arg<Context>(static_cast<Char>(value));
} }
template<typename T> template <typename T>
typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) typename std::enable_if<!std::is_integral<T>::value>::type operator()(T) {
{
// No coversion needed for non-integral types. // No coversion needed for non-integral types.
} }
}; };
// 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.
template<typename Char> template <typename Char>
class printf_width_handler : public function<unsigned> class printf_width_handler: public function<unsigned> {
{ private:
private:
typedef basic_format_specs<Char> format_specs; typedef basic_format_specs<Char> format_specs;
format_specs &spec_; format_specs &spec_;
FMT_DISALLOW_COPY_AND_ASSIGN(printf_width_handler); public:
explicit printf_width_handler(format_specs &spec) : spec_(spec) {}
public: template <typename T>
explicit printf_width_handler(format_specs &spec) typename std::enable_if<std::is_integral<T>::value, unsigned>::type
: spec_(spec) operator()(T value) {
{
}
template<typename T>
typename std::enable_if<std::is_integral<T>::value, unsigned>::type operator()(T value)
{
typedef typename internal::int_traits<T>::main_type UnsignedType; typedef typename internal::int_traits<T>::main_type UnsignedType;
UnsignedType width = static_cast<UnsignedType>(value); UnsignedType width = static_cast<UnsignedType>(value);
if (internal::is_negative(value)) if (internal::is_negative(value)) {
{
spec_.align_ = ALIGN_LEFT; spec_.align_ = ALIGN_LEFT;
width = 0 - width; width = 0 - width;
} }
@ -230,19 +185,22 @@ public:
return static_cast<unsigned>(width); return static_cast<unsigned>(width);
} }
template<typename T> template <typename T>
typename std::enable_if<!std::is_integral<T>::value, unsigned>::type operator()(T) typename std::enable_if<!std::is_integral<T>::value, unsigned>::type
{ operator()(T) {
FMT_THROW(format_error("width is not integer")); FMT_THROW(format_error("width is not integer"));
return 0; return 0;
} }
}; };
} // namespace internal } // namespace internal
template<typename Range> template <typename Range>
class printf_arg_formatter; class printf_arg_formatter;
template<typename OutputIt, typename Char, typename ArgFormatter = printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>> template <
typename OutputIt, typename Char,
typename ArgFormatter =
printf_arg_formatter<back_insert_range<internal::basic_buffer<Char>>>>
class basic_printf_context; class basic_printf_context;
/** /**
@ -250,11 +208,12 @@ class basic_printf_context;
The ``printf`` argument formatter. The ``printf`` argument formatter.
\endrst \endrst
*/ */
template<typename Range> template <typename Range>
class printf_arg_formatter : public internal::function<typename internal::arg_formatter_base<Range>::iterator>, class printf_arg_formatter:
public internal::arg_formatter_base<Range> public internal::function<
{ typename internal::arg_formatter_base<Range>::iterator>,
private: public internal::arg_formatter_base<Range> {
private:
typedef typename Range::value_type char_type; typedef typename Range::value_type char_type;
typedef decltype(internal::declval<Range>().begin()) iterator; typedef decltype(internal::declval<Range>().begin()) iterator;
typedef internal::arg_formatter_base<Range> base; typedef internal::arg_formatter_base<Range> base;
@ -262,19 +221,17 @@ private:
context_type &context_; context_type &context_;
void write_null_pointer(char) void write_null_pointer(char) {
{ this->spec()->type_ = 0;
this->spec().type_ = 0;
this->write("(nil)"); this->write("(nil)");
} }
void write_null_pointer(wchar_t) void write_null_pointer(wchar_t) {
{ this->spec()->type_ = 0;
this->spec().type_ = 0;
this->write(L"(nil)"); this->write(L"(nil)");
} }
public: public:
typedef typename base::format_specs format_specs; typedef typename base::format_specs format_specs;
/** /**
@ -284,53 +241,46 @@ public:
specifier information for standard argument types. specifier information for standard argument types.
\endrst \endrst
*/ */
printf_arg_formatter(internal::basic_buffer<char_type> &buffer, format_specs &spec, context_type &ctx) printf_arg_formatter(internal::basic_buffer<char_type> &buffer,
: base(back_insert_range<internal::basic_buffer<char_type>>(buffer), spec) format_specs &spec, context_type &ctx)
, context_(ctx) : base(back_insert_range<internal::basic_buffer<char_type>>(buffer), &spec),
{ context_(ctx) {}
}
template<typename T> template <typename T>
typename std::enable_if<std::is_integral<T>::value, iterator>::type operator()(T value) typename std::enable_if<std::is_integral<T>::value, iterator>::type
{ operator()(T value) {
// MSVC2013 fails to compile separate overloads for bool and char_type so // MSVC2013 fails to compile separate overloads for bool and char_type so
// use std::is_same instead. // use std::is_same instead.
if (std::is_same<T, bool>::value) if (std::is_same<T, bool>::value) {
{ format_specs &fmt_spec = *this->spec();
format_specs &fmt_spec = this->spec();
if (fmt_spec.type_ != 's') if (fmt_spec.type_ != 's')
return base::operator()(value ? 1 : 0); return base::operator()(value ? 1 : 0);
fmt_spec.type_ = 0; fmt_spec.type_ = 0;
this->write(value != 0); this->write(value != 0);
} } else if (std::is_same<T, char_type>::value) {
else if (std::is_same<T, char_type>::value) format_specs &fmt_spec = *this->spec();
{
format_specs &fmt_spec = this->spec();
if (fmt_spec.type_ && fmt_spec.type_ != 'c') if (fmt_spec.type_ && fmt_spec.type_ != 'c')
return (*this)(static_cast<int>(value)); return (*this)(static_cast<int>(value));
fmt_spec.flags_ = 0; fmt_spec.flags_ = 0;
fmt_spec.align_ = ALIGN_RIGHT; fmt_spec.align_ = ALIGN_RIGHT;
return base::operator()(value); return base::operator()(value);
} } else {
else
{
return base::operator()(value); return base::operator()(value);
} }
return this->out(); return this->out();
} }
template<typename T> template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, iterator>::type operator()(T value) typename std::enable_if<std::is_floating_point<T>::value, iterator>::type
{ operator()(T value) {
return base::operator()(value); return base::operator()(value);
} }
/** Formats a null-terminated C string. */ /** Formats a null-terminated C string. */
iterator operator()(const char *value) iterator operator()(const char *value) {
{
if (value) if (value)
base::operator()(value); base::operator()(value);
else if (this->spec().type_ == 'p') else if (this->spec()->type_ == 'p')
write_null_pointer(char_type()); write_null_pointer(char_type());
else else
this->write("(null)"); this->write("(null)");
@ -338,77 +288,67 @@ public:
} }
/** Formats a null-terminated wide C string. */ /** Formats a null-terminated wide C string. */
iterator operator()(const wchar_t *value) iterator operator()(const wchar_t *value) {
{
if (value) if (value)
base::operator()(value); base::operator()(value);
else if (this->spec().type_ == 'p') else if (this->spec()->type_ == 'p')
write_null_pointer(char_type()); write_null_pointer(char_type());
else else
this->write(L"(null)"); this->write(L"(null)");
return this->out(); return this->out();
} }
iterator operator()(basic_string_view<char_type> value) iterator operator()(basic_string_view<char_type> value) {
{
return base::operator()(value); return base::operator()(value);
} }
iterator operator()(monostate value) iterator operator()(monostate value) {
{
return base::operator()(value); return base::operator()(value);
} }
/** Formats a pointer. */ /** Formats a pointer. */
iterator operator()(const void *value) iterator operator()(const void *value) {
{
if (value) if (value)
return base::operator()(value); return base::operator()(value);
this->spec().type_ = 0; this->spec()->type_ = 0;
write_null_pointer(char_type()); write_null_pointer(char_type());
return this->out(); return this->out();
} }
/** Formats an argument of a custom (user-defined) type. */ /** Formats an argument of a custom (user-defined) type. */
iterator operator()(typename basic_format_arg<context_type>::handle handle) iterator operator()(typename basic_format_arg<context_type>::handle handle) {
{
handle.format(context_); handle.format(context_);
return this->out(); return this->out();
} }
}; };
template<typename T> template <typename T>
struct printf_formatter struct printf_formatter {
{ template <typename ParseContext>
template<typename ParseContext> auto parse(ParseContext &ctx) -> decltype(ctx.begin()) { return ctx.begin(); }
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
return ctx.begin();
}
template<typename FormatContext> template <typename FormatContext>
auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) auto format(const T &value, FormatContext &ctx) -> decltype(ctx.out()) {
{
internal::format_value(internal::get_container(ctx.out()), value); internal::format_value(internal::get_container(ctx.out()), value);
return ctx.out(); return ctx.out();
} }
}; };
/** This template formats data and writes the output to a writer. */ /** This template formats data and writes the output to a writer. */
template<typename OutputIt, typename Char, typename ArgFormatter> template <typename OutputIt, typename Char, typename ArgFormatter>
class basic_printf_context : private internal::context_base<OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> class basic_printf_context :
{ // Inherit publicly as a workaround for the icc bug
public: // https://software.intel.com/en-us/forums/intel-c-compiler/topic/783476.
public internal::context_base<
OutputIt, basic_printf_context<OutputIt, Char, ArgFormatter>, Char> {
public:
/** The character type for the output. */ /** The character type for the output. */
typedef Char char_type; typedef Char char_type;
template<typename T> template <typename T>
struct formatter_type struct formatter_type { typedef printf_formatter<T> type; };
{
typedef printf_formatter<T> type;
};
private: private:
typedef internal::context_base<OutputIt, basic_printf_context, Char> base; typedef internal::context_base<OutputIt, basic_printf_context, Char> base;
typedef typename base::format_arg format_arg; typedef typename base::format_arg format_arg;
typedef basic_format_specs<char_type> format_specs; typedef basic_format_specs<char_type> format_specs;
@ -418,12 +358,14 @@ private:
// Returns the argument with specified index or, if arg_index is equal // Returns the argument with specified index or, if arg_index is equal
// to the maximum unsigned value, the next argument. // to the maximum unsigned value, the next argument.
format_arg get_arg(iterator it, unsigned arg_index = (std::numeric_limits<unsigned>::max)()); format_arg get_arg(
iterator it,
unsigned arg_index = (std::numeric_limits<unsigned>::max)());
// Parses argument index, flags and width and returns the argument index. // Parses argument index, flags and width and returns the argument index.
unsigned parse_header(iterator &it, format_specs &spec); unsigned parse_header(iterator &it, format_specs &spec);
public: public:
/** /**
\rst \rst
Constructs a ``printf_context`` object. References to the arguments and Constructs a ``printf_context`` object. References to the arguments and
@ -431,26 +373,23 @@ public:
appropriate lifetimes. appropriate lifetimes.
\endrst \endrst
*/ */
basic_printf_context(OutputIt out, basic_string_view<char_type> format_str, basic_format_args<basic_printf_context> args) basic_printf_context(OutputIt out, basic_string_view<char_type> format_str,
: base(out, format_str, args) basic_format_args<basic_printf_context> args)
{ : base(out, format_str, args) {}
}
using base::advance_to;
using base::out;
using base::parse_context; using base::parse_context;
using base::out;
using base::advance_to;
/** Formats stored arguments and writes the output to the range. */ /** Formats stored arguments and writes the output to the range. */
void format(); void format();
}; };
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs &spec, iterator &it) void basic_printf_context<OutputIt, Char, AF>::parse_flags(
{ format_specs &spec, iterator &it) {
for (;;) for (;;) {
{ switch (*it++) {
switch (*it++)
{
case '-': case '-':
spec.align_ = ALIGN_LEFT; spec.align_ = ALIGN_LEFT;
break; break;
@ -473,38 +412,33 @@ void basic_printf_context<OutputIt, Char, AF>::parse_flags(format_specs &spec, i
} }
} }
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
typename basic_printf_context<OutputIt, Char, AF>::format_arg basic_printf_context<OutputIt, Char, AF>::get_arg( typename basic_printf_context<OutputIt, Char, AF>::format_arg
iterator it, unsigned arg_index) basic_printf_context<OutputIt, Char, AF>::get_arg(
{ iterator it, unsigned arg_index) {
(void)it; (void)it;
if (arg_index == std::numeric_limits<unsigned>::max()) if (arg_index == std::numeric_limits<unsigned>::max())
return this->do_get_arg(this->parse_context().next_arg_id()); return this->do_get_arg(this->parse_context().next_arg_id());
return base::get_arg(arg_index - 1); return base::get_arg(arg_index - 1);
} }
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(iterator &it, format_specs &spec) unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(
{ iterator &it, format_specs &spec) {
unsigned arg_index = std::numeric_limits<unsigned>::max(); unsigned arg_index = std::numeric_limits<unsigned>::max();
char_type c = *it; char_type c = *it;
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9') {
{
// Parse an argument index (if followed by '$') or a width possibly // Parse an argument index (if followed by '$') or a width possibly
// preceded with '0' flag(s). // preceded with '0' flag(s).
internal::error_handler eh; internal::error_handler eh;
unsigned value = parse_nonnegative_int(it, eh); unsigned value = parse_nonnegative_int(it, eh);
if (*it == '$') if (*it == '$') { // value is an argument index
{ // value is an argument index
++it; ++it;
arg_index = value; arg_index = value;
} } else {
else
{
if (c == '0') if (c == '0')
spec.fill_ = '0'; spec.fill_ = '0';
if (value != 0) if (value != 0) {
{
// Nonzero value means that we parsed width and don't need to // Nonzero value means that we parsed width and don't need to
// parse it or flags again, so return now. // parse it or flags again, so return now.
spec.width_ = value; spec.width_ = value;
@ -514,33 +448,27 @@ unsigned basic_printf_context<OutputIt, Char, AF>::parse_header(iterator &it, fo
} }
parse_flags(spec, it); parse_flags(spec, it);
// Parse width. // Parse width.
if (*it >= '0' && *it <= '9') if (*it >= '0' && *it <= '9') {
{
internal::error_handler eh; internal::error_handler eh;
spec.width_ = parse_nonnegative_int(it, eh); spec.width_ = parse_nonnegative_int(it, eh);
} } else if (*it == '*') {
else if (*it == '*')
{
++it; ++it;
spec.width_ = visit(internal::printf_width_handler<char_type>(spec), get_arg(it)); spec.width_ =
visit(internal::printf_width_handler<char_type>(spec), get_arg(it));
} }
return arg_index; return arg_index;
} }
template<typename OutputIt, typename Char, typename AF> template <typename OutputIt, typename Char, typename AF>
void basic_printf_context<OutputIt, Char, AF>::format() void basic_printf_context<OutputIt, Char, AF>::format() {
{
auto &buffer = internal::get_container(this->out()); auto &buffer = internal::get_container(this->out());
auto start = iterator(this->parse_context()); auto start = iterator(this->parse_context());
auto it = start; auto it = start;
using internal::pointer_from; using internal::pointer_from;
while (*it) while (*it) {
{
char_type c = *it++; char_type c = *it++;
if (c != '%') if (c != '%') continue;
continue; if (*it == c) {
if (*it == c)
{
buffer.append(pointer_from(start), pointer_from(it)); buffer.append(pointer_from(start), pointer_from(it));
start = ++it; start = ++it;
continue; continue;
@ -554,21 +482,16 @@ void basic_printf_context<OutputIt, Char, AF>::format()
unsigned arg_index = parse_header(it, spec); unsigned arg_index = parse_header(it, spec);
// Parse precision. // Parse precision.
if (*it == '.') if (*it == '.') {
{
++it; ++it;
if ('0' <= *it && *it <= '9') if ('0' <= *it && *it <= '9') {
{
internal::error_handler eh; internal::error_handler eh;
spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh)); spec.precision_ = static_cast<int>(parse_nonnegative_int(it, eh));
} } else if (*it == '*') {
else if (*it == '*')
{
++it; ++it;
spec.precision_ = visit(internal::printf_precision_handler(), get_arg(it)); spec.precision_ =
} visit(internal::printf_precision_handler(), get_arg(it));
else } else {
{
spec.precision_ = 0; spec.precision_ = 0;
} }
} }
@ -576,8 +499,7 @@ void basic_printf_context<OutputIt, Char, AF>::format()
format_arg arg = get_arg(it, arg_index); format_arg arg = get_arg(it, arg_index);
if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg)) if (spec.flag(HASH_FLAG) && visit(internal::is_zero_int(), arg))
spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG); spec.flags_ &= ~internal::to_unsigned<int>(HASH_FLAG);
if (spec.fill_ == '0') if (spec.fill_ == '0') {
{
if (arg.is_arithmetic()) if (arg.is_arithmetic())
spec.align_ = ALIGN_NUMERIC; spec.align_ = ALIGN_NUMERIC;
else else
@ -586,8 +508,7 @@ void basic_printf_context<OutputIt, Char, AF>::format()
// Parse length and convert the argument to the required type. // Parse length and convert the argument to the required type.
using internal::convert_arg; using internal::convert_arg;
switch (*it++) switch (*it++) {
{
case 'h': case 'h':
if (*it == 'h') if (*it == 'h')
convert_arg<signed char>(arg, *++it); convert_arg<signed char>(arg, *++it);
@ -622,13 +543,10 @@ void basic_printf_context<OutputIt, Char, AF>::format()
if (!*it) if (!*it)
FMT_THROW(format_error("invalid format string")); FMT_THROW(format_error("invalid format string"));
spec.type_ = static_cast<char>(*it++); spec.type_ = static_cast<char>(*it++);
if (arg.is_integral()) if (arg.is_integral()) {
{
// Normalize type. // Normalize type.
switch (spec.type_) switch (spec.type_) {
{ case 'i': case 'u':
case 'i':
case 'u':
spec.type_ = 'd'; spec.type_ = 'd';
break; break;
case 'c': case 'c':
@ -646,28 +564,28 @@ void basic_printf_context<OutputIt, Char, AF>::format()
buffer.append(pointer_from(start), pointer_from(it)); buffer.append(pointer_from(start), pointer_from(it));
} }
template<typename Char, typename Context> template <typename Char, typename Context>
void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format, basic_format_args<Context> args) void printf(internal::basic_buffer<Char> &buf, basic_string_view<Char> format,
{ basic_format_args<Context> args) {
Context(std::back_inserter(buf), format, args).format(); Context(std::back_inserter(buf), format, args).format();
} }
template<typename Buffer> template <typename Buffer>
struct printf_context struct printf_context {
{ typedef basic_printf_context<
typedef basic_printf_context<std::back_insert_iterator<Buffer>, typename Buffer::value_type> type; std::back_insert_iterator<Buffer>, typename Buffer::value_type> type;
}; };
template<typename... Args> template <typename ...Args>
inline format_arg_store<printf_context<internal::buffer>::type, Args...> make_printf_args(const Args &... args) inline format_arg_store<printf_context<internal::buffer>::type, Args...>
{ make_printf_args(const Args & ... args) {
return format_arg_store<printf_context<internal::buffer>::type, Args...>(args...); return format_arg_store<printf_context<internal::buffer>::type, Args...>(
args...);
} }
typedef basic_format_args<printf_context<internal::buffer>::type> printf_args; typedef basic_format_args<printf_context<internal::buffer>::type> printf_args;
typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args; typedef basic_format_args<printf_context<internal::wbuffer>::type> wprintf_args;
inline std::string vsprintf(string_view format, printf_args args) inline std::string vsprintf(string_view format, printf_args args) {
{
memory_buffer buffer; memory_buffer buffer;
printf(buffer, format, args); printf(buffer, format, args);
return to_string(buffer); return to_string(buffer);
@ -682,33 +600,33 @@ inline std::string vsprintf(string_view format, printf_args args)
std::string message = fmt::sprintf("The answer is %d", 42); std::string message = fmt::sprintf("The answer is %d", 42);
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline std::string sprintf(string_view format_str, const Args &... args) inline std::string sprintf(string_view format_str, const Args & ... args) {
{ return vsprintf(format_str,
return vsprintf(format_str, make_format_args<typename printf_context<internal::buffer>::type>(args...)); make_format_args<typename printf_context<internal::buffer>::type>(args...));
} }
inline std::wstring vsprintf(wstring_view format, wprintf_args args) inline std::wstring vsprintf(wstring_view format, wprintf_args args) {
{
wmemory_buffer buffer; wmemory_buffer buffer;
printf(buffer, format, args); printf(buffer, format, args);
return to_string(buffer); return to_string(buffer);
} }
template<typename... Args> template <typename... Args>
inline std::wstring sprintf(wstring_view format_str, const Args &... args) inline std::wstring sprintf(wstring_view format_str, const Args & ... args) {
{ return vsprintf(format_str,
return vsprintf(format_str, make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
} }
template<typename Char> template <typename Char>
inline int vfprintf( inline int vfprintf(std::FILE *f, basic_string_view<Char> format,
std::FILE *f, basic_string_view<Char> format, basic_format_args<typename printf_context<internal::basic_buffer<Char>>::type> args) basic_format_args<typename printf_context<
{ internal::basic_buffer<Char>>::type> args) {
basic_memory_buffer<Char> buffer; basic_memory_buffer<Char> buffer;
printf(buffer, format, args); printf(buffer, format, args);
std::size_t size = buffer.size(); std::size_t size = buffer.size();
return std::fwrite(buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size); return std::fwrite(
buffer.data(), sizeof(Char), size, f) < size ? -1 : static_cast<int>(size);
} }
/** /**
@ -720,26 +638,25 @@ inline int vfprintf(
fmt::fprintf(stderr, "Don't %s!", "panic"); fmt::fprintf(stderr, "Don't %s!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline int fprintf(std::FILE *f, string_view format_str, const Args &... args) inline int fprintf(std::FILE *f, string_view format_str, const Args & ... args) {
{ auto vargs = make_format_args<
auto vargs = make_format_args<typename printf_context<internal::buffer>::type>(args...); typename printf_context<internal::buffer>::type>(args...);
return vfprintf<char>(f, format_str, vargs); return vfprintf<char>(f, format_str, vargs);
} }
template<typename... Args> template <typename... Args>
inline int fprintf(std::FILE *f, wstring_view format_str, const Args &... args) inline int fprintf(std::FILE *f, wstring_view format_str,
{ const Args & ... args) {
return vfprintf(f, format_str, make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); return vfprintf(f, format_str,
make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
} }
inline int vprintf(string_view format, printf_args args) inline int vprintf(string_view format, printf_args args) {
{
return vfprintf(stdout, format, args); return vfprintf(stdout, format, args);
} }
inline int vprintf(wstring_view format, wprintf_args args) inline int vprintf(wstring_view format, wprintf_args args) {
{
return vfprintf(stdout, format, args); return vfprintf(stdout, format, args);
} }
@ -752,28 +669,28 @@ inline int vprintf(wstring_view format, wprintf_args args)
fmt::printf("Elapsed time: %.2f seconds", 1.23); fmt::printf("Elapsed time: %.2f seconds", 1.23);
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline int printf(string_view format_str, const Args &... args) inline int printf(string_view format_str, const Args & ... args) {
{ return vprintf(format_str,
return vprintf(format_str, make_format_args<typename printf_context<internal::buffer>::type>(args...)); make_format_args<typename printf_context<internal::buffer>::type>(args...));
} }
template<typename... Args> template <typename... Args>
inline int printf(wstring_view format_str, const Args &... args) inline int printf(wstring_view format_str, const Args & ... args) {
{ return vprintf(format_str,
return vprintf(format_str, make_format_args<typename printf_context<internal::wbuffer>::type>(args...)); make_format_args<typename printf_context<internal::wbuffer>::type>(args...));
} }
inline int vfprintf(std::ostream &os, string_view format_str, printf_args args) inline int vfprintf(std::ostream &os, string_view format_str,
{ printf_args args) {
memory_buffer buffer; memory_buffer buffer;
printf(buffer, format_str, args); printf(buffer, format_str, args);
internal::write(os, buffer); internal::write(os, buffer);
return static_cast<int>(buffer.size()); return static_cast<int>(buffer.size());
} }
inline int vfprintf(std::wostream &os, wstring_view format_str, wprintf_args args) inline int vfprintf(std::wostream &os, wstring_view format_str,
{ wprintf_args args) {
wmemory_buffer buffer; wmemory_buffer buffer;
printf(buffer, format_str, args); printf(buffer, format_str, args);
internal::write(os, buffer); internal::write(os, buffer);
@ -789,17 +706,19 @@ inline int vfprintf(std::wostream &os, wstring_view format_str, wprintf_args arg
fmt::fprintf(cerr, "Don't %s!", "panic"); fmt::fprintf(cerr, "Don't %s!", "panic");
\endrst \endrst
*/ */
template<typename... Args> template <typename... Args>
inline int fprintf(std::ostream &os, string_view format_str, const Args &... args) inline int fprintf(std::ostream &os, string_view format_str,
{ const Args & ... args) {
auto vargs = make_format_args<typename printf_context<internal::buffer>::type>(args...); auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs); return vfprintf(os, format_str, vargs);
} }
template<typename... Args> template <typename... Args>
inline int fprintf(std::wostream &os, wstring_view format_str, const Args &... args) inline int fprintf(std::wostream &os, wstring_view format_str,
{ const Args & ... args) {
auto vargs = make_format_args<typename printf_context<internal::buffer>::type>(args...); auto vargs = make_format_args<
typename printf_context<internal::buffer>::type>(args...);
return vfprintf(os, format_str, vargs); return vfprintf(os, format_str, vargs);
} }
FMT_END_NAMESPACE FMT_END_NAMESPACE

View File

@ -17,270 +17,233 @@
// output only up to N items from the range. // output only up to N items from the range.
#ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT #ifndef FMT_RANGE_OUTPUT_LENGTH_LIMIT
#define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256 # define FMT_RANGE_OUTPUT_LENGTH_LIMIT 256
#endif #endif
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
template<typename Char> template <typename Char>
struct formatting_base struct formatting_base {
{ template <typename ParseContext>
template<typename ParseContext> FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
return ctx.begin(); return ctx.begin();
} }
}; };
template<typename Char, typename Enable = void> template <typename Char, typename Enable = void>
struct formatting_range : formatting_base<Char> struct formatting_range : formatting_base<Char> {
{ static FMT_CONSTEXPR_DECL const std::size_t range_length_limit =
static FMT_CONSTEXPR_DECL const std::size_t range_length_limit = FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the FMT_RANGE_OUTPUT_LENGTH_LIMIT; // output only up to N items from the range.
// range.
Char prefix; Char prefix;
Char delimiter; Char delimiter;
Char postfix; Char postfix;
formatting_range() formatting_range() : prefix('{'), delimiter(','), postfix('}') {}
: prefix('{')
, delimiter(',')
, postfix('}')
{
}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
}; };
template<typename Char, typename Enable = void> template <typename Char, typename Enable = void>
struct formatting_tuple : formatting_base<Char> struct formatting_tuple : formatting_base<Char> {
{
Char prefix; Char prefix;
Char delimiter; Char delimiter;
Char postfix; Char postfix;
formatting_tuple() formatting_tuple() : prefix('('), delimiter(','), postfix(')') {}
: prefix('(')
, delimiter(',')
, postfix(')')
{
}
static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true; static FMT_CONSTEXPR_DECL const bool add_delimiter_spaces = true;
static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false; static FMT_CONSTEXPR_DECL const bool add_prepostfix_space = false;
}; };
namespace internal { namespace internal {
template<typename RangeT, typename OutputIterator> template <typename RangeT, typename OutputIterator>
void copy(const RangeT &range, OutputIterator out) void copy(const RangeT &range, OutputIterator out) {
{
for (auto it = range.begin(), end = range.end(); it != end; ++it) for (auto it = range.begin(), end = range.end(); it != end; ++it)
*out++ = *it; *out++ = *it;
} }
template<typename OutputIterator> template <typename OutputIterator>
void copy(const char *str, OutputIterator out) void copy(const char *str, OutputIterator out) {
{
const char *p_curr = str; const char *p_curr = str;
while (*p_curr) while (*p_curr) {
{
*out++ = *p_curr++; *out++ = *p_curr++;
} }
} }
template<typename OutputIterator> template <typename OutputIterator>
void copy(char ch, OutputIterator out) void copy(char ch, OutputIterator out) {
{
*out++ = ch; *out++ = ch;
} }
/// Return true value if T has std::string interface, like std::string_view. /// Return true value if T has std::string interface, like std::string_view.
template<typename T> template <typename T>
class is_like_std_string class is_like_std_string {
{ template <typename U>
template<typename U> static auto check(U *p) ->
static auto check(U *p) -> decltype(p->find('a'), p->length(), p->data(), int()); decltype(p->find('a'), p->length(), p->data(), int());
template<typename> template <typename>
static void check(...); static void check(...);
public: public:
static FMT_CONSTEXPR_DECL const bool value = !std::is_void<decltype(check<T>(FMT_NULL))>::value; static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
}; };
template<typename... Ts> template <typename... Ts>
struct conditional_helper struct conditional_helper {};
{
};
template<typename T, typename _ = void> template <typename T, typename _ = void>
struct is_range_ : std::false_type struct is_range_ : std::false_type {};
{
};
#if !FMT_MSC_VER || FMT_MSC_VER > 1800 #if !FMT_MSC_VER || FMT_MSC_VER > 1800
template<typename T> template <typename T>
struct is_range_<T, typename std::conditional<false, struct is_range_<T, typename std::conditional<
conditional_helper<decltype(internal::declval<T>().begin()), decltype(internal::declval<T>().end())>, void>::type> false,
: std::true_type conditional_helper<decltype(internal::declval<T>().begin()),
{ decltype(internal::declval<T>().end())>,
}; void>::type> : std::true_type {};
#endif #endif
/// tuple_size and tuple_element check. /// tuple_size and tuple_element check.
template<typename T> template <typename T>
class is_tuple_like_ class is_tuple_like_ {
{ template <typename U>
template<typename U> static auto check(U *p) ->
static auto check(U *p) -> decltype(std::tuple_size<U>::value, internal::declval<typename std::tuple_element<0, U>::type>(), int()); decltype(std::tuple_size<U>::value,
template<typename> internal::declval<typename std::tuple_element<0, U>::type>(), int());
template <typename>
static void check(...); static void check(...);
public: public:
static FMT_CONSTEXPR_DECL const bool value = !std::is_void<decltype(check<T>(FMT_NULL))>::value; static FMT_CONSTEXPR_DECL const bool value =
!std::is_void<decltype(check<T>(FMT_NULL))>::value;
}; };
// Check for integer_sequence // Check for integer_sequence
#if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900 #if defined(__cpp_lib_integer_sequence) || FMT_MSC_VER >= 1900
template<typename T, T... N> template <typename T, T... N>
using integer_sequence = std::integer_sequence<T, N...>; using integer_sequence = std::integer_sequence<T, N...>;
template<std::size_t... N> template <std::size_t... N>
using index_sequence = std::index_sequence<N...>; using index_sequence = std::index_sequence<N...>;
template<std::size_t N> template <std::size_t N>
using make_index_sequence = std::make_index_sequence<N>; using make_index_sequence = std::make_index_sequence<N>;
#else #else
template<typename T, T... N> template <typename T, T... N>
struct integer_sequence struct integer_sequence {
{
typedef T value_type; typedef T value_type;
static FMT_CONSTEXPR std::size_t size() static FMT_CONSTEXPR std::size_t size() {
{
return sizeof...(N); return sizeof...(N);
} }
}; };
template<std::size_t... N> template <std::size_t... N>
using index_sequence = integer_sequence<std::size_t, N...>; using index_sequence = integer_sequence<std::size_t, N...>;
template<typename T, std::size_t N, T... Ns> template <typename T, std::size_t N, T... Ns>
struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> struct make_integer_sequence : make_integer_sequence<T, N - 1, N - 1, Ns...> {};
{ template <typename T, T... Ns>
}; struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...> {};
template<typename T, T... Ns>
struct make_integer_sequence<T, 0, Ns...> : integer_sequence<T, Ns...>
{
};
template<std::size_t N> template <std::size_t N>
using make_index_sequence = make_integer_sequence<std::size_t, N>; using make_index_sequence = make_integer_sequence<std::size_t, N>;
#endif #endif
template<class Tuple, class F, size_t... Is> template <class Tuple, class F, size_t... Is>
void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT void for_each(index_sequence<Is...>, Tuple &&tup, F &&f) FMT_NOEXCEPT {
{
using std::get; using std::get;
// using free function get<I>(T) now. // using free function get<I>(T) now.
const int _[] = {0, ((void)f(get<Is>(tup)), 0)...}; const int _[] = {0, ((void)f(get<Is>(tup)), 0)...};
(void)_; // blocks warnings (void)_; // blocks warnings
} }
template<class T> template <class T>
FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value> get_indexes(T const &) FMT_CONSTEXPR make_index_sequence<std::tuple_size<T>::value>
{ get_indexes(T const &) { return {}; }
return {};
}
template<class Tuple, class F> template <class Tuple, class F>
void for_each(Tuple &&tup, F &&f) void for_each(Tuple &&tup, F &&f) {
{
const auto indexes = get_indexes(tup); const auto indexes = get_indexes(tup);
for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f)); for_each(indexes, std::forward<Tuple>(tup), std::forward<F>(f));
} }
template<typename Arg> template<typename Arg>
FMT_CONSTEXPR const char *format_str_quoted( FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
bool add_space, const Arg &, typename std::enable_if<!is_like_std_string<typename std::decay<Arg>::type>::value>::type * = nullptr) typename std::enable_if<
{ !is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " {}" : "{}"; return add_space ? " {}" : "{}";
} }
template<typename Arg> template<typename Arg>
FMT_CONSTEXPR const char *format_str_quoted( FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const Arg&,
bool add_space, const Arg &, typename std::enable_if<is_like_std_string<typename std::decay<Arg>::type>::value>::type * = nullptr) typename std::enable_if<
{ is_like_std_string<typename std::decay<Arg>::type>::value>::type* = nullptr) {
return add_space ? " \"{}\"" : "\"{}\""; return add_space ? " \"{}\"" : "\"{}\"";
} }
FMT_CONSTEXPR const char *format_str_quoted(bool add_space, const char *) FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char*) {
{
return add_space ? " \"{}\"" : "\"{}\""; return add_space ? " \"{}\"" : "\"{}\"";
} }
FMT_CONSTEXPR const wchar_t *format_str_quoted(bool add_space, const wchar_t *) FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t*) {
{
return add_space ? L" \"{}\"" : L"\"{}\""; return add_space ? L" \"{}\"" : L"\"{}\"";
} }
FMT_CONSTEXPR const char *format_str_quoted(bool add_space, const char) FMT_CONSTEXPR const char* format_str_quoted(bool add_space, const char) {
{
return add_space ? " '{}'" : "'{}'"; return add_space ? " '{}'" : "'{}'";
} }
FMT_CONSTEXPR const wchar_t *format_str_quoted(bool add_space, const wchar_t) FMT_CONSTEXPR const wchar_t* format_str_quoted(bool add_space, const wchar_t) {
{
return add_space ? L" '{}'" : L"'{}'"; return add_space ? L" '{}'" : L"'{}'";
} }
} // namespace internal } // namespace internal
template<typename T> template <typename T>
struct is_tuple_like struct is_tuple_like {
{ static FMT_CONSTEXPR_DECL const bool value =
static FMT_CONSTEXPR_DECL const bool value = internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value; internal::is_tuple_like_<T>::value && !internal::is_range_<T>::value;
}; };
template<typename TupleT, typename Char> template <typename TupleT, typename Char>
struct formatter<TupleT, Char, typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> struct formatter<TupleT, Char,
{ typename std::enable_if<fmt::is_tuple_like<TupleT>::value>::type> {
private: private:
// C++11 generic lambda for format() // C++11 generic lambda for format()
template<typename FormatContext> template <typename FormatContext>
struct format_each struct format_each {
{ template <typename T>
template<typename T> void operator()(const T& v) {
void operator()(const T &v) if (i > 0) {
{ if (formatting.add_prepostfix_space) {
if (i > 0)
{
if (formatting.add_prepostfix_space)
{
*out++ = ' '; *out++ = ' ';
} }
internal::copy(formatting.delimiter, out); internal::copy(formatting.delimiter, out);
} }
format_to(out, internal::format_str_quoted((formatting.add_delimiter_spaces && i > 0), v), v); format_to(out,
internal::format_str_quoted(
(formatting.add_delimiter_spaces && i > 0), v),
v);
++i; ++i;
} }
formatting_tuple<Char> &formatting; formatting_tuple<Char>& formatting;
std::size_t &i; std::size_t& i;
typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out; typename std::add_lvalue_reference<decltype(std::declval<FormatContext>().out())>::type out;
}; };
public: public:
formatting_tuple<Char> formatting; formatting_tuple<Char> formatting;
template<typename ParseContext> template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
{
return formatting.parse(ctx); return formatting.parse(ctx);
} }
template<typename FormatContext = format_context> template <typename FormatContext = format_context>
auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) auto format(const TupleT &values, FormatContext &ctx) -> decltype(ctx.out()) {
{
auto out = ctx.out(); auto out = ctx.out();
std::size_t i = 0; std::size_t i = 0;
internal::copy(formatting.prefix, out); internal::copy(formatting.prefix, out);
internal::for_each(values, format_each<FormatContext>{formatting, i, out}); internal::for_each(values, format_each<FormatContext>{formatting, i, out});
if (formatting.add_prepostfix_space) if (formatting.add_prepostfix_space) {
{
*out++ = ' '; *out++ = ' ';
} }
internal::copy(formatting.postfix, out); internal::copy(formatting.postfix, out);
@ -289,49 +252,46 @@ public:
} }
}; };
template<typename T> template <typename T>
struct is_range struct is_range {
{ static FMT_CONSTEXPR_DECL const bool value =
static FMT_CONSTEXPR_DECL const bool value = internal::is_range_<T>::value && !internal::is_like_std_string<T>::value; internal::is_range_<T>::value && !internal::is_like_std_string<T>::value;
}; };
template<typename RangeT, typename Char> template <typename RangeT, typename Char>
struct formatter<RangeT, Char, typename std::enable_if<fmt::is_range<RangeT>::value>::type> struct formatter<RangeT, Char,
{ typename std::enable_if<fmt::is_range<RangeT>::value>::type> {
formatting_range<Char> formatting; formatting_range<Char> formatting;
template<typename ParseContext> template <typename ParseContext>
FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) FMT_CONSTEXPR auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
{
return formatting.parse(ctx); return formatting.parse(ctx);
} }
template<typename FormatContext> template <typename FormatContext>
typename FormatContext::iterator format(const RangeT &values, FormatContext &ctx) typename FormatContext::iterator format(
{ const RangeT &values, FormatContext &ctx) {
auto out = ctx.out(); auto out = ctx.out();
internal::copy(formatting.prefix, out); internal::copy(formatting.prefix, out);
std::size_t i = 0; std::size_t i = 0;
for (auto it = values.begin(), end = values.end(); it != end; ++it) for (auto it = values.begin(), end = values.end(); it != end; ++it) {
{ if (i > 0) {
if (i > 0) if (formatting.add_prepostfix_space) {
{
if (formatting.add_prepostfix_space)
{
*out++ = ' '; *out++ = ' ';
} }
internal::copy(formatting.delimiter, out); internal::copy(formatting.delimiter, out);
} }
format_to(out, internal::format_str_quoted((formatting.add_delimiter_spaces && i > 0), *it), *it); format_to(out,
if (++i > formatting.range_length_limit) internal::format_str_quoted(
{ (formatting.add_delimiter_spaces && i > 0), *it),
*it);
if (++i > formatting.range_length_limit) {
format_to(out, " ... <other elements>"); format_to(out, " ... <other elements>");
break; break;
} }
} }
if (formatting.add_prepostfix_space) if (formatting.add_prepostfix_space) {
{
*out++ = ' '; *out++ = ' ';
} }
internal::copy(formatting.postfix, out); internal::copy(formatting.postfix, out);
@ -342,3 +302,4 @@ struct formatter<RangeT, Char, typename std::enable_if<fmt::is_range<RangeT>::va
FMT_END_NAMESPACE FMT_END_NAMESPACE
#endif // FMT_RANGES_H_ #endif // FMT_RANGES_H_

View File

@ -13,66 +13,43 @@
FMT_BEGIN_NAMESPACE FMT_BEGIN_NAMESPACE
namespace internal { // Prevents expansion of a preceding token as a function-style macro.
inline null<> localtime_r(...) // Usage: f FMT_NOMACRO()
{ #define FMT_NOMACRO
return null<>();
namespace internal{
inline null<> localtime_r FMT_NOMACRO(...) { return null<>(); }
inline null<> localtime_s(...) { return null<>(); }
inline null<> gmtime_r(...) { return null<>(); }
inline null<> gmtime_s(...) { return null<>(); }
} }
inline null<> localtime_s(...)
{
return null<>();
}
inline null<> gmtime_r(...)
{
return null<>();
}
inline null<> gmtime_s(...)
{
return null<>();
}
} // namespace internal
// Thread-safe replacement for std::localtime // Thread-safe replacement for std::localtime
inline std::tm localtime(std::time_t time) inline std::tm localtime(std::time_t time) {
{ struct dispatcher {
struct dispatcher
{
std::time_t time_; std::time_t time_;
std::tm tm_; std::tm tm_;
dispatcher(std::time_t t) dispatcher(std::time_t t): time_(t) {}
: time_(t)
{
}
bool run() bool run() {
{
using namespace fmt::internal; using namespace fmt::internal;
return handle(localtime_r(&time_, &tm_)); return handle(localtime_r(&time_, &tm_));
} }
bool handle(std::tm *tm) bool handle(std::tm *tm) { return tm != FMT_NULL; }
{
return tm != FMT_NULL;
}
bool handle(internal::null<>) bool handle(internal::null<>) {
{
using namespace fmt::internal; using namespace fmt::internal;
return fallback(localtime_s(&tm_, &time_)); return fallback(localtime_s(&tm_, &time_));
} }
bool fallback(int res) bool fallback(int res) { return res == 0; }
{
return res == 0;
}
bool fallback(internal::null<>) bool fallback(internal::null<>) {
{
using namespace fmt::internal; using namespace fmt::internal;
std::tm *tm = std::localtime(&time_); std::tm *tm = std::localtime(&time_);
if (tm) if (tm) tm_ = *tm;
tm_ = *tm;
return tm != FMT_NULL; return tm != FMT_NULL;
} }
}; };
@ -84,45 +61,30 @@ inline std::tm localtime(std::time_t time)
} }
// Thread-safe replacement for std::gmtime // Thread-safe replacement for std::gmtime
inline std::tm gmtime(std::time_t time) inline std::tm gmtime(std::time_t time) {
{ struct dispatcher {
struct dispatcher
{
std::time_t time_; std::time_t time_;
std::tm tm_; std::tm tm_;
dispatcher(std::time_t t) dispatcher(std::time_t t): time_(t) {}
: time_(t)
{
}
bool run() bool run() {
{
using namespace fmt::internal; using namespace fmt::internal;
return handle(gmtime_r(&time_, &tm_)); return handle(gmtime_r(&time_, &tm_));
} }
bool handle(std::tm *tm) bool handle(std::tm *tm) { return tm != FMT_NULL; }
{
return tm != FMT_NULL;
}
bool handle(internal::null<>) bool handle(internal::null<>) {
{
using namespace fmt::internal; using namespace fmt::internal;
return fallback(gmtime_s(&tm_, &time_)); return fallback(gmtime_s(&tm_, &time_));
} }
bool fallback(int res) bool fallback(int res) { return res == 0; }
{
return res == 0;
}
bool fallback(internal::null<>) bool fallback(internal::null<>) {
{
std::tm *tm = std::gmtime(&time_); std::tm *tm = std::gmtime(&time_);
if (tm) if (tm) tm_ = *tm;
tm_ = *tm;
return tm != FMT_NULL; return tm != FMT_NULL;
} }
}; };
@ -134,23 +96,21 @@ inline std::tm gmtime(std::time_t time)
} }
namespace internal { namespace internal {
inline std::size_t strftime(char *str, std::size_t count, const char *format, const std::tm *time) inline std::size_t strftime(char *str, std::size_t count, const char *format,
{ const std::tm *time) {
return std::strftime(str, count, format, time); return std::strftime(str, count, format, time);
} }
inline std::size_t strftime(wchar_t *str, std::size_t count, const wchar_t *format, const std::tm *time) inline std::size_t strftime(wchar_t *str, std::size_t count,
{ const wchar_t *format, const std::tm *time) {
return std::wcsftime(str, count, format, time); return std::wcsftime(str, count, format, time);
} }
} // namespace internal }
template<typename Char> template <typename Char>
struct formatter<std::tm, Char> struct formatter<std::tm, Char> {
{ template <typename ParseContext>
template<typename ParseContext> auto parse(ParseContext &ctx) -> decltype(ctx.begin()) {
auto parse(ParseContext &ctx) -> decltype(ctx.begin())
{
auto it = internal::null_terminating_iterator<Char>(ctx); auto it = internal::null_terminating_iterator<Char>(ctx);
if (*it == ':') if (*it == ':')
++it; ++it;
@ -164,22 +124,19 @@ struct formatter<std::tm, Char>
return pointer_from(end); return pointer_from(end);
} }
template<typename FormatContext> template <typename FormatContext>
auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) auto format(const std::tm &tm, FormatContext &ctx) -> decltype(ctx.out()) {
{
internal::basic_buffer<Char> &buf = internal::get_container(ctx.out()); internal::basic_buffer<Char> &buf = internal::get_container(ctx.out());
std::size_t start = buf.size(); std::size_t start = buf.size();
for (;;) for (;;) {
{
std::size_t size = buf.capacity() - start; std::size_t size = buf.capacity() - start;
std::size_t count = internal::strftime(&buf[start], size, &tm_format[0], &tm); std::size_t count =
if (count != 0) internal::strftime(&buf[start], size, &tm_format[0], &tm);
{ if (count != 0) {
buf.resize(start + count); buf.resize(start + count);
break; break;
} }
if (size >= tm_format.size() * 256) if (size >= tm_format.size() * 256) {
{
// If the buffer is 256 times larger than the format string, assume // If the buffer is 256 times larger than the format string, assume
// that `strftime` gives an empty result. There doesn't seem to be a // that `strftime` gives an empty result. There doesn't seem to be a
// better way to distinguish the two cases: // better way to distinguish the two cases: