commit
fcd72eb81b
13
doc/api.rst
13
doc/api.rst
@ -85,6 +85,19 @@ Compatibility
|
|||||||
.. doxygentypedef:: fmt::string_view
|
.. doxygentypedef:: fmt::string_view
|
||||||
.. doxygentypedef:: fmt::wstring_view
|
.. doxygentypedef:: fmt::wstring_view
|
||||||
|
|
||||||
|
Locale
|
||||||
|
------
|
||||||
|
|
||||||
|
All formatting is locale-independent by default. Use the ``'n'`` format
|
||||||
|
specifier to insert the appropriate number separator characters from the
|
||||||
|
locale::
|
||||||
|
|
||||||
|
#include <fmt/core.h>
|
||||||
|
#include <locale>
|
||||||
|
|
||||||
|
std::locale::global(std::locale("en_US.UTF-8"));
|
||||||
|
auto s = fmt::format("{:n}", 1000000); // s == "1,000,000"
|
||||||
|
|
||||||
.. _format-api:
|
.. _format-api:
|
||||||
|
|
||||||
Format API
|
Format API
|
||||||
|
|||||||
@ -76,7 +76,7 @@ The general form of a *standard format specifier* is:
|
|||||||
|
|
||||||
.. productionlist:: sf
|
.. productionlist:: sf
|
||||||
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
|
format_spec: [[`fill`]`align`][`sign`]["#"]["0"][`width`]["." `precision`][`type`]
|
||||||
fill: <a character other than '{', '}' or '\0'>
|
fill: <a character other than '{' or '}'>
|
||||||
align: "<" | ">" | "^"
|
align: "<" | ">" | "^"
|
||||||
sign: "+" | "-" | " "
|
sign: "+" | "-" | " "
|
||||||
width: `integer` | "{" `arg_id` "}"
|
width: `integer` | "{" `arg_id` "}"
|
||||||
@ -84,11 +84,11 @@ The general form of a *standard format specifier* is:
|
|||||||
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
type: `int_type` | "a" | "A" | "c" | "e" | "E" | "f" | "F" | "g" | "G" | "p" | "s"
|
||||||
int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X"
|
int_type: "b" | "B" | "d" | "n" | "o" | "x" | "X"
|
||||||
|
|
||||||
The *fill* character can be any character other than '{', '}' or '\\0'. The
|
The *fill* character can be any Unicode code point other than ``'{'`` or
|
||||||
presence of a fill character is signaled by the character following it, which
|
``'}'``. The presence of a fill character is signaled by the character following
|
||||||
must be one of the alignment options. If the second character of *format_spec*
|
it, which must be one of the alignment options. If the second character of
|
||||||
is not a valid alignment option, then it is assumed that both the fill character
|
*format_spec* is not a valid alignment option, then it is assumed that both the
|
||||||
and the alignment option are absent.
|
fill character and the alignment option are absent.
|
||||||
|
|
||||||
The meaning of the various alignment options is as follows:
|
The meaning of the various alignment options is as follows:
|
||||||
|
|
||||||
@ -320,71 +320,93 @@ following examples.
|
|||||||
|
|
||||||
Accessing arguments by position::
|
Accessing arguments by position::
|
||||||
|
|
||||||
format("{0}, {1}, {2}", 'a', 'b', 'c');
|
fmt::format("{0}, {1}, {2}", 'a', 'b', 'c');
|
||||||
// Result: "a, b, c"
|
// Result: "a, b, c"
|
||||||
format("{}, {}, {}", 'a', 'b', 'c');
|
fmt::format("{}, {}, {}", 'a', 'b', 'c');
|
||||||
// Result: "a, b, c"
|
// Result: "a, b, c"
|
||||||
format("{2}, {1}, {0}", 'a', 'b', 'c');
|
fmt::format("{2}, {1}, {0}", 'a', 'b', 'c');
|
||||||
// Result: "c, b, a"
|
// Result: "c, b, a"
|
||||||
format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
|
fmt::format("{0}{1}{0}", "abra", "cad"); // arguments' indices can be repeated
|
||||||
// Result: "abracadabra"
|
// Result: "abracadabra"
|
||||||
|
|
||||||
Aligning the text and specifying a width::
|
Aligning the text and specifying a width::
|
||||||
|
|
||||||
format("{:<30}", "left aligned");
|
fmt::format("{:<30}", "left aligned");
|
||||||
// Result: "left aligned "
|
// Result: "left aligned "
|
||||||
format("{:>30}", "right aligned");
|
fmt::format("{:>30}", "right aligned");
|
||||||
// Result: " right aligned"
|
// Result: " right aligned"
|
||||||
format("{:^30}", "centered");
|
fmt::format("{:^30}", "centered");
|
||||||
// Result: " centered "
|
// Result: " centered "
|
||||||
format("{:*^30}", "centered"); // use '*' as a fill char
|
fmt::format("{:*^30}", "centered"); // use '*' as a fill char
|
||||||
// Result: "***********centered***********"
|
// Result: "***********centered***********"
|
||||||
|
|
||||||
Dynamic width::
|
Dynamic width::
|
||||||
|
|
||||||
format("{:<{}}", "left aligned", 30);
|
fmt::format("{:<{}}", "left aligned", 30);
|
||||||
// Result: "left aligned "
|
// Result: "left aligned "
|
||||||
|
|
||||||
Dynamic precision::
|
Dynamic precision::
|
||||||
|
|
||||||
format("{:.{}f}", 3.14, 1);
|
fmt::format("{:.{}f}", 3.14, 1);
|
||||||
// Result: "3.1"
|
// Result: "3.1"
|
||||||
|
|
||||||
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
|
Replacing ``%+f``, ``%-f``, and ``% f`` and specifying a sign::
|
||||||
|
|
||||||
format("{:+f}; {:+f}", 3.14, -3.14); // show it always
|
fmt::format("{:+f}; {:+f}", 3.14, -3.14); // show it always
|
||||||
// Result: "+3.140000; -3.140000"
|
// Result: "+3.140000; -3.140000"
|
||||||
format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
|
fmt::format("{: f}; {: f}", 3.14, -3.14); // show a space for positive numbers
|
||||||
// Result: " 3.140000; -3.140000"
|
// Result: " 3.140000; -3.140000"
|
||||||
format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
|
fmt::format("{:-f}; {:-f}", 3.14, -3.14); // show only the minus -- same as '{:f}; {:f}'
|
||||||
// Result: "3.140000; -3.140000"
|
// Result: "3.140000; -3.140000"
|
||||||
|
|
||||||
Replacing ``%x`` and ``%o`` and converting the value to different bases::
|
Replacing ``%x`` and ``%o`` and converting the value to different bases::
|
||||||
|
|
||||||
format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
fmt::format("int: {0:d}; hex: {0:x}; oct: {0:o}; bin: {0:b}", 42);
|
||||||
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
|
// Result: "int: 42; hex: 2a; oct: 52; bin: 101010"
|
||||||
// with 0x or 0 or 0b as prefix:
|
// with 0x or 0 or 0b as prefix:
|
||||||
format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
|
fmt::format("int: {0:d}; hex: {0:#x}; oct: {0:#o}; bin: {0:#b}", 42);
|
||||||
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
|
// Result: "int: 42; hex: 0x2a; oct: 052; bin: 0b101010"
|
||||||
|
|
||||||
Padded hex byte with prefix and always prints both hex characters::
|
Padded hex byte with prefix and always prints both hex characters::
|
||||||
|
|
||||||
format("{:#04x}", 0);
|
fmt::format("{:#04x}", 0);
|
||||||
// Result: "0x00"
|
// Result: "0x00"
|
||||||
|
|
||||||
.. ifconfig:: False
|
Box drawing using Unicode fill::
|
||||||
|
|
||||||
Using the comma as a thousands separator::
|
fmt::print(
|
||||||
|
"┌{0:─^{2}}┐\n"
|
||||||
|
"│{1: ^{2}}│\n"
|
||||||
|
"└{0:─^{2}}┘\n", "", "Hello, world!", 20);
|
||||||
|
|
||||||
format("{:,}", 1234567890);
|
prints::
|
||||||
'1,234,567,890'
|
|
||||||
|
┌────────────────────┐
|
||||||
|
│ Hello, world! │
|
||||||
|
└────────────────────┘
|
||||||
|
|
||||||
Using type-specific formatting::
|
Using type-specific formatting::
|
||||||
|
|
||||||
>>> import datetime
|
#include <fmt/chrono.h>
|
||||||
>>> d = datetime.datetime(2010, 7, 4, 12, 15, 58)
|
|
||||||
Format("{:%Y-%m-%d %H:%M:%S}") << d)
|
auto t = tm();
|
||||||
'2010-07-04 12:15:58'
|
t.tm_year = 2010 - 1900;
|
||||||
|
t.tm_mon = 6;
|
||||||
|
t.tm_mday = 4;
|
||||||
|
t.tm_hour = 12;
|
||||||
|
t.tm_min = 15;
|
||||||
|
t.tm_sec = 58;
|
||||||
|
fmt::print("{:%Y-%m-%d %H:%M:%S}", t);
|
||||||
|
// Prints: 2010-08-04 12:15:58
|
||||||
|
|
||||||
|
Using the comma as a thousands separator::
|
||||||
|
|
||||||
|
#include <fmt/locale.h>
|
||||||
|
|
||||||
|
auto s = fmt::format(std::locale("en_US.UTF-8"), "{:n}", 1234567890);
|
||||||
|
// s == "1,234,567,890"
|
||||||
|
|
||||||
|
.. ifconfig:: False
|
||||||
|
|
||||||
Nesting arguments and more complex examples::
|
Nesting arguments and more complex examples::
|
||||||
|
|
||||||
|
|||||||
@ -114,6 +114,22 @@ fmt can be installed on Linux, macOS and Windows with
|
|||||||
|
|
||||||
conda install -c conda-forge fmt
|
conda install -c conda-forge fmt
|
||||||
|
|
||||||
|
Vcpkg
|
||||||
|
=====
|
||||||
|
|
||||||
|
You can download and install fmt using the `vcpkg
|
||||||
|
<https://github.com/Microsoft/vcpkg>`__ dependency manager::
|
||||||
|
|
||||||
|
git clone https://github.com/Microsoft/vcpkg.git
|
||||||
|
cd vcpkg
|
||||||
|
./bootstrap-vcpkg.sh
|
||||||
|
./vcpkg integrate install
|
||||||
|
./vcpkg install fmt
|
||||||
|
|
||||||
|
The fmt port in vcpkg is kept up to date by Microsoft team members and community
|
||||||
|
contributors. If the version is out of date, please `create an issue or pull
|
||||||
|
request <https://github.com/Microsoft/vcpkg>`__ on the vcpkg repository.
|
||||||
|
|
||||||
Android NDK
|
Android NDK
|
||||||
===========
|
===========
|
||||||
|
|
||||||
|
|||||||
@ -8,14 +8,14 @@
|
|||||||
#ifndef FMT_CHRONO_H_
|
#ifndef FMT_CHRONO_H_
|
||||||
#define FMT_CHRONO_H_
|
#define FMT_CHRONO_H_
|
||||||
|
|
||||||
#include "format.h"
|
|
||||||
#include "locale.h"
|
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <locale>
|
#include <locale>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
|
#include "locale.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// Enable safe chrono durations, unless explicitly disabled.
|
// Enable safe chrono durations, unless explicitly disabled.
|
||||||
@ -495,12 +495,12 @@ FMT_CONSTEXPR const Char* parse_chrono_format(const Char* begin,
|
|||||||
handler.on_text(ptr - 1, ptr);
|
handler.on_text(ptr - 1, ptr);
|
||||||
break;
|
break;
|
||||||
case 'n': {
|
case 'n': {
|
||||||
const char newline[] = "\n";
|
const Char newline[]{'\n', 0};
|
||||||
handler.on_text(newline, newline + 1);
|
handler.on_text(newline, newline + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 't': {
|
case 't': {
|
||||||
const char tab[] = "\t";
|
const Char tab[]{'\t', 0};
|
||||||
handler.on_text(tab, tab + 1);
|
handler.on_text(tab, tab + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -759,18 +759,30 @@ inline std::chrono::duration<Rep, std::milli> get_milliseconds(
|
|||||||
return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
|
return std::chrono::duration<Rep, std::milli>(static_cast<Rep>(ms));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Rep, typename OutputIt>
|
template <typename Char, typename Rep, typename OutputIt>
|
||||||
OutputIt format_chrono_duration_value(OutputIt out, Rep val, int precision) {
|
OutputIt format_duration_value(OutputIt out, Rep val, int precision) {
|
||||||
if (precision >= 0) return format_to(out, "{:.{}f}", val, precision);
|
const Char pr_f[]{'{', ':', '.', '{', '}', 'f', '}', 0};
|
||||||
return format_to(out, std::is_floating_point<Rep>::value ? "{:g}" : "{}",
|
if (precision >= 0) return format_to(out, pr_f, val, precision);
|
||||||
|
const Char fp_f[]{'{', ':', 'g', '}', 0};
|
||||||
|
const Char format[]{'{', '}', 0};
|
||||||
|
return format_to(out, std::is_floating_point<Rep>::value ? fp_f : format,
|
||||||
val);
|
val);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Period, typename OutputIt>
|
template <typename Char, typename Period, typename OutputIt>
|
||||||
static OutputIt format_chrono_duration_unit(OutputIt out) {
|
OutputIt format_duration_unit(OutputIt out) {
|
||||||
if (const char* unit = get_units<Period>()) return format_to(out, "{}", unit);
|
if (const char* unit = get_units<Period>()) {
|
||||||
if (Period::den == 1) return format_to(out, "[{}]s", Period::num);
|
string_view s(unit);
|
||||||
return format_to(out, "[{}/{}]s", Period::num, Period::den);
|
if (const_check(std::is_same<Char, wchar_t>())) {
|
||||||
|
utf8_to_utf16 u(s);
|
||||||
|
return std::copy(u.c_str(), u.c_str() + u.size(), out);
|
||||||
|
}
|
||||||
|
return std::copy(s.begin(), s.end(), out);
|
||||||
|
}
|
||||||
|
const Char num_f[]{'[', '{', '}', ']', 's', 0};
|
||||||
|
if (Period::den == 1) return format_to(out, num_f, Period::num);
|
||||||
|
const Char num_def_f[]{'[', '{', '}', '/', '{', '}', ']', 's', 0};
|
||||||
|
return format_to(out, num_def_f, Period::num, Period::den);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename FormatContext, typename OutputIt, typename Rep,
|
template <typename FormatContext, typename OutputIt, typename Rep,
|
||||||
@ -871,13 +883,13 @@ struct chrono_formatter {
|
|||||||
void write_pinf() { std::copy_n("inf", 3, out); }
|
void write_pinf() { std::copy_n("inf", 3, out); }
|
||||||
void write_ninf() { std::copy_n("-inf", 4, out); }
|
void write_ninf() { std::copy_n("-inf", 4, out); }
|
||||||
|
|
||||||
void format_localized(const tm& time, const char* format) {
|
void format_localized(const tm& time, char format, char modifier = 0) {
|
||||||
if (isnan(val)) return write_nan();
|
if (isnan(val)) return write_nan();
|
||||||
auto locale = context.locale().template get<std::locale>();
|
auto locale = context.locale().template get<std::locale>();
|
||||||
auto& facet = std::use_facet<std::time_put<char_type>>(locale);
|
auto& facet = std::use_facet<std::time_put<char_type>>(locale);
|
||||||
std::basic_ostringstream<char_type> os;
|
std::basic_ostringstream<char_type> os;
|
||||||
os.imbue(locale);
|
os.imbue(locale);
|
||||||
facet.put(os, os, ' ', &time, format, format + std::strlen(format));
|
facet.put(os, os, ' ', &time, format, modifier);
|
||||||
auto str = os.str();
|
auto str = os.str();
|
||||||
std::copy(str.begin(), str.end(), out);
|
std::copy(str.begin(), str.end(), out);
|
||||||
}
|
}
|
||||||
@ -907,7 +919,7 @@ struct chrono_formatter {
|
|||||||
if (ns == numeric_system::standard) return write(hour(), 2);
|
if (ns == numeric_system::standard) return write(hour(), 2);
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_hour = to_nonnegative_int(hour(), 24);
|
time.tm_hour = to_nonnegative_int(hour(), 24);
|
||||||
format_localized(time, "%OH");
|
format_localized(time, 'H', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_12_hour(numeric_system ns) {
|
void on_12_hour(numeric_system ns) {
|
||||||
@ -916,7 +928,7 @@ struct chrono_formatter {
|
|||||||
if (ns == numeric_system::standard) return write(hour12(), 2);
|
if (ns == numeric_system::standard) return write(hour12(), 2);
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_hour = to_nonnegative_int(hour12(), 12);
|
time.tm_hour = to_nonnegative_int(hour12(), 12);
|
||||||
format_localized(time, "%OI");
|
format_localized(time, 'I', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_minute(numeric_system ns) {
|
void on_minute(numeric_system ns) {
|
||||||
@ -925,7 +937,7 @@ struct chrono_formatter {
|
|||||||
if (ns == numeric_system::standard) return write(minute(), 2);
|
if (ns == numeric_system::standard) return write(minute(), 2);
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_min = to_nonnegative_int(minute(), 60);
|
time.tm_min = to_nonnegative_int(minute(), 60);
|
||||||
format_localized(time, "%OM");
|
format_localized(time, 'M', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_second(numeric_system ns) {
|
void on_second(numeric_system ns) {
|
||||||
@ -950,13 +962,12 @@ struct chrono_formatter {
|
|||||||
}
|
}
|
||||||
auto time = tm();
|
auto time = tm();
|
||||||
time.tm_sec = to_nonnegative_int(second(), 60);
|
time.tm_sec = to_nonnegative_int(second(), 60);
|
||||||
format_localized(time, "%OS");
|
format_localized(time, 'S', 'O');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_12_hour_time() {
|
void on_12_hour_time() {
|
||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
|
format_localized(time(), 'r');
|
||||||
format_localized(time(), "%r");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_24_hour_time() {
|
void on_24_hour_time() {
|
||||||
@ -980,16 +991,18 @@ struct chrono_formatter {
|
|||||||
|
|
||||||
void on_am_pm() {
|
void on_am_pm() {
|
||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
format_localized(time(), "%p");
|
format_localized(time(), 'p');
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_duration_value() {
|
void on_duration_value() {
|
||||||
if (handle_nan_inf()) return;
|
if (handle_nan_inf()) return;
|
||||||
write_sign();
|
write_sign();
|
||||||
out = format_chrono_duration_value(out, val, precision);
|
out = format_duration_value<char_type>(out, val, precision);
|
||||||
}
|
}
|
||||||
|
|
||||||
void on_duration_unit() { out = format_chrono_duration_unit<Period>(out); }
|
void on_duration_unit() {
|
||||||
|
out = format_duration_unit<char_type, Period>(out);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -1024,7 +1037,7 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
|
void on_error(const char* msg) { FMT_THROW(format_error(msg)); }
|
||||||
void on_fill(Char fill) { f.specs.fill[0] = fill; }
|
void on_fill(basic_string_view<Char> fill) { f.specs.fill = fill; }
|
||||||
void on_align(align_t align) { f.specs.align = align; }
|
void on_align(align_t align) { f.specs.align = align; }
|
||||||
void on_width(int width) { f.specs.width = width; }
|
void on_width(int width) { f.specs.width = width; }
|
||||||
void on_precision(int _precision) { f.precision = _precision; }
|
void on_precision(int _precision) { f.precision = _precision; }
|
||||||
@ -1088,8 +1101,8 @@ struct formatter<std::chrono::duration<Rep, Period>, Char> {
|
|||||||
internal::handle_dynamic_spec<internal::precision_checker>(
|
internal::handle_dynamic_spec<internal::precision_checker>(
|
||||||
precision, precision_ref, ctx);
|
precision, precision_ref, ctx);
|
||||||
if (begin == end || *begin == '}') {
|
if (begin == end || *begin == '}') {
|
||||||
out = internal::format_chrono_duration_value(out, d.count(), precision);
|
out = internal::format_duration_value<Char>(out, d.count(), precision);
|
||||||
internal::format_chrono_duration_unit<Period>(out);
|
internal::format_duration_unit<Char, Period>(out);
|
||||||
} else {
|
} else {
|
||||||
internal::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
internal::chrono_formatter<FormatContext, decltype(out), Rep, Period> f(
|
||||||
ctx, out, d);
|
ctx, out, d);
|
||||||
|
|||||||
@ -491,10 +491,8 @@ void vformat_to(basic_memory_buffer<Char>& buf, const text_style& ts,
|
|||||||
internal::make_background_color<Char>(ts.get_background());
|
internal::make_background_color<Char>(ts.get_background());
|
||||||
buf.append(background.begin(), background.end());
|
buf.append(background.begin(), background.end());
|
||||||
}
|
}
|
||||||
vformat_to(buf, format_str, args);
|
internal::vformat_to(buf, format_str, args);
|
||||||
if (has_style) {
|
if (has_style) internal::reset_color<Char>(buf);
|
||||||
internal::reset_color<Char>(buf);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
@ -540,7 +538,7 @@ void print(const text_style& ts, const S& format_str, const Args&... args) {
|
|||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vformat(
|
inline std::basic_string<Char> vformat(
|
||||||
const text_style& ts, const S& format_str,
|
const text_style& ts, const S& format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buf;
|
basic_memory_buffer<Char> buf;
|
||||||
internal::vformat_to(buf, ts, to_string_view(format_str), args);
|
internal::vformat_to(buf, ts, to_string_view(format_str), args);
|
||||||
return fmt::to_string(buf);
|
return fmt::to_string(buf);
|
||||||
@ -562,7 +560,7 @@ template <typename S, typename... Args, typename Char = char_t<S>>
|
|||||||
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
inline std::basic_string<Char> format(const text_style& ts, const S& format_str,
|
||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
return vformat(ts, to_string_view(format_str),
|
return vformat(ts, to_string_view(format_str),
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#define FMT_COMPILE_H_
|
#define FMT_COMPILE_H_
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
@ -549,7 +550,7 @@ std::basic_string<Char> format(const CompiledFormat& cf, const Args&... args) {
|
|||||||
using range = buffer_range<Char>;
|
using range = buffer_range<Char>;
|
||||||
using context = buffer_context<Char>;
|
using context = buffer_context<Char>;
|
||||||
internal::cf::vformat_to<context>(range(buffer), cf,
|
internal::cf::vformat_to<context>(range(buffer), cf,
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,8 +562,8 @@ OutputIt format_to(OutputIt out, const CompiledFormat& cf,
|
|||||||
using char_type = typename CompiledFormat::char_type;
|
using char_type = typename CompiledFormat::char_type;
|
||||||
using range = internal::output_range<OutputIt, char_type>;
|
using range = internal::output_range<OutputIt, char_type>;
|
||||||
using context = format_context_t<OutputIt, char_type>;
|
using context = format_context_t<OutputIt, char_type>;
|
||||||
return internal::cf::vformat_to<context>(
|
return internal::cf::vformat_to<context>(range(out), cf,
|
||||||
range(out), cf, {make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
template <typename OutputIt, typename CompiledFormat, typename... Args,
|
||||||
|
|||||||
@ -15,7 +15,7 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
// The fmt library version in the form major * 10000 + minor * 100 + patch.
|
||||||
#define FMT_VERSION 60102
|
#define FMT_VERSION 60103
|
||||||
|
|
||||||
#ifdef __has_feature
|
#ifdef __has_feature
|
||||||
# define FMT_HAS_FEATURE(x) __has_feature(x)
|
# define FMT_HAS_FEATURE(x) __has_feature(x)
|
||||||
@ -217,7 +217,7 @@
|
|||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// Implementations of enable_if_t and other metafunctions for pre-C++14 systems.
|
// Implementations of enable_if_t and other metafunctions for older systems.
|
||||||
template <bool B, class T = void>
|
template <bool B, class T = void>
|
||||||
using enable_if_t = typename std::enable_if<B, T>::type;
|
using enable_if_t = typename std::enable_if<B, T>::type;
|
||||||
template <bool B, class T, class F>
|
template <bool B, class T, class F>
|
||||||
@ -229,6 +229,8 @@ template <typename T>
|
|||||||
using remove_const_t = typename std::remove_const<T>::type;
|
using remove_const_t = typename std::remove_const<T>::type;
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
using remove_cvref_t = typename std::remove_cv<remove_reference_t<T>>::type;
|
||||||
|
template <typename T> struct type_identity { using type = T; };
|
||||||
|
template <typename T> using type_identity_t = typename type_identity<T>::type;
|
||||||
|
|
||||||
struct monostate {};
|
struct monostate {};
|
||||||
|
|
||||||
@ -251,7 +253,7 @@ FMT_API void assert_fail(const char* file, int line, const char* message);
|
|||||||
# define FMT_ASSERT(condition, message) \
|
# define FMT_ASSERT(condition, message) \
|
||||||
((condition) \
|
((condition) \
|
||||||
? void() \
|
? void() \
|
||||||
: fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
|
: ::fmt::internal::assert_fail(__FILE__, __LINE__, (message)))
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -266,7 +268,7 @@ template <typename T> struct std_string_view {};
|
|||||||
|
|
||||||
#ifdef FMT_USE_INT128
|
#ifdef FMT_USE_INT128
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
#elif defined(__SIZEOF_INT128__)
|
#elif defined(__SIZEOF_INT128__) && !FMT_NVCC
|
||||||
# define FMT_USE_INT128 1
|
# define FMT_USE_INT128 1
|
||||||
using int128_t = __int128_t;
|
using int128_t = __int128_t;
|
||||||
using uint128_t = __uint128_t;
|
using uint128_t = __uint128_t;
|
||||||
@ -1220,7 +1222,13 @@ using wformat_context = buffer_context<wchar_t>;
|
|||||||
such as `~fmt::vformat`.
|
such as `~fmt::vformat`.
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Context, typename... Args> class format_arg_store {
|
template <typename Context, typename... Args>
|
||||||
|
class format_arg_store
|
||||||
|
#if FMT_GCC_VERSION < 409
|
||||||
|
// Workaround a GCC template argument substitution bug.
|
||||||
|
: public basic_format_args<Context>
|
||||||
|
#endif
|
||||||
|
{
|
||||||
private:
|
private:
|
||||||
static const size_t num_args = sizeof...(Args);
|
static const size_t num_args = sizeof...(Args);
|
||||||
static const bool is_packed = num_args < internal::max_packed_args;
|
static const bool is_packed = num_args < internal::max_packed_args;
|
||||||
@ -1239,7 +1247,12 @@ template <typename Context, typename... Args> class format_arg_store {
|
|||||||
: internal::is_unpacked_bit | num_args;
|
: internal::is_unpacked_bit | num_args;
|
||||||
|
|
||||||
format_arg_store(const Args&... args)
|
format_arg_store(const Args&... args)
|
||||||
: data_{internal::make_arg<is_packed, Context>(args)...} {}
|
:
|
||||||
|
#if FMT_GCC_VERSION < 409
|
||||||
|
basic_format_args<Context>(*this),
|
||||||
|
#endif
|
||||||
|
data_{internal::make_arg<is_packed, Context>(args)...} {
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1426,21 +1439,23 @@ template <typename... Args, typename S, typename Char = char_t<S>>
|
|||||||
inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
|
inline format_arg_store<buffer_context<Char>, remove_reference_t<Args>...>
|
||||||
make_args_checked(const S& format_str,
|
make_args_checked(const S& format_str,
|
||||||
const remove_reference_t<Args>&... args) {
|
const remove_reference_t<Args>&... args) {
|
||||||
static_assert(all_true<(!std::is_base_of<view, remove_reference_t<Args>>() ||
|
static_assert(
|
||||||
!std::is_reference<Args>())...>::value,
|
all_true<(!std::is_base_of<view, remove_reference_t<Args>>::value ||
|
||||||
|
!std::is_reference<Args>::value)...>::value,
|
||||||
"passing views as lvalues is disallowed");
|
"passing views as lvalues is disallowed");
|
||||||
check_format_string<remove_const_t<remove_reference_t<Args>>...>(format_str);
|
check_format_string<remove_const_t<remove_reference_t<Args>>...>(format_str);
|
||||||
return {args...};
|
return {args...};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
std::basic_string<Char> vformat(basic_string_view<Char> format_str,
|
std::basic_string<Char> vformat(
|
||||||
basic_format_args<buffer_context<Char>> args);
|
basic_string_view<Char> format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args);
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
typename buffer_context<Char>::iterator vformat_to(
|
typename buffer_context<Char>::iterator vformat_to(
|
||||||
buffer<Char>& buf, basic_string_view<Char> format_str,
|
buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args);
|
basic_format_args<buffer_context<type_identity_t<Char>>> args);
|
||||||
|
|
||||||
FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
|
FMT_API void vprint_mojibake(std::FILE*, string_view, format_args);
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
@ -1471,8 +1486,9 @@ void arg(S, internal::named_arg<T, Char>) = delete;
|
|||||||
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
template <typename OutputIt, typename S, typename Char = char_t<S>,
|
||||||
FMT_ENABLE_IF(
|
FMT_ENABLE_IF(
|
||||||
internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
|
internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
|
||||||
OutputIt vformat_to(OutputIt out, const S& format_str,
|
OutputIt vformat_to(
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
OutputIt out, const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
using container = remove_reference_t<decltype(internal::get_container(out))>;
|
using container = remove_reference_t<decltype(internal::get_container(out))>;
|
||||||
internal::container_buffer<container> buf((internal::get_container(out)));
|
internal::container_buffer<container> buf((internal::get_container(out)));
|
||||||
internal::vformat_to(buf, to_string_view(format_str), args);
|
internal::vformat_to(buf, to_string_view(format_str), args);
|
||||||
@ -1485,14 +1501,14 @@ template <typename Container, typename S, typename... Args,
|
|||||||
inline std::back_insert_iterator<Container> format_to(
|
inline std::back_insert_iterator<Container> format_to(
|
||||||
std::back_insert_iterator<Container> out, const S& format_str,
|
std::back_insert_iterator<Container> out, const S& format_str,
|
||||||
Args&&... args) {
|
Args&&... args) {
|
||||||
return vformat_to(
|
return vformat_to(out, to_string_view(format_str),
|
||||||
out, to_string_view(format_str),
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vformat(
|
inline std::basic_string<Char> vformat(
|
||||||
const S& format_str, basic_format_args<buffer_context<Char>> args) {
|
const S& format_str,
|
||||||
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
return internal::vformat(to_string_view(format_str), args);
|
return internal::vformat(to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1512,7 +1528,7 @@ template <typename S, typename... Args, typename Char = char_t<S>>
|
|||||||
inline std::basic_string<Char> format(const S& format_str, Args&&... args) {
|
inline std::basic_string<Char> format(const S& format_str, Args&&... args) {
|
||||||
return internal::vformat(
|
return internal::vformat(
|
||||||
to_string_view(format_str),
|
to_string_view(format_str),
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
FMT_API void vprint(string_view, format_args);
|
FMT_API void vprint(string_view, format_args);
|
||||||
|
|||||||
@ -8,8 +8,6 @@
|
|||||||
#ifndef FMT_FORMAT_INL_H_
|
#ifndef FMT_FORMAT_INL_H_
|
||||||
#define FMT_FORMAT_INL_H_
|
#define FMT_FORMAT_INL_H_
|
||||||
|
|
||||||
#include "format.h"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
#include <climits>
|
#include <climits>
|
||||||
@ -17,6 +15,8 @@
|
|||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstring> // for std::memmove
|
#include <cstring> // for std::memmove
|
||||||
#include <cwchar>
|
#include <cwchar>
|
||||||
|
|
||||||
|
#include "format.h"
|
||||||
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
# include <locale>
|
# include <locale>
|
||||||
#endif
|
#endif
|
||||||
@ -386,7 +386,8 @@ class fp {
|
|||||||
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
const int exponent_bias = (1 << exponent_size) - limits::max_exponent - 1;
|
||||||
auto u = bit_cast<uint64_t>(d);
|
auto u = bit_cast<uint64_t>(d);
|
||||||
f = u & significand_mask;
|
f = u & significand_mask;
|
||||||
auto biased_e = (u & exponent_mask) >> double_significand_size;
|
int biased_e =
|
||||||
|
static_cast<int>((u & exponent_mask) >> double_significand_size);
|
||||||
// Predecessor is closer if d is a normalized power of 2 (f == 0) other than
|
// Predecessor is closer if d is a normalized power of 2 (f == 0) other than
|
||||||
// the smallest normalized number (biased_e > 1).
|
// the smallest normalized number (biased_e > 1).
|
||||||
bool is_predecessor_closer = f == 0 && biased_e > 1;
|
bool is_predecessor_closer = f == 0 && biased_e > 1;
|
||||||
@ -394,7 +395,7 @@ class fp {
|
|||||||
f += implicit_bit;
|
f += implicit_bit;
|
||||||
else
|
else
|
||||||
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
|
biased_e = 1; // Subnormals use biased exponent 1 (min exponent).
|
||||||
e = static_cast<int>(biased_e - exponent_bias - double_significand_size);
|
e = biased_e - exponent_bias - double_significand_size;
|
||||||
return is_predecessor_closer;
|
return is_predecessor_closer;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -458,13 +459,11 @@ inline fp operator*(fp x, fp y) { return {multiply(x.f, y.f), x.e + y.e + 64}; }
|
|||||||
// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its
|
// Returns a cached power of 10 `c_k = c_k.f * pow(2, c_k.e)` such that its
|
||||||
// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`.
|
// (binary) exponent satisfies `min_exponent <= c_k.e <= min_exponent + 28`.
|
||||||
inline fp get_cached_power(int min_exponent, int& pow10_exponent) {
|
inline fp get_cached_power(int min_exponent, int& pow10_exponent) {
|
||||||
const uint64_t one_over_log2_10 = 0x4d104d42; // round(pow(2, 32) / log2(10))
|
const int64_t one_over_log2_10 = 0x4d104d42; // round(pow(2, 32) / log2(10))
|
||||||
int index = static_cast<int>(
|
int index = static_cast<int>(
|
||||||
static_cast<int64_t>(
|
((min_exponent + fp::significand_size - 1) * one_over_log2_10 +
|
||||||
(min_exponent + fp::significand_size - 1) * one_over_log2_10 +
|
((int64_t(1) << 32) - 1)) // ceil
|
||||||
((uint64_t(1) << 32) - 1) // ceil
|
>> 32 // arithmetic shift
|
||||||
) >>
|
|
||||||
32 // arithmetic shift
|
|
||||||
);
|
);
|
||||||
// Decimal exponent of the first (smallest) cached power of 10.
|
// Decimal exponent of the first (smallest) cached power of 10.
|
||||||
const int first_dec_exp = -348;
|
const int first_dec_exp = -348;
|
||||||
@ -1038,7 +1037,7 @@ void fallback_format(Double d, buffer<char>& buf, int& exp10) {
|
|||||||
// if T is a IEEE754 binary32 or binary64 and snprintf otherwise.
|
// if T is a IEEE754 binary32 or binary64 and snprintf otherwise.
|
||||||
template <typename T>
|
template <typename T>
|
||||||
int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
|
int format_float(T value, int precision, float_specs specs, buffer<char>& buf) {
|
||||||
static_assert(!std::is_same<T, float>(), "");
|
static_assert(!std::is_same<T, float>::value, "");
|
||||||
FMT_ASSERT(value >= 0, "value is negative");
|
FMT_ASSERT(value >= 0, "value is negative");
|
||||||
|
|
||||||
const bool fixed = specs.format == float_format::fixed;
|
const bool fixed = specs.format == float_format::fixed;
|
||||||
@ -1113,7 +1112,7 @@ int snprintf_float(T value, int precision, float_specs specs,
|
|||||||
buffer<char>& buf) {
|
buffer<char>& buf) {
|
||||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||||
FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
|
FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
|
||||||
static_assert(!std::is_same<T, float>(), "");
|
static_assert(!std::is_same<T, float>::value, "");
|
||||||
|
|
||||||
// Subtract 1 to account for the difference in precision since we use %e for
|
// Subtract 1 to account for the difference in precision since we use %e for
|
||||||
// both general and exponent format.
|
// both general and exponent format.
|
||||||
@ -1148,7 +1147,8 @@ int snprintf_float(T value, int precision, float_specs specs,
|
|||||||
"fuzz mode - avoid large allocation inside snprintf");
|
"fuzz mode - avoid large allocation inside snprintf");
|
||||||
#endif
|
#endif
|
||||||
// Suppress the warning about a nonliteral format string.
|
// Suppress the warning about a nonliteral format string.
|
||||||
auto snprintf_ptr = FMT_SNPRINTF;
|
// Cannot use auto becase of a bug in MinGW (#1532).
|
||||||
|
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
|
||||||
int result = precision >= 0
|
int result = precision >= 0
|
||||||
? snprintf_ptr(begin, capacity, format, precision, value)
|
? snprintf_ptr(begin, capacity, format, precision, value)
|
||||||
: snprintf_ptr(begin, capacity, format, value);
|
: snprintf_ptr(begin, capacity, format, value);
|
||||||
@ -1380,7 +1380,8 @@ FMT_FUNC void vprint(std::FILE* f, string_view format_str, format_args args) {
|
|||||||
FMT_FUNC void internal::vprint_mojibake(std::FILE* f, string_view format_str,
|
FMT_FUNC void internal::vprint_mojibake(std::FILE* f, string_view format_str,
|
||||||
format_args args) {
|
format_args args) {
|
||||||
memory_buffer buffer;
|
memory_buffer buffer;
|
||||||
vformat_to(buffer, format_str, basic_format_args<buffer_context<char>>(args));
|
internal::vformat_to(buffer, format_str,
|
||||||
|
basic_format_args<buffer_context<char>>(args));
|
||||||
fwrite_fully(buffer.data(), 1, buffer.size(), f);
|
fwrite_fully(buffer.data(), 1, buffer.size(), f);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -33,8 +33,6 @@
|
|||||||
#ifndef FMT_FORMAT_H_
|
#ifndef FMT_FORMAT_H_
|
||||||
#define FMT_FORMAT_H_
|
#define FMT_FORMAT_H_
|
||||||
|
|
||||||
#include "core.h"
|
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
@ -43,6 +41,8 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
#ifdef __clang__
|
#ifdef __clang__
|
||||||
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
|
# define FMT_CLANG_VERSION (__clang_major__ * 100 + __clang_minor__)
|
||||||
#else
|
#else
|
||||||
@ -221,7 +221,7 @@ namespace internal {
|
|||||||
|
|
||||||
// A helper function to suppress bogus "conditional expression is constant"
|
// A helper function to suppress bogus "conditional expression is constant"
|
||||||
// warnings.
|
// warnings.
|
||||||
template <typename T> inline T const_check(T value) { return value; }
|
template <typename T> FMT_CONSTEXPR T const_check(T value) { return value; }
|
||||||
|
|
||||||
// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have
|
// An equivalent of `*reinterpret_cast<Dest*>(&source)` that doesn't have
|
||||||
// undefined behavior (e.g. due to type aliasing).
|
// undefined behavior (e.g. due to type aliasing).
|
||||||
@ -235,7 +235,7 @@ inline Dest bit_cast(const Source& source) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool is_big_endian() {
|
inline bool is_big_endian() {
|
||||||
auto u = 1u;
|
const auto u = 1u;
|
||||||
struct bytes {
|
struct bytes {
|
||||||
char data[sizeof(u)];
|
char data[sizeof(u)];
|
||||||
};
|
};
|
||||||
@ -878,11 +878,11 @@ inline Char* format_decimal(Char* buffer, UInt value, int num_digits,
|
|||||||
return end;
|
return end;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Int> constexpr int digits10() noexcept {
|
template <typename Int> constexpr int digits10() FMT_NOEXCEPT {
|
||||||
return std::numeric_limits<Int>::digits10;
|
return std::numeric_limits<Int>::digits10;
|
||||||
}
|
}
|
||||||
template <> constexpr int digits10<int128_t>() noexcept { return 38; }
|
template <> constexpr int digits10<int128_t>() FMT_NOEXCEPT { return 38; }
|
||||||
template <> constexpr int digits10<uint128_t>() noexcept { return 38; }
|
template <> constexpr int digits10<uint128_t>() FMT_NOEXCEPT { return 38; }
|
||||||
|
|
||||||
template <typename Char, typename UInt, typename Iterator, typename F>
|
template <typename Char, typename UInt, typename Iterator, typename F>
|
||||||
inline Iterator format_decimal(Iterator out, UInt value, int num_digits,
|
inline Iterator format_decimal(Iterator out, UInt value, int num_digits,
|
||||||
@ -962,9 +962,24 @@ template <typename T = void> struct null {};
|
|||||||
// Workaround an array initialization issue in gcc 4.8.
|
// Workaround an array initialization issue in gcc 4.8.
|
||||||
template <typename Char> struct fill_t {
|
template <typename Char> struct fill_t {
|
||||||
private:
|
private:
|
||||||
Char data_[6];
|
enum { max_size = 4 };
|
||||||
|
Char data_[max_size];
|
||||||
|
unsigned char size_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
|
||||||
|
auto size = s.size();
|
||||||
|
if (size > max_size) {
|
||||||
|
FMT_THROW(format_error("invalid fill"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < size; ++i) data_[i] = s[i];
|
||||||
|
size_ = static_cast<unsigned char>(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t size() const { return size_; }
|
||||||
|
const Char* data() const { return data_; }
|
||||||
|
|
||||||
FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; }
|
FMT_CONSTEXPR Char& operator[](size_t index) { return data_[index]; }
|
||||||
FMT_CONSTEXPR const Char& operator[](size_t index) const {
|
FMT_CONSTEXPR const Char& operator[](size_t index) const {
|
||||||
return data_[index];
|
return data_[index];
|
||||||
@ -973,6 +988,7 @@ template <typename Char> struct fill_t {
|
|||||||
static FMT_CONSTEXPR fill_t<Char> make() {
|
static FMT_CONSTEXPR fill_t<Char> make() {
|
||||||
auto fill = fill_t<Char>();
|
auto fill = fill_t<Char>();
|
||||||
fill[0] = Char(' ');
|
fill[0] = Char(' ');
|
||||||
|
fill.size_ = 1;
|
||||||
return fill;
|
return fill;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -1352,6 +1368,14 @@ template <typename Char> struct nonfinite_writer {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename OutputIt, typename Char>
|
||||||
|
OutputIt fill(OutputIt it, size_t n, const fill_t<Char>& fill) {
|
||||||
|
auto fill_size = fill.size();
|
||||||
|
if (fill_size == 1) return std::fill_n(it, n, fill[0]);
|
||||||
|
for (size_t i = 0; i < n; ++i) it = std::copy_n(fill.data(), fill_size, it);
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
// This template provides operations for formatting and writing data into a
|
// This template provides operations for formatting and writing data into a
|
||||||
// character range.
|
// character range.
|
||||||
template <typename Range> class basic_writer {
|
template <typename Range> class basic_writer {
|
||||||
@ -1614,20 +1638,20 @@ template <typename Range> class basic_writer {
|
|||||||
size_t size = f.size(); // The number of code units.
|
size_t size = f.size(); // The number of code units.
|
||||||
size_t num_code_points = width != 0 ? f.width() : size;
|
size_t num_code_points = width != 0 ? f.width() : size;
|
||||||
if (width <= num_code_points) return f(reserve(size));
|
if (width <= num_code_points) return f(reserve(size));
|
||||||
auto&& it = reserve(width + (size - num_code_points));
|
size_t padding = width - num_code_points;
|
||||||
char_type fill = specs.fill[0];
|
size_t fill_size = specs.fill.size();
|
||||||
std::size_t padding = width - num_code_points;
|
auto&& it = reserve(size + padding * fill_size);
|
||||||
if (specs.align == align::right) {
|
if (specs.align == align::right) {
|
||||||
it = std::fill_n(it, padding, fill);
|
it = fill(it, padding, specs.fill);
|
||||||
f(it);
|
f(it);
|
||||||
} else if (specs.align == align::center) {
|
} else if (specs.align == align::center) {
|
||||||
std::size_t left_padding = padding / 2;
|
std::size_t left_padding = padding / 2;
|
||||||
it = std::fill_n(it, left_padding, fill);
|
it = fill(it, left_padding, specs.fill);
|
||||||
f(it);
|
f(it);
|
||||||
it = std::fill_n(it, padding - left_padding, fill);
|
it = fill(it, padding - left_padding, specs.fill);
|
||||||
} else {
|
} else {
|
||||||
f(it);
|
f(it);
|
||||||
it = std::fill_n(it, padding, fill);
|
it = fill(it, padding, specs.fill);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2008,7 +2032,9 @@ template <typename Char> class specs_setter {
|
|||||||
: specs_(other.specs_) {}
|
: specs_(other.specs_) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
|
FMT_CONSTEXPR void on_align(align_t align) { specs_.align = align; }
|
||||||
FMT_CONSTEXPR void on_fill(Char fill) { specs_.fill[0] = fill; }
|
FMT_CONSTEXPR void on_fill(basic_string_view<Char> fill) {
|
||||||
|
specs_.fill = fill;
|
||||||
|
}
|
||||||
FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
|
FMT_CONSTEXPR void on_plus() { specs_.sign = sign::plus; }
|
||||||
FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
|
FMT_CONSTEXPR void on_minus() { specs_.sign = sign::minus; }
|
||||||
FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
|
FMT_CONSTEXPR void on_space() { specs_.sign = sign::space; }
|
||||||
@ -2320,16 +2346,25 @@ template <typename SpecHandler, typename Char> struct precision_adapter {
|
|||||||
SpecHandler& handler;
|
SpecHandler& handler;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char>
|
||||||
|
FMT_CONSTEXPR const Char* next_code_point(const Char* begin, const Char* end) {
|
||||||
|
if (const_check(sizeof(Char) != 1) || (*begin & 0x80) == 0) return begin + 1;
|
||||||
|
do {
|
||||||
|
++begin;
|
||||||
|
} while (begin != end && (*begin & 0xc0) == 0x80);
|
||||||
|
return begin;
|
||||||
|
}
|
||||||
|
|
||||||
// Parses fill and alignment.
|
// Parses fill and alignment.
|
||||||
template <typename Char, typename Handler>
|
template <typename Char, typename Handler>
|
||||||
FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
|
FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
|
||||||
Handler&& handler) {
|
Handler&& handler) {
|
||||||
FMT_ASSERT(begin != end, "");
|
FMT_ASSERT(begin != end, "");
|
||||||
auto align = align::none;
|
auto align = align::none;
|
||||||
int i = 0;
|
auto p = next_code_point(begin, end);
|
||||||
if (begin + 1 != end) ++i;
|
if (p == end) p = begin;
|
||||||
do {
|
for (;;) {
|
||||||
switch (static_cast<char>(begin[i])) {
|
switch (static_cast<char>(*p)) {
|
||||||
case '<':
|
case '<':
|
||||||
align = align::left;
|
align = align::left;
|
||||||
break;
|
break;
|
||||||
@ -2346,18 +2381,21 @@ FMT_CONSTEXPR const Char* parse_align(const Char* begin, const Char* end,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (align != align::none) {
|
if (align != align::none) {
|
||||||
if (i > 0) {
|
if (p != begin) {
|
||||||
auto c = *begin;
|
auto c = *begin;
|
||||||
if (c == '{')
|
if (c == '{')
|
||||||
return handler.on_error("invalid fill character '{'"), begin;
|
return handler.on_error("invalid fill character '{'"), begin;
|
||||||
begin += 2;
|
handler.on_fill(basic_string_view<Char>(begin, p - begin));
|
||||||
handler.on_fill(c);
|
begin = p + 1;
|
||||||
} else
|
} else
|
||||||
++begin;
|
++begin;
|
||||||
handler.on_align(align);
|
handler.on_align(align);
|
||||||
break;
|
break;
|
||||||
|
} else if (p == begin) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
p = begin;
|
||||||
}
|
}
|
||||||
} while (i-- > 0);
|
|
||||||
return begin;
|
return begin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3178,6 +3216,11 @@ arg_join<It, wchar_t> join(It begin, It end, wstring_view sep) {
|
|||||||
std::vector<int> v = {1, 2, 3};
|
std::vector<int> v = {1, 2, 3};
|
||||||
fmt::print("{}", fmt::join(v, ", "));
|
fmt::print("{}", fmt::join(v, ", "));
|
||||||
// Output: "1, 2, 3"
|
// Output: "1, 2, 3"
|
||||||
|
|
||||||
|
``fmt::join`` applies passed format specifiers to the range elements::
|
||||||
|
|
||||||
|
fmt::print("{:02}", fmt::join(v, ", "));
|
||||||
|
// Output: "01, 02, 03"
|
||||||
\endrst
|
\endrst
|
||||||
*/
|
*/
|
||||||
template <typename Range>
|
template <typename Range>
|
||||||
@ -3223,7 +3266,7 @@ std::basic_string<Char> to_string(const basic_memory_buffer<Char, SIZE>& buf) {
|
|||||||
template <typename Char>
|
template <typename Char>
|
||||||
typename buffer_context<Char>::iterator internal::vformat_to(
|
typename buffer_context<Char>::iterator internal::vformat_to(
|
||||||
internal::buffer<Char>& buf, basic_string_view<Char> format_str,
|
internal::buffer<Char>& buf, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
using range = buffer_range<Char>;
|
using range = buffer_range<Char>;
|
||||||
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
|
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str),
|
||||||
args);
|
args);
|
||||||
@ -3233,7 +3276,7 @@ template <typename S, typename Char = char_t<S>,
|
|||||||
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
FMT_ENABLE_IF(internal::is_string<S>::value)>
|
||||||
inline typename buffer_context<Char>::iterator vformat_to(
|
inline typename buffer_context<Char>::iterator vformat_to(
|
||||||
internal::buffer<Char>& buf, const S& format_str,
|
internal::buffer<Char>& buf, const S& format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
return internal::vformat_to(buf, to_string_view(format_str), args);
|
return internal::vformat_to(buf, to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3244,7 +3287,7 @@ inline typename buffer_context<Char>::iterator format_to(
|
|||||||
internal::check_format_string<Args...>(format_str);
|
internal::check_format_string<Args...>(format_str);
|
||||||
using context = buffer_context<Char>;
|
using context = buffer_context<Char>;
|
||||||
return internal::vformat_to(buf, to_string_view(format_str),
|
return internal::vformat_to(buf, to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt, typename Char = char>
|
template <typename OutputIt, typename Char = char>
|
||||||
@ -3257,8 +3300,9 @@ template <typename S, typename OutputIt, typename... Args,
|
|||||||
FMT_ENABLE_IF(
|
FMT_ENABLE_IF(
|
||||||
internal::is_output_iterator<OutputIt>::value &&
|
internal::is_output_iterator<OutputIt>::value &&
|
||||||
!internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
|
!internal::is_contiguous_back_insert_iterator<OutputIt>::value)>
|
||||||
inline OutputIt vformat_to(OutputIt out, const S& format_str,
|
inline OutputIt vformat_to(
|
||||||
format_args_t<OutputIt, char_t<S>> args) {
|
OutputIt out, const S& format_str,
|
||||||
|
format_args_t<type_identity_t<OutputIt>, char_t<S>> args) {
|
||||||
using range = internal::output_range<OutputIt, char_t<S>>;
|
using range = internal::output_range<OutputIt, char_t<S>>;
|
||||||
return vformat_to<arg_formatter<range>>(range(out),
|
return vformat_to<arg_formatter<range>>(range(out),
|
||||||
to_string_view(format_str), args);
|
to_string_view(format_str), args);
|
||||||
@ -3284,7 +3328,7 @@ inline OutputIt format_to(OutputIt out, const S& format_str, Args&&... args) {
|
|||||||
internal::check_format_string<Args...>(format_str);
|
internal::check_format_string<Args...>(format_str);
|
||||||
using context = format_context_t<OutputIt, char_t<S>>;
|
using context = format_context_t<OutputIt, char_t<S>>;
|
||||||
return vformat_to(out, to_string_view(format_str),
|
return vformat_to(out, to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename OutputIt> struct format_to_n_result {
|
template <typename OutputIt> struct format_to_n_result {
|
||||||
@ -3312,7 +3356,7 @@ template <typename OutputIt, typename Char, typename... Args,
|
|||||||
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
|
FMT_ENABLE_IF(internal::is_output_iterator<OutputIt>::value)>
|
||||||
inline format_to_n_result<OutputIt> vformat_to_n(
|
inline format_to_n_result<OutputIt> vformat_to_n(
|
||||||
OutputIt out, std::size_t n, basic_string_view<Char> format_str,
|
OutputIt out, std::size_t n, basic_string_view<Char> format_str,
|
||||||
format_to_n_args<OutputIt, Char> args) {
|
format_to_n_args<type_identity_t<OutputIt>, type_identity_t<Char>> args) {
|
||||||
auto it = vformat_to(internal::truncating_iterator<OutputIt>(out, n),
|
auto it = vformat_to(internal::truncating_iterator<OutputIt>(out, n),
|
||||||
format_str, args);
|
format_str, args);
|
||||||
return {it.base(), it.count()};
|
return {it.base(), it.count()};
|
||||||
@ -3334,13 +3378,13 @@ inline format_to_n_result<OutputIt> format_to_n(OutputIt out, std::size_t n,
|
|||||||
internal::check_format_string<Args...>(format_str);
|
internal::check_format_string<Args...>(format_str);
|
||||||
using context = format_to_n_context<OutputIt, char_t<S>>;
|
using context = format_to_n_context<OutputIt, char_t<S>>;
|
||||||
return vformat_to_n(out, n, to_string_view(format_str),
|
return vformat_to_n(out, n, to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
inline std::basic_string<Char> internal::vformat(
|
inline std::basic_string<Char> internal::vformat(
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
internal::vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
@ -3405,6 +3449,10 @@ template <typename Char> struct udl_arg {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename Char, size_t N>
|
||||||
|
FMT_CONSTEXPR basic_string_view<Char> literal_to_view(const Char (&s)[N]) {
|
||||||
|
return {s, N - 1};
|
||||||
|
}
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
|
|
||||||
inline namespace literals {
|
inline namespace literals {
|
||||||
@ -3468,7 +3516,8 @@ FMT_END_NAMESPACE
|
|||||||
using char_type = fmt::remove_cvref_t<decltype(*s)>; \
|
using char_type = fmt::remove_cvref_t<decltype(*s)>; \
|
||||||
__VA_ARGS__ FMT_CONSTEXPR \
|
__VA_ARGS__ FMT_CONSTEXPR \
|
||||||
operator fmt::basic_string_view<char_type>() const { \
|
operator fmt::basic_string_view<char_type>() const { \
|
||||||
return {s, sizeof(s) / sizeof(char_type) - 1}; \
|
/* FMT_STRING only accepts string literals. */ \
|
||||||
|
return fmt::internal::literal_to_view(s); \
|
||||||
} \
|
} \
|
||||||
}; \
|
}; \
|
||||||
return FMT_STRING(); \
|
return FMT_STRING(); \
|
||||||
@ -3476,7 +3525,7 @@ FMT_END_NAMESPACE
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
\rst
|
\rst
|
||||||
Constructs a compile-time format string.
|
Constructs a compile-time format string from a string literal *s*.
|
||||||
|
|
||||||
**Example**::
|
**Example**::
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@
|
|||||||
#define FMT_LOCALE_H_
|
#define FMT_LOCALE_H_
|
||||||
|
|
||||||
#include <locale>
|
#include <locale>
|
||||||
|
|
||||||
#include "format.h"
|
#include "format.h"
|
||||||
|
|
||||||
FMT_BEGIN_NAMESPACE
|
FMT_BEGIN_NAMESPACE
|
||||||
@ -18,16 +19,16 @@ template <typename Char>
|
|||||||
typename buffer_context<Char>::iterator vformat_to(
|
typename buffer_context<Char>::iterator vformat_to(
|
||||||
const std::locale& loc, buffer<Char>& buf,
|
const std::locale& loc, buffer<Char>& buf,
|
||||||
basic_string_view<Char> format_str,
|
basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
using range = buffer_range<Char>;
|
using range = buffer_range<Char>;
|
||||||
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
|
return vformat_to<arg_formatter<range>>(buf, to_string_view(format_str), args,
|
||||||
internal::locale_ref(loc));
|
internal::locale_ref(loc));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
std::basic_string<Char> vformat(const std::locale& loc,
|
std::basic_string<Char> vformat(
|
||||||
basic_string_view<Char> format_str,
|
const std::locale& loc, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
internal::vformat_to(loc, buffer, format_str, args);
|
internal::vformat_to(loc, buffer, format_str, args);
|
||||||
return fmt::to_string(buffer);
|
return fmt::to_string(buffer);
|
||||||
@ -37,7 +38,7 @@ std::basic_string<Char> vformat(const std::locale& loc,
|
|||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vformat(
|
inline std::basic_string<Char> vformat(
|
||||||
const std::locale& loc, const S& format_str,
|
const std::locale& loc, const S& format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
return internal::vformat(loc, to_string_view(format_str), args);
|
return internal::vformat(loc, to_string_view(format_str), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -46,15 +47,15 @@ inline std::basic_string<Char> format(const std::locale& loc,
|
|||||||
const S& format_str, Args&&... args) {
|
const S& format_str, Args&&... args) {
|
||||||
return internal::vformat(
|
return internal::vformat(
|
||||||
loc, to_string_view(format_str),
|
loc, to_string_view(format_str),
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename OutputIt, typename... Args,
|
template <typename S, typename OutputIt, typename... Args,
|
||||||
typename Char = enable_if_t<
|
typename Char = enable_if_t<
|
||||||
internal::is_output_iterator<OutputIt>::value, char_t<S>>>
|
internal::is_output_iterator<OutputIt>::value, char_t<S>>>
|
||||||
inline OutputIt vformat_to(OutputIt out, const std::locale& loc,
|
inline OutputIt vformat_to(
|
||||||
const S& format_str,
|
OutputIt out, const std::locale& loc, const S& format_str,
|
||||||
format_args_t<OutputIt, Char> args) {
|
format_args_t<type_identity_t<OutputIt>, Char> args) {
|
||||||
using range = internal::output_range<OutputIt, Char>;
|
using range = internal::output_range<OutputIt, Char>;
|
||||||
return vformat_to<arg_formatter<range>>(
|
return vformat_to<arg_formatter<range>>(
|
||||||
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
range(out), to_string_view(format_str), args, internal::locale_ref(loc));
|
||||||
|
|||||||
@ -93,7 +93,9 @@ void format_value(buffer<Char>& buf, const T& value,
|
|||||||
locale_ref loc = locale_ref()) {
|
locale_ref loc = locale_ref()) {
|
||||||
formatbuf<Char> format_buf(buf);
|
formatbuf<Char> format_buf(buf);
|
||||||
std::basic_ostream<Char> output(&format_buf);
|
std::basic_ostream<Char> output(&format_buf);
|
||||||
|
#if !defined(FMT_STATIC_THOUSANDS_SEPARATOR)
|
||||||
if (loc) output.imbue(loc.get<std::locale>());
|
if (loc) output.imbue(loc.get<std::locale>());
|
||||||
|
#endif
|
||||||
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
output.exceptions(std::ios_base::failbit | std::ios_base::badbit);
|
||||||
output << value;
|
output << value;
|
||||||
buf.resize(buf.size());
|
buf.resize(buf.size());
|
||||||
@ -115,7 +117,7 @@ struct fallback_formatter<T, Char, enable_if_t<is_streamable<T, Char>::value>>
|
|||||||
|
|
||||||
template <typename Char>
|
template <typename Char>
|
||||||
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
void vprint(std::basic_ostream<Char>& os, basic_string_view<Char> format_str,
|
||||||
basic_format_args<buffer_context<Char>> args) {
|
basic_format_args<buffer_context<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
internal::vformat_to(buffer, format_str, args);
|
internal::vformat_to(buffer, format_str, args);
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
@ -134,7 +136,7 @@ template <typename S, typename... Args,
|
|||||||
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
||||||
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
void print(std::basic_ostream<Char>& os, const S& format_str, Args&&... args) {
|
||||||
vprint(os, to_string_view(format_str),
|
vprint(os, to_string_view(format_str),
|
||||||
{internal::make_args_checked<Args...>(format_str, args...)});
|
internal::make_args_checked<Args...>(format_str, args...));
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|||||||
@ -597,7 +597,8 @@ inline format_arg_store<wprintf_context, Args...> make_wprintf_args(
|
|||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline std::basic_string<Char> vsprintf(
|
inline std::basic_string<Char> vsprintf(
|
||||||
const S& format, basic_format_args<basic_printf_context_t<Char>> args) {
|
const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, to_string_view(format), args);
|
printf(buffer, to_string_view(format), args);
|
||||||
return to_string(buffer);
|
return to_string(buffer);
|
||||||
@ -616,12 +617,13 @@ template <typename S, typename... Args,
|
|||||||
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
typename Char = enable_if_t<internal::is_string<S>::value, char_t<S>>>
|
||||||
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
|
inline std::basic_string<Char> sprintf(const S& format, const Args&... args) {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vsprintf(to_string_view(format), {make_format_args<context>(args...)});
|
return vsprintf(to_string_view(format), make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline int vfprintf(std::FILE* f, const S& format,
|
inline int vfprintf(
|
||||||
basic_format_args<basic_printf_context_t<Char>> args) {
|
std::FILE* f, const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, to_string_view(format), args);
|
printf(buffer, to_string_view(format), args);
|
||||||
std::size_t size = buffer.size();
|
std::size_t size = buffer.size();
|
||||||
@ -644,12 +646,13 @@ template <typename S, typename... Args,
|
|||||||
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
|
inline int fprintf(std::FILE* f, const S& format, const Args&... args) {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vfprintf(f, to_string_view(format),
|
return vfprintf(f, to_string_view(format),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline int vprintf(const S& format,
|
inline int vprintf(
|
||||||
basic_format_args<basic_printf_context_t<Char>> args) {
|
const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
return vfprintf(stdout, to_string_view(format), args);
|
return vfprintf(stdout, to_string_view(format), args);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -667,12 +670,13 @@ template <typename S, typename... Args,
|
|||||||
inline int printf(const S& format_str, const Args&... args) {
|
inline int printf(const S& format_str, const Args&... args) {
|
||||||
using context = basic_printf_context_t<char_t<S>>;
|
using context = basic_printf_context_t<char_t<S>>;
|
||||||
return vprintf(to_string_view(format_str),
|
return vprintf(to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename S, typename Char = char_t<S>>
|
template <typename S, typename Char = char_t<S>>
|
||||||
inline int vfprintf(std::basic_ostream<Char>& os, const S& format,
|
inline int vfprintf(
|
||||||
basic_format_args<basic_printf_context_t<Char>> args) {
|
std::basic_ostream<Char>& os, const S& format,
|
||||||
|
basic_format_args<basic_printf_context_t<type_identity_t<Char>>> args) {
|
||||||
basic_memory_buffer<Char> buffer;
|
basic_memory_buffer<Char> buffer;
|
||||||
printf(buffer, to_string_view(format), args);
|
printf(buffer, to_string_view(format), args);
|
||||||
internal::write(os, buffer);
|
internal::write(os, buffer);
|
||||||
@ -683,9 +687,9 @@ inline int vfprintf(std::basic_ostream<Char>& os, const S& format,
|
|||||||
template <typename ArgFormatter, typename Char,
|
template <typename ArgFormatter, typename Char,
|
||||||
typename Context =
|
typename Context =
|
||||||
basic_printf_context<typename ArgFormatter::iterator, Char>>
|
basic_printf_context<typename ArgFormatter::iterator, Char>>
|
||||||
typename ArgFormatter::iterator vprintf(internal::buffer<Char>& out,
|
typename ArgFormatter::iterator vprintf(
|
||||||
basic_string_view<Char> format_str,
|
internal::buffer<Char>& out, basic_string_view<Char> format_str,
|
||||||
basic_format_args<Context> args) {
|
basic_format_args<type_identity_t<Context>> args) {
|
||||||
typename ArgFormatter::iterator iter(out);
|
typename ArgFormatter::iterator iter(out);
|
||||||
Context(iter, format_str, args).template format<ArgFormatter>();
|
Context(iter, format_str, args).template format<ArgFormatter>();
|
||||||
return iter;
|
return iter;
|
||||||
@ -705,7 +709,7 @@ inline int fprintf(std::basic_ostream<Char>& os, const S& format_str,
|
|||||||
const Args&... args) {
|
const Args&... args) {
|
||||||
using context = basic_printf_context_t<Char>;
|
using context = basic_printf_context_t<Char>;
|
||||||
return vfprintf(os, to_string_view(format_str),
|
return vfprintf(os, to_string_view(format_str),
|
||||||
{make_format_args<context>(args...)});
|
make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
FMT_END_NAMESPACE
|
FMT_END_NAMESPACE
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ int format_float(char* buf, std::size_t size, const char* format, int precision,
|
|||||||
"fuzz mode - avoid large allocation inside snprintf");
|
"fuzz mode - avoid large allocation inside snprintf");
|
||||||
#endif
|
#endif
|
||||||
// Suppress the warning about nonliteral format string.
|
// Suppress the warning about nonliteral format string.
|
||||||
auto snprintf_ptr = FMT_SNPRINTF;
|
int (*snprintf_ptr)(char*, size_t, const char*, ...) = FMT_SNPRINTF;
|
||||||
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
return precision < 0 ? snprintf_ptr(buf, size, format, value)
|
||||||
: snprintf_ptr(buf, size, format, precision, value);
|
: snprintf_ptr(buf, size, format, precision, value);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -145,6 +145,48 @@ TEST(ChronoTest, FormatDefault) {
|
|||||||
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
fmt::format("{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ChronoTest, FormatWide) {
|
||||||
|
EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
|
||||||
|
EXPECT_EQ(L"42as",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::atto>(42)));
|
||||||
|
EXPECT_EQ(L"42fs",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::femto>(42)));
|
||||||
|
EXPECT_EQ(L"42ps",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::pico>(42)));
|
||||||
|
EXPECT_EQ(L"42ns", fmt::format(L"{}", std::chrono::nanoseconds(42)));
|
||||||
|
EXPECT_EQ(L"42\u00B5s", fmt::format(L"{}", std::chrono::microseconds(42)));
|
||||||
|
EXPECT_EQ(L"42ms", fmt::format(L"{}", std::chrono::milliseconds(42)));
|
||||||
|
EXPECT_EQ(L"42cs",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::centi>(42)));
|
||||||
|
EXPECT_EQ(L"42ds",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::deci>(42)));
|
||||||
|
EXPECT_EQ(L"42s", fmt::format(L"{}", std::chrono::seconds(42)));
|
||||||
|
EXPECT_EQ(L"42das",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::deca>(42)));
|
||||||
|
EXPECT_EQ(L"42hs",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::hecto>(42)));
|
||||||
|
EXPECT_EQ(L"42ks",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::kilo>(42)));
|
||||||
|
EXPECT_EQ(L"42Ms",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::mega>(42)));
|
||||||
|
EXPECT_EQ(L"42Gs",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::giga>(42)));
|
||||||
|
EXPECT_EQ(L"42Ts",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::tera>(42)));
|
||||||
|
EXPECT_EQ(L"42Ps",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::peta>(42)));
|
||||||
|
EXPECT_EQ(L"42Es",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::exa>(42)));
|
||||||
|
EXPECT_EQ(L"42m", fmt::format(L"{}", std::chrono::minutes(42)));
|
||||||
|
EXPECT_EQ(L"42h", fmt::format(L"{}", std::chrono::hours(42)));
|
||||||
|
EXPECT_EQ(
|
||||||
|
L"42[15]s",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::ratio<15, 1>>(42)));
|
||||||
|
EXPECT_EQ(
|
||||||
|
L"42[15/4]s",
|
||||||
|
fmt::format(L"{}", std::chrono::duration<int, std::ratio<15, 4>>(42)));
|
||||||
|
}
|
||||||
|
|
||||||
TEST(ChronoTest, Align) {
|
TEST(ChronoTest, Align) {
|
||||||
auto s = std::chrono::seconds(42);
|
auto s = std::chrono::seconds(42);
|
||||||
EXPECT_EQ("42s ", fmt::format("{:5}", s));
|
EXPECT_EQ("42s ", fmt::format("{:5}", s));
|
||||||
|
|||||||
12
test/format
12
test/format
@ -83,9 +83,9 @@ namespace std {
|
|||||||
Out format_to(Out out, wstring_view fmt, const Args&... args);
|
Out format_to(Out out, wstring_view fmt, const Args&... args);
|
||||||
|
|
||||||
template<class Out>
|
template<class Out>
|
||||||
Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args);
|
Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args);
|
||||||
template<class Out>
|
template<class Out>
|
||||||
Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
|
Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
|
||||||
|
|
||||||
template<class Out>
|
template<class Out>
|
||||||
struct format_to_n_result {
|
struct format_to_n_result {
|
||||||
@ -730,17 +730,17 @@ wstring vformat(wstring_view fmt, wformat_args args);
|
|||||||
template<class Out, class... Args>
|
template<class Out, class... Args>
|
||||||
Out format_to(Out out, string_view fmt, const Args&... args) {
|
Out format_to(Out out, string_view fmt, const Args&... args) {
|
||||||
using context = basic_format_context<Out, decltype(fmt)::value_type>;
|
using context = basic_format_context<Out, decltype(fmt)::value_type>;
|
||||||
return vformat_to(out, fmt, {make_format_args<context>(args...)});
|
return vformat_to(out, fmt, make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Out, class... Args>
|
template<class Out, class... Args>
|
||||||
Out format_to(Out out, wstring_view fmt, const Args&... args) {
|
Out format_to(Out out, wstring_view fmt, const Args&... args) {
|
||||||
using context = basic_format_context<Out, decltype(fmt)::value_type>;
|
using context = basic_format_context<Out, decltype(fmt)::value_type>;
|
||||||
return vformat_to(out, fmt, {make_format_args<context>(args...)});
|
return vformat_to(out, fmt, make_format_args<context>(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class Out>
|
template<class Out>
|
||||||
Out vformat_to(Out out, string_view fmt, format_args_t<Out, char> args) {
|
Out vformat_to(Out out, string_view fmt, format_args_t<fmt::type_identity_t<Out>, char> args) {
|
||||||
using range = fmt::internal::output_range<Out, char>;
|
using range = fmt::internal::output_range<Out, char>;
|
||||||
detail::format_handler<detail::arg_formatter<range>, char, basic_format_context<Out, char>>
|
detail::format_handler<detail::arg_formatter<range>, char, basic_format_context<Out, char>>
|
||||||
h(range(out), fmt, args, {});
|
h(range(out), fmt, args, {});
|
||||||
@ -749,7 +749,7 @@ template<class Out>
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class Out>
|
template<class Out>
|
||||||
Out vformat_to(Out out, wstring_view fmt, format_args_t<Out, wchar_t> args);
|
Out vformat_to(Out out, wstring_view fmt, format_args_t<fmt::type_identity_t<Out>, wchar_t> args);
|
||||||
|
|
||||||
template<class Out, class... Args>
|
template<class Out, class... Args>
|
||||||
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
|
format_to_n_result<Out> format_to_n(Out out, iter_difference_t<Out> n,
|
||||||
|
|||||||
@ -815,6 +815,9 @@ TEST(FormatterTest, Fill) {
|
|||||||
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
|
EXPECT_EQ("**0xface", format("{0:*>8}", reinterpret_cast<void*>(0xface)));
|
||||||
EXPECT_EQ("foo=", format("{:}=", "foo"));
|
EXPECT_EQ("foo=", format("{:}=", "foo"));
|
||||||
EXPECT_EQ(std::string("\0\0\0*", 4), format(string_view("{:\0>4}", 6), '*'));
|
EXPECT_EQ(std::string("\0\0\0*", 4), format(string_view("{:\0>4}", 6), '*'));
|
||||||
|
EXPECT_EQ("жж42", format("{0:ж>4}", 42));
|
||||||
|
EXPECT_THROW_MSG(format("{:\x80\x80\x80\x80\x80>}", 0), format_error,
|
||||||
|
"invalid fill");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(FormatterTest, PlusSign) {
|
TEST(FormatterTest, PlusSign) {
|
||||||
@ -2173,7 +2176,7 @@ struct test_format_specs_handler {
|
|||||||
type(other.type) {}
|
type(other.type) {}
|
||||||
|
|
||||||
FMT_CONSTEXPR void on_align(fmt::align_t a) { align = a; }
|
FMT_CONSTEXPR void on_align(fmt::align_t a) { align = a; }
|
||||||
FMT_CONSTEXPR void on_fill(char f) { fill = f; }
|
FMT_CONSTEXPR void on_fill(fmt::string_view f) { fill = f[0]; }
|
||||||
FMT_CONSTEXPR void on_plus() { res = PLUS; }
|
FMT_CONSTEXPR void on_plus() { res = PLUS; }
|
||||||
FMT_CONSTEXPR void on_minus() { res = MINUS; }
|
FMT_CONSTEXPR void on_minus() { res = MINUS; }
|
||||||
FMT_CONSTEXPR void on_space() { res = SPACE; }
|
FMT_CONSTEXPR void on_space() { res = SPACE; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user