mirror of
https://github.com/shadps4-emu/ext-fmt.git
synced 2024-11-23 09:49:42 +00:00
Get rid of bit fields
This commit is contained in:
parent
f8c0c8ee78
commit
b906c321f0
@ -2092,51 +2092,6 @@ using unsigned_char = typename conditional_t<std::is_integral<Char>::value,
|
||||
std::make_unsigned<Char>,
|
||||
type_identity<unsigned>>::type;
|
||||
|
||||
// Character (code unit) type is erased to prevent template bloat.
|
||||
struct fill_t {
|
||||
private:
|
||||
enum { max_size = 4 };
|
||||
char data_[max_size] = {' '};
|
||||
unsigned char size_ = 1;
|
||||
|
||||
public:
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR void operator=(basic_string_view<Char> s) {
|
||||
auto size = s.size();
|
||||
size_ = static_cast<unsigned char>(size);
|
||||
if (size == 1) {
|
||||
unsigned uchar = static_cast<unsigned_char<Char>>(s[0]);
|
||||
data_[0] = static_cast<char>(uchar);
|
||||
data_[1] = static_cast<char>(uchar >> 8);
|
||||
return;
|
||||
}
|
||||
FMT_ASSERT(size <= max_size, "invalid fill");
|
||||
for (size_t i = 0; i < size; ++i) data_[i] = static_cast<char>(s[i]);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void operator=(char c) {
|
||||
data_[0] = c;
|
||||
size_ = 1;
|
||||
}
|
||||
|
||||
constexpr auto size() const -> size_t { return size_; }
|
||||
|
||||
template <typename Char> constexpr auto get() const -> Char {
|
||||
using uchar = unsigned char;
|
||||
return static_cast<Char>(static_cast<uchar>(data_[0]) |
|
||||
(static_cast<uchar>(data_[1]) << 8));
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
|
||||
constexpr auto data() const -> const Char* {
|
||||
return data_;
|
||||
}
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
constexpr auto data() const -> const Char* {
|
||||
return nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
enum class arg_id_kind { none, index, name };
|
||||
|
||||
} // namespace detail
|
||||
@ -2164,39 +2119,156 @@ enum class presentation_type : unsigned char {
|
||||
hexfloat // 'a' or 'A'
|
||||
};
|
||||
|
||||
// Basic format specifiers for built-in and string types.
|
||||
class basic_specs {
|
||||
private:
|
||||
// Upper 32-bit of data contain fill and lower 32-bit are arranged as follows:
|
||||
//
|
||||
// 0 1 2 3
|
||||
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
// +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
// |type |align| w | p | s |u|#|L| f | unused |
|
||||
// +-----+-----+---+---+---+-+-+-+-----+---------------------------+
|
||||
//
|
||||
// w - dynamic width info
|
||||
// p - dynamic precision info
|
||||
// s - sign
|
||||
// u - uppercase (e.g. 'X' for 'x')
|
||||
// # - alternate form ('#')
|
||||
// L - localized
|
||||
// f - fill size
|
||||
//
|
||||
// Bitfields are not used because of compiler bugs such as gcc bug 61414.
|
||||
enum : unsigned {
|
||||
type_mask = 0x00007,
|
||||
align_mask = 0x00038,
|
||||
width_mask = 0x000C0,
|
||||
precision_mask = 0x00300,
|
||||
sign_mask = 0x00C00,
|
||||
uppercase_mask = 0x01000,
|
||||
alternate_mask = 0x02000,
|
||||
localized_mask = 0x04000,
|
||||
fill_size_mask = 0x38000,
|
||||
|
||||
align_shift = 3,
|
||||
width_shift = 6,
|
||||
precision_shift = 8,
|
||||
sign_shift = 10,
|
||||
fill_size_shift = 15,
|
||||
|
||||
max_fill_size = 4
|
||||
};
|
||||
|
||||
unsigned long long data_ = 1 << fill_size_shift;
|
||||
|
||||
// Character (code unit) type is erased to prevent template bloat.
|
||||
char fill_data_[max_fill_size] = {' '};
|
||||
|
||||
FMT_CONSTEXPR void set_fill_size(size_t size) {
|
||||
data_ = (data_ & ~fill_size_mask) | (size << fill_size_shift);
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr auto type() const -> presentation_type {
|
||||
return static_cast<presentation_type>(data_ & type_mask);
|
||||
}
|
||||
FMT_CONSTEXPR void set_type(presentation_type t) {
|
||||
data_ = (data_ & ~type_mask) | static_cast<unsigned>(t);
|
||||
}
|
||||
|
||||
constexpr auto align() const -> align_t {
|
||||
return static_cast<align_t>((data_ & align_mask) >> align_shift);
|
||||
}
|
||||
FMT_CONSTEXPR void set_align(align_t a) {
|
||||
data_ = (data_ & ~align_mask) | (static_cast<unsigned>(a) << align_shift);
|
||||
}
|
||||
|
||||
constexpr auto dynamic_width() const -> detail::arg_id_kind {
|
||||
return static_cast<detail::arg_id_kind>((data_ & width_mask) >>
|
||||
width_shift);
|
||||
}
|
||||
FMT_CONSTEXPR void set_dynamic_width(detail::arg_id_kind w) {
|
||||
data_ = (data_ & ~width_mask) | (static_cast<unsigned>(w) << width_shift);
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR auto dynamic_precision() const -> detail::arg_id_kind {
|
||||
return static_cast<detail::arg_id_kind>((data_ & precision_mask) >>
|
||||
precision_shift);
|
||||
}
|
||||
FMT_CONSTEXPR void set_dynamic_precision(detail::arg_id_kind p) {
|
||||
data_ = (data_ & ~precision_mask) |
|
||||
(static_cast<unsigned>(p) << precision_shift);
|
||||
}
|
||||
|
||||
constexpr bool dynamic() const {
|
||||
return (data_ & (width_mask | precision_mask)) != 0;
|
||||
}
|
||||
|
||||
constexpr auto sign() const -> sign_t {
|
||||
return static_cast<sign_t>((data_ & sign_mask) >> sign_shift);
|
||||
}
|
||||
FMT_CONSTEXPR void set_sign(sign_t a) {
|
||||
data_ = (data_ & ~sign_mask) | (static_cast<unsigned>(a) << sign_shift);
|
||||
}
|
||||
|
||||
constexpr auto upper() const -> bool { return (data_ & uppercase_mask) != 0; }
|
||||
FMT_CONSTEXPR void set_upper() { data_ |= uppercase_mask; }
|
||||
|
||||
constexpr auto alt() const -> bool { return (data_ & alternate_mask) != 0; }
|
||||
FMT_CONSTEXPR void set_alt() { data_ |= alternate_mask; }
|
||||
FMT_CONSTEXPR void clear_alt() { data_ &= ~alternate_mask; }
|
||||
|
||||
constexpr auto localized() const -> bool {
|
||||
return (data_ & localized_mask) != 0;
|
||||
}
|
||||
FMT_CONSTEXPR void set_localized() { data_ |= localized_mask; }
|
||||
|
||||
constexpr auto fill_size() const -> size_t {
|
||||
return (data_ & fill_size_mask) >> fill_size_shift;
|
||||
}
|
||||
|
||||
template <typename Char, FMT_ENABLE_IF(std::is_same<Char, char>::value)>
|
||||
constexpr auto fill() const -> const Char* {
|
||||
return fill_data_;
|
||||
}
|
||||
template <typename Char, FMT_ENABLE_IF(!std::is_same<Char, char>::value)>
|
||||
constexpr auto fill() const -> const Char* {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename Char> constexpr auto fill_unit() const -> Char {
|
||||
using uchar = unsigned char;
|
||||
return static_cast<Char>(static_cast<uchar>(fill_data_[0]) |
|
||||
(static_cast<uchar>(fill_data_[1]) << 8));
|
||||
}
|
||||
|
||||
FMT_CONSTEXPR void set_fill(char c) {
|
||||
fill_data_[0] = c;
|
||||
set_fill_size(1);
|
||||
}
|
||||
|
||||
template <typename Char>
|
||||
FMT_CONSTEXPR void set_fill(basic_string_view<Char> s) {
|
||||
auto size = s.size();
|
||||
set_fill_size(size);
|
||||
if (size == 1) {
|
||||
unsigned uchar = static_cast<detail::unsigned_char<Char>>(s[0]);
|
||||
fill_data_[0] = static_cast<char>(uchar);
|
||||
fill_data_[1] = static_cast<char>(uchar >> 8);
|
||||
return;
|
||||
}
|
||||
FMT_ASSERT(size <= max_fill_size, "invalid fill");
|
||||
for (size_t i = 0; i < size; ++i)
|
||||
fill_data_[i & 3] = static_cast<char>(s[i]);
|
||||
}
|
||||
};
|
||||
|
||||
// Format specifiers for built-in and string types.
|
||||
struct format_specs {
|
||||
struct format_specs : basic_specs {
|
||||
int width;
|
||||
int precision;
|
||||
presentation_type type;
|
||||
align_t align : 4;
|
||||
sign_t sign : 3;
|
||||
unsigned char dynamic : 4;
|
||||
bool upper : 1; // An uppercase version e.g. 'X' for 'x'.
|
||||
bool alt : 1; // Alternate form ('#').
|
||||
bool localized : 1;
|
||||
detail::fill_t fill;
|
||||
|
||||
constexpr format_specs()
|
||||
: width(0),
|
||||
precision(-1),
|
||||
type(presentation_type::none),
|
||||
align(align::none),
|
||||
sign(sign::none),
|
||||
dynamic(0),
|
||||
upper(false),
|
||||
alt(false),
|
||||
localized(false) {}
|
||||
|
||||
FMT_CONSTEXPR auto dynamic_width() const -> detail::arg_id_kind {
|
||||
enum { dynamic_width_mask = 3 };
|
||||
return static_cast<detail::arg_id_kind>(dynamic & dynamic_width_mask);
|
||||
}
|
||||
FMT_CONSTEXPR auto dynamic_precision() const -> detail::arg_id_kind {
|
||||
enum { dynamic_precision_mask = 12 };
|
||||
return static_cast<detail::arg_id_kind>(
|
||||
(dynamic & dynamic_precision_mask) >> 2);
|
||||
}
|
||||
constexpr format_specs() : width(0), precision(-1) {}
|
||||
};
|
||||
|
||||
namespace detail {
|
||||
@ -2381,7 +2453,7 @@ FMT_CONSTEXPR auto parse_width(const Char* begin, const Char* end,
|
||||
basic_format_parse_context<Char>& ctx)
|
||||
-> const Char* {
|
||||
auto result = parse_dynamic_spec(begin, end, specs.width, width_ref, ctx);
|
||||
specs.dynamic = static_cast<unsigned char>(result.kind) & 0x3u;
|
||||
specs.set_dynamic_width(result.kind);
|
||||
return result.end;
|
||||
}
|
||||
|
||||
@ -2398,9 +2470,7 @@ FMT_CONSTEXPR auto parse_precision(const Char* begin, const Char* end,
|
||||
}
|
||||
auto result =
|
||||
parse_dynamic_spec(begin, end, specs.precision, precision_ref, ctx);
|
||||
auto kind_val = static_cast<unsigned char>(result.kind);
|
||||
specs.dynamic =
|
||||
static_cast<unsigned char>(specs.dynamic | (kind_val << 2)) & 0xfu;
|
||||
specs.set_dynamic_precision(result.kind);
|
||||
return result.end;
|
||||
}
|
||||
|
||||
@ -2439,7 +2509,7 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
||||
|
||||
FMT_CONSTEXPR auto operator()(pres pres_type, int set) -> const Char* {
|
||||
if (!in(arg_type, set)) report_error("invalid format specifier");
|
||||
specs.type = pres_type;
|
||||
specs.set_type(pres_type);
|
||||
return begin + 1;
|
||||
}
|
||||
} parse_presentation_type{begin, specs, arg_type};
|
||||
@ -2450,13 +2520,13 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
||||
case '>':
|
||||
case '^':
|
||||
enter_state(state::align);
|
||||
specs.align = parse_align(c);
|
||||
specs.set_align(parse_align(c));
|
||||
++begin;
|
||||
break;
|
||||
case '+':
|
||||
FMT_FALLTHROUGH;
|
||||
case ' ':
|
||||
specs.sign = c == ' ' ? sign::space : sign::plus;
|
||||
specs.set_sign(c == ' ' ? sign::space : sign::plus);
|
||||
FMT_FALLTHROUGH;
|
||||
case '-':
|
||||
enter_state(state::sign, in(arg_type, sint_set | float_set));
|
||||
@ -2464,17 +2534,17 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
||||
break;
|
||||
case '#':
|
||||
enter_state(state::hash, is_arithmetic_type(arg_type));
|
||||
specs.alt = true;
|
||||
specs.set_alt();
|
||||
++begin;
|
||||
break;
|
||||
case '0':
|
||||
enter_state(state::zero);
|
||||
if (!is_arithmetic_type(arg_type))
|
||||
report_error("format specifier requires numeric argument");
|
||||
if (specs.align == align::none) {
|
||||
if (specs.align() == align::none) {
|
||||
// Ignore 0 if align is specified for compatibility with std::format.
|
||||
specs.align = align::numeric;
|
||||
specs.fill = '0';
|
||||
specs.set_align(align::numeric);
|
||||
specs.set_fill('0');
|
||||
}
|
||||
++begin;
|
||||
break;
|
||||
@ -2498,40 +2568,40 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
||||
break;
|
||||
case 'L':
|
||||
enter_state(state::locale, is_arithmetic_type(arg_type));
|
||||
specs.localized = true;
|
||||
specs.set_localized();
|
||||
++begin;
|
||||
break;
|
||||
case 'd':
|
||||
return parse_presentation_type(pres::dec, integral_set);
|
||||
case 'X':
|
||||
specs.upper = true;
|
||||
specs.set_upper();
|
||||
FMT_FALLTHROUGH;
|
||||
case 'x':
|
||||
return parse_presentation_type(pres::hex, integral_set);
|
||||
case 'o':
|
||||
return parse_presentation_type(pres::oct, integral_set);
|
||||
case 'B':
|
||||
specs.upper = true;
|
||||
specs.set_upper();
|
||||
FMT_FALLTHROUGH;
|
||||
case 'b':
|
||||
return parse_presentation_type(pres::bin, integral_set);
|
||||
case 'E':
|
||||
specs.upper = true;
|
||||
specs.set_upper();
|
||||
FMT_FALLTHROUGH;
|
||||
case 'e':
|
||||
return parse_presentation_type(pres::exp, float_set);
|
||||
case 'F':
|
||||
specs.upper = true;
|
||||
specs.set_upper();
|
||||
FMT_FALLTHROUGH;
|
||||
case 'f':
|
||||
return parse_presentation_type(pres::fixed, float_set);
|
||||
case 'G':
|
||||
specs.upper = true;
|
||||
specs.set_upper();
|
||||
FMT_FALLTHROUGH;
|
||||
case 'g':
|
||||
return parse_presentation_type(pres::general, float_set);
|
||||
case 'A':
|
||||
specs.upper = true;
|
||||
specs.set_upper();
|
||||
FMT_FALLTHROUGH;
|
||||
case 'a':
|
||||
return parse_presentation_type(pres::hexfloat, float_set);
|
||||
@ -2562,9 +2632,9 @@ FMT_CONSTEXPR auto parse_format_specs(const Char* begin, const Char* end,
|
||||
}
|
||||
auto align = parse_align(to_ascii(*fill_end));
|
||||
enter_state(state::align, align != align::none);
|
||||
specs.fill =
|
||||
basic_string_view<Char>(begin, to_unsigned(fill_end - begin));
|
||||
specs.align = align;
|
||||
specs.set_fill(
|
||||
basic_string_view<Char>(begin, to_unsigned(fill_end - begin)));
|
||||
specs.set_align(align);
|
||||
begin = fill_end + 1;
|
||||
}
|
||||
}
|
||||
@ -2706,13 +2776,15 @@ FMT_CONSTEXPR auto parse_format_specs(ParseContext& ctx)
|
||||
|
||||
// Checks char specs and returns true iff the presentation type is char-like.
|
||||
FMT_CONSTEXPR inline auto check_char_specs(const format_specs& specs) -> bool {
|
||||
if (specs.type != presentation_type::none &&
|
||||
specs.type != presentation_type::chr &&
|
||||
specs.type != presentation_type::debug) {
|
||||
auto type = specs.type();
|
||||
if (type != presentation_type::none && type != presentation_type::chr &&
|
||||
type != presentation_type::debug) {
|
||||
return false;
|
||||
}
|
||||
if (specs.align == align::numeric || specs.sign != sign::none || specs.alt)
|
||||
if (specs.align() == align::numeric || specs.sign() != sign::none ||
|
||||
specs.alt()) {
|
||||
report_error("invalid format specifier for char");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -2861,7 +2933,7 @@ template <typename T, typename Char, type TYPE> struct native_formatter {
|
||||
FMT_ENABLE_IF(U == type::string_type || U == type::cstring_type ||
|
||||
U == type::char_type)>
|
||||
FMT_CONSTEXPR void set_debug_format(bool set = true) {
|
||||
specs_.type = set ? presentation_type::debug : presentation_type::none;
|
||||
specs_.set_type(set ? presentation_type::debug : presentation_type::none);
|
||||
}
|
||||
|
||||
template <typename FormatContext>
|
||||
|
@ -1732,8 +1732,8 @@ template <typename Char, typename Rep, typename OutputIt,
|
||||
auto format_duration_value(OutputIt out, Rep val, int precision) -> OutputIt {
|
||||
auto specs = format_specs();
|
||||
specs.precision = precision;
|
||||
specs.type =
|
||||
precision >= 0 ? presentation_type::fixed : presentation_type::general;
|
||||
specs.set_type(precision >= 0 ? presentation_type::fixed
|
||||
: presentation_type::general);
|
||||
return write<Char>(out, val, specs);
|
||||
}
|
||||
|
||||
|
@ -1718,11 +1718,11 @@ constexpr auto convert_float(T value) -> convert_float_result<T> {
|
||||
}
|
||||
|
||||
template <typename Char, typename OutputIt>
|
||||
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n, const fill_t& fill)
|
||||
-> OutputIt {
|
||||
auto fill_size = fill.size();
|
||||
if (fill_size == 1) return detail::fill_n(it, n, fill.template get<Char>());
|
||||
if (const Char* data = fill.template data<Char>()) {
|
||||
FMT_NOINLINE FMT_CONSTEXPR auto fill(OutputIt it, size_t n,
|
||||
const basic_specs& specs) -> OutputIt {
|
||||
auto fill_size = specs.fill_size();
|
||||
if (fill_size == 1) return detail::fill_n(it, n, specs.fill_unit<Char>());
|
||||
if (const Char* data = specs.fill<Char>()) {
|
||||
for (size_t i = 0; i < n; ++i) it = copy<Char>(data, data + fill_size, it);
|
||||
}
|
||||
return it;
|
||||
@ -1741,12 +1741,12 @@ FMT_CONSTEXPR auto write_padded(OutputIt out, const format_specs& specs,
|
||||
// Shifts are encoded as string literals because static constexpr is not
|
||||
// supported in constexpr functions.
|
||||
auto* shifts = align == align::left ? "\x1f\x1f\x00\x01" : "\x00\x1f\x00\x01";
|
||||
size_t left_padding = padding >> shifts[specs.align];
|
||||
size_t left_padding = padding >> shifts[specs.align()];
|
||||
size_t right_padding = padding - left_padding;
|
||||
auto it = reserve(out, size + padding * specs.fill.size());
|
||||
if (left_padding != 0) it = fill<Char>(it, left_padding, specs.fill);
|
||||
auto it = reserve(out, size + padding * specs.fill_size());
|
||||
if (left_padding != 0) it = fill<Char>(it, left_padding, specs);
|
||||
it = f(it);
|
||||
if (right_padding != 0) it = fill<Char>(it, right_padding, specs.fill);
|
||||
if (right_padding != 0) it = fill<Char>(it, right_padding, specs);
|
||||
return base_iterator(out, it);
|
||||
}
|
||||
|
||||
@ -1931,7 +1931,7 @@ auto write_escaped_char(OutputIt out, Char v) -> OutputIt {
|
||||
template <typename Char, typename OutputIt>
|
||||
FMT_CONSTEXPR auto write_char(OutputIt out, Char value,
|
||||
const format_specs& specs) -> OutputIt {
|
||||
bool is_debug = specs.type == presentation_type::debug;
|
||||
bool is_debug = specs.type() == presentation_type::debug;
|
||||
return write_padded<Char>(out, specs, 1, [=](reserve_iterator<OutputIt> it) {
|
||||
if (is_debug) return write_escaped_char(it, value);
|
||||
*it++ = value;
|
||||
@ -1958,7 +1958,7 @@ template <typename Char> struct write_int_data {
|
||||
FMT_CONSTEXPR write_int_data(int num_digits, unsigned prefix,
|
||||
const format_specs& specs)
|
||||
: size((prefix >> 24) + to_unsigned(num_digits)), padding(0) {
|
||||
if (specs.align == align::numeric) {
|
||||
if (specs.align() == align::numeric) {
|
||||
auto width = to_unsigned(specs.width);
|
||||
if (width > size) {
|
||||
padding = width - size;
|
||||
@ -2076,7 +2076,7 @@ auto write_int(OutputIt out, UInt value, unsigned prefix,
|
||||
static_assert(std::is_same<uint64_or_128_t<UInt>, UInt>::value, "");
|
||||
int num_digits = 0;
|
||||
auto buffer = memory_buffer();
|
||||
switch (specs.type) {
|
||||
switch (specs.type()) {
|
||||
default:
|
||||
FMT_ASSERT(false, "");
|
||||
FMT_FALLTHROUGH;
|
||||
@ -2086,22 +2086,22 @@ auto write_int(OutputIt out, UInt value, unsigned prefix,
|
||||
format_decimal<char>(appender(buffer), value, num_digits);
|
||||
break;
|
||||
case presentation_type::hex:
|
||||
if (specs.alt)
|
||||
prefix_append(prefix, unsigned(specs.upper ? 'X' : 'x') << 8 | '0');
|
||||
if (specs.alt())
|
||||
prefix_append(prefix, unsigned(specs.upper() ? 'X' : 'x') << 8 | '0');
|
||||
num_digits = count_digits<4>(value);
|
||||
format_uint<4, char>(appender(buffer), value, num_digits, specs.upper);
|
||||
format_uint<4, char>(appender(buffer), value, num_digits, specs.upper());
|
||||
break;
|
||||
case presentation_type::oct:
|
||||
num_digits = count_digits<3>(value);
|
||||
// Octal prefix '0' is counted as a digit, so only add it if precision
|
||||
// is not greater than the number of digits.
|
||||
if (specs.alt && specs.precision <= num_digits && value != 0)
|
||||
if (specs.alt() && specs.precision <= num_digits && value != 0)
|
||||
prefix_append(prefix, '0');
|
||||
format_uint<3, char>(appender(buffer), value, num_digits);
|
||||
break;
|
||||
case presentation_type::bin:
|
||||
if (specs.alt)
|
||||
prefix_append(prefix, unsigned(specs.upper ? 'B' : 'b') << 8 | '0');
|
||||
if (specs.alt())
|
||||
prefix_append(prefix, unsigned(specs.upper() ? 'B' : 'b') << 8 | '0');
|
||||
num_digits = count_digits<1>(value);
|
||||
format_uint<1, char>(appender(buffer), value, num_digits);
|
||||
break;
|
||||
@ -2158,7 +2158,7 @@ template <typename Char = char> struct loc_writer {
|
||||
|
||||
template <typename T, FMT_ENABLE_IF(is_integer<T>::value)>
|
||||
auto operator()(T value) -> bool {
|
||||
auto arg = make_write_int_arg(value, specs.sign);
|
||||
auto arg = make_write_int_arg(value, specs.sign());
|
||||
write_int(out, static_cast<uint64_or_128_t<T>>(arg.abs_value), arg.prefix,
|
||||
specs, digit_grouping<Char>(grouping, sep));
|
||||
return true;
|
||||
@ -2177,7 +2177,7 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
|
||||
static_assert(std::is_same<T, uint32_or_64_or_128_t<T>>::value, "");
|
||||
auto abs_value = arg.abs_value;
|
||||
auto prefix = arg.prefix;
|
||||
switch (specs.type) {
|
||||
switch (specs.type()) {
|
||||
default:
|
||||
FMT_ASSERT(false, "");
|
||||
FMT_FALLTHROUGH;
|
||||
@ -2190,19 +2190,19 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
|
||||
});
|
||||
}
|
||||
case presentation_type::hex: {
|
||||
if (specs.alt)
|
||||
prefix_append(prefix, unsigned(specs.upper ? 'X' : 'x') << 8 | '0');
|
||||
if (specs.alt())
|
||||
prefix_append(prefix, unsigned(specs.upper() ? 'X' : 'x') << 8 | '0');
|
||||
int num_digits = count_digits<4>(abs_value);
|
||||
return write_int<Char>(
|
||||
out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
|
||||
return format_uint<4, Char>(it, abs_value, num_digits, specs.upper);
|
||||
return format_uint<4, Char>(it, abs_value, num_digits, specs.upper());
|
||||
});
|
||||
}
|
||||
case presentation_type::oct: {
|
||||
int num_digits = count_digits<3>(abs_value);
|
||||
// Octal prefix '0' is counted as a digit, so only add it if precision
|
||||
// is not greater than the number of digits.
|
||||
if (specs.alt && specs.precision <= num_digits && abs_value != 0)
|
||||
if (specs.alt() && specs.precision <= num_digits && abs_value != 0)
|
||||
prefix_append(prefix, '0');
|
||||
return write_int<Char>(
|
||||
out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
|
||||
@ -2210,8 +2210,8 @@ FMT_CONSTEXPR FMT_INLINE auto write_int(OutputIt out, write_int_arg<T> arg,
|
||||
});
|
||||
}
|
||||
case presentation_type::bin: {
|
||||
if (specs.alt)
|
||||
prefix_append(prefix, unsigned(specs.upper ? 'B' : 'b') << 8 | '0');
|
||||
if (specs.alt())
|
||||
prefix_append(prefix, unsigned(specs.upper() ? 'B' : 'b') << 8 | '0');
|
||||
int num_digits = count_digits<1>(abs_value);
|
||||
return write_int<Char>(
|
||||
out, num_digits, prefix, specs, [=](reserve_iterator<OutputIt> it) {
|
||||
@ -2236,8 +2236,8 @@ template <typename Char, typename T,
|
||||
FMT_CONSTEXPR FMT_INLINE auto write(basic_appender<Char> out, T value,
|
||||
const format_specs& specs, locale_ref loc)
|
||||
-> basic_appender<Char> {
|
||||
if (specs.localized && write_loc(out, value, specs, loc)) return out;
|
||||
return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign),
|
||||
if (specs.localized() && write_loc(out, value, specs, loc)) return out;
|
||||
return write_int_noinline<Char>(out, make_write_int_arg(value, specs.sign()),
|
||||
specs, loc);
|
||||
}
|
||||
// An inlined version of write used in format string compilation.
|
||||
@ -2249,8 +2249,8 @@ template <typename Char, typename OutputIt, typename T,
|
||||
FMT_CONSTEXPR FMT_INLINE auto write(OutputIt out, T value,
|
||||
const format_specs& specs, locale_ref loc)
|
||||
-> OutputIt {
|
||||
if (specs.localized && write_loc(out, value, specs, loc)) return out;
|
||||
return write_int<Char>(out, make_write_int_arg(value, specs.sign), specs,
|
||||
if (specs.localized() && write_loc(out, value, specs, loc)) return out;
|
||||
return write_int<Char>(out, make_write_int_arg(value, specs.sign()), specs,
|
||||
loc);
|
||||
}
|
||||
|
||||
@ -2261,7 +2261,7 @@ FMT_CONSTEXPR auto write(OutputIt out, basic_string_view<Char> s,
|
||||
auto size = s.size();
|
||||
if (specs.precision >= 0 && to_unsigned(specs.precision) < size)
|
||||
size = code_point_index(s, to_unsigned(specs.precision));
|
||||
bool is_debug = specs.type == presentation_type::debug;
|
||||
bool is_debug = specs.type() == presentation_type::debug;
|
||||
size_t width = 0;
|
||||
|
||||
if (is_debug) {
|
||||
@ -2291,7 +2291,7 @@ FMT_CONSTEXPR auto write(OutputIt out,
|
||||
template <typename Char, typename OutputIt>
|
||||
FMT_CONSTEXPR auto write(OutputIt out, const Char* s, const format_specs& specs,
|
||||
locale_ref) -> OutputIt {
|
||||
if (specs.type == presentation_type::pointer)
|
||||
if (specs.type() == presentation_type::pointer)
|
||||
return write_ptr<Char>(out, bit_cast<uintptr_t>(s), &specs);
|
||||
if (!s) report_error("string pointer is null");
|
||||
return write<Char>(out, basic_string_view<Char>(s), specs, {});
|
||||
@ -2344,7 +2344,7 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
|
||||
report_error("invalid fill character '{'");
|
||||
return begin;
|
||||
}
|
||||
specs.fill = basic_string_view<Char>(begin, to_unsigned(p - begin));
|
||||
specs.set_fill(basic_string_view<Char>(begin, to_unsigned(p - begin)));
|
||||
begin = p + 1;
|
||||
} else {
|
||||
++begin;
|
||||
@ -2355,7 +2355,7 @@ FMT_CONSTEXPR auto parse_align(const Char* begin, const Char* end,
|
||||
}
|
||||
p = begin;
|
||||
}
|
||||
specs.align = align;
|
||||
specs.set_align(align);
|
||||
return begin;
|
||||
}
|
||||
|
||||
@ -2364,13 +2364,13 @@ FMT_CONSTEXPR20 auto write_nonfinite(OutputIt out, bool isnan,
|
||||
format_specs specs, sign_t sign)
|
||||
-> OutputIt {
|
||||
auto str =
|
||||
isnan ? (specs.upper ? "NAN" : "nan") : (specs.upper ? "INF" : "inf");
|
||||
isnan ? (specs.upper() ? "NAN" : "nan") : (specs.upper() ? "INF" : "inf");
|
||||
constexpr size_t str_size = 3;
|
||||
auto size = str_size + (sign ? 1 : 0);
|
||||
// Replace '0'-padding with space for non-finite values.
|
||||
const bool is_zero_fill =
|
||||
specs.fill.size() == 1 && specs.fill.template get<Char>() == '0';
|
||||
if (is_zero_fill) specs.fill = ' ';
|
||||
specs.fill_size() == 1 && specs.fill_unit<Char>() == '0';
|
||||
if (is_zero_fill) specs.set_fill(' ');
|
||||
return write_padded<Char>(out, specs, size,
|
||||
[=](reserve_iterator<OutputIt> it) {
|
||||
if (sign) *it++ = detail::sign<Char>(sign);
|
||||
@ -2492,13 +2492,13 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
||||
size_t size = to_unsigned(significand_size) + (sign ? 1 : 0);
|
||||
using iterator = reserve_iterator<OutputIt>;
|
||||
|
||||
Char decimal_point = specs.localized ? detail::decimal_point<Char>(loc)
|
||||
: static_cast<Char>('.');
|
||||
Char decimal_point = specs.localized() ? detail::decimal_point<Char>(loc)
|
||||
: static_cast<Char>('.');
|
||||
|
||||
int output_exp = f.exponent + significand_size - 1;
|
||||
auto use_exp_format = [=]() {
|
||||
if (specs.type == presentation_type::exp) return true;
|
||||
if (specs.type == presentation_type::fixed) return false;
|
||||
if (specs.type() == presentation_type::exp) return true;
|
||||
if (specs.type() == presentation_type::fixed) return false;
|
||||
// Use the fixed notation if the exponent is in [exp_lower, exp_upper),
|
||||
// e.g. 0.0001 instead of 1e-04. Otherwise use the exponent notation.
|
||||
const int exp_lower = -4, exp_upper = 16;
|
||||
@ -2507,7 +2507,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
||||
};
|
||||
if (use_exp_format()) {
|
||||
int num_zeros = 0;
|
||||
if (specs.alt) {
|
||||
if (specs.alt()) {
|
||||
num_zeros = specs.precision - significand_size;
|
||||
if (num_zeros < 0) num_zeros = 0;
|
||||
size += to_unsigned(num_zeros);
|
||||
@ -2519,7 +2519,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
||||
if (abs_output_exp >= 100) exp_digits = abs_output_exp >= 1000 ? 4 : 3;
|
||||
|
||||
size += to_unsigned((decimal_point ? 1 : 0) + 2 + exp_digits);
|
||||
char exp_char = specs.upper ? 'E' : 'e';
|
||||
char exp_char = specs.upper() ? 'E' : 'e';
|
||||
auto write = [=](iterator it) {
|
||||
if (sign) *it++ = detail::sign<Char>(sign);
|
||||
// Insert a decimal point after the first digit and add an exponent.
|
||||
@ -2540,27 +2540,27 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
||||
size += to_unsigned(f.exponent);
|
||||
int num_zeros = specs.precision - exp;
|
||||
abort_fuzzing_if(num_zeros > 5000);
|
||||
if (specs.alt) {
|
||||
if (specs.alt()) {
|
||||
++size;
|
||||
if (num_zeros <= 0 && specs.type != presentation_type::fixed)
|
||||
if (num_zeros <= 0 && specs.type() != presentation_type::fixed)
|
||||
num_zeros = 0;
|
||||
if (num_zeros > 0) size += to_unsigned(num_zeros);
|
||||
}
|
||||
auto grouping = Grouping(loc, specs.localized);
|
||||
auto grouping = Grouping(loc, specs.localized());
|
||||
size += to_unsigned(grouping.count_separators(exp));
|
||||
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
||||
if (sign) *it++ = detail::sign<Char>(sign);
|
||||
it = write_significand<Char>(it, significand, significand_size,
|
||||
f.exponent, grouping);
|
||||
if (!specs.alt) return it;
|
||||
if (!specs.alt()) return it;
|
||||
*it++ = decimal_point;
|
||||
return num_zeros > 0 ? detail::fill_n(it, num_zeros, zero) : it;
|
||||
});
|
||||
} else if (exp > 0) {
|
||||
// 1234e-2 -> 12.34[0+]
|
||||
int num_zeros = specs.alt ? specs.precision - significand_size : 0;
|
||||
int num_zeros = specs.alt() ? specs.precision - significand_size : 0;
|
||||
size += 1 + to_unsigned(num_zeros > 0 ? num_zeros : 0);
|
||||
auto grouping = Grouping(loc, specs.localized);
|
||||
auto grouping = Grouping(loc, specs.localized());
|
||||
size += to_unsigned(grouping.count_separators(exp));
|
||||
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
||||
if (sign) *it++ = detail::sign<Char>(sign);
|
||||
@ -2575,7 +2575,7 @@ FMT_CONSTEXPR20 auto do_write_float(OutputIt out, const DecimalFP& f,
|
||||
specs.precision < num_zeros) {
|
||||
num_zeros = specs.precision;
|
||||
}
|
||||
bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt;
|
||||
bool pointy = num_zeros != 0 || significand_size != 0 || specs.alt();
|
||||
size += 1 + (pointy ? 1 : 0) + to_unsigned(num_zeros);
|
||||
return write_padded<Char, align::right>(out, specs, size, [&](iterator it) {
|
||||
if (sign) *it++ = detail::sign<Char>(sign);
|
||||
@ -3116,20 +3116,20 @@ FMT_CONSTEXPR20 void format_hexfloat(Float value, format_specs specs,
|
||||
|
||||
char xdigits[num_bits<carrier_uint>() / 4];
|
||||
detail::fill_n(xdigits, sizeof(xdigits), '0');
|
||||
format_uint<4>(xdigits, f.f, num_xdigits, specs.upper);
|
||||
format_uint<4>(xdigits, f.f, num_xdigits, specs.upper());
|
||||
|
||||
// Remove zero tail
|
||||
while (print_xdigits > 0 && xdigits[print_xdigits] == '0') --print_xdigits;
|
||||
|
||||
buf.push_back('0');
|
||||
buf.push_back(specs.upper ? 'X' : 'x');
|
||||
buf.push_back(specs.upper() ? 'X' : 'x');
|
||||
buf.push_back(xdigits[0]);
|
||||
if (specs.alt || print_xdigits > 0 || print_xdigits < specs.precision)
|
||||
if (specs.alt() || print_xdigits > 0 || print_xdigits < specs.precision)
|
||||
buf.push_back('.');
|
||||
buf.append(xdigits + 1, xdigits + 1 + print_xdigits);
|
||||
for (; print_xdigits < specs.precision; ++print_xdigits) buf.push_back('0');
|
||||
|
||||
buf.push_back(specs.upper ? 'P' : 'p');
|
||||
buf.push_back(specs.upper() ? 'P' : 'p');
|
||||
|
||||
uint32_t abs_e;
|
||||
if (f.e < 0) {
|
||||
@ -3167,7 +3167,7 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision,
|
||||
static_assert(!std::is_same<Float, float>::value, "");
|
||||
auto converted_value = convert_float(value);
|
||||
|
||||
const bool fixed = specs.type == presentation_type::fixed;
|
||||
const bool fixed = specs.type() == presentation_type::fixed;
|
||||
if (value == 0) {
|
||||
if (precision <= 0 || !fixed) {
|
||||
buf.push_back('0');
|
||||
@ -3446,7 +3446,7 @@ FMT_CONSTEXPR20 auto format_float(Float value, int precision,
|
||||
if (precision > max_double_digits) precision = max_double_digits;
|
||||
format_dragon(f, dragon_flags, precision, buf, exp);
|
||||
}
|
||||
if (!fixed && !specs.alt) {
|
||||
if (!fixed && !specs.alt()) {
|
||||
// Remove trailing zeros.
|
||||
auto num_digits = buf.size();
|
||||
while (num_digits > 0 && buf[num_digits - 1] == '0') {
|
||||
@ -3462,12 +3462,12 @@ template <typename Char, typename OutputIt, typename T>
|
||||
FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
||||
locale_ref loc) -> OutputIt {
|
||||
// Use signbit because value < 0 is false for NaN.
|
||||
sign_t sign = detail::signbit(value) ? sign::minus : specs.sign;
|
||||
sign_t sign = detail::signbit(value) ? sign::minus : specs.sign();
|
||||
|
||||
if (!detail::isfinite(value))
|
||||
return write_nonfinite<Char>(out, detail::isnan(value), specs, sign);
|
||||
|
||||
if (specs.align == align::numeric && sign) {
|
||||
if (specs.align() == align::numeric && sign) {
|
||||
*out++ = detail::sign<Char>(sign);
|
||||
sign = sign::none;
|
||||
if (specs.width != 0) --specs.width;
|
||||
@ -3475,7 +3475,7 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
||||
|
||||
int precision = specs.precision;
|
||||
if (precision < 0) {
|
||||
if (specs.type != presentation_type::none) {
|
||||
if (specs.type() != presentation_type::none) {
|
||||
precision = 6;
|
||||
} else if (is_fast_float<T>::value && !is_constant_evaluated()) {
|
||||
// Use Dragonbox for the shortest format.
|
||||
@ -3486,21 +3486,21 @@ FMT_CONSTEXPR20 auto write_float(OutputIt out, T value, format_specs specs,
|
||||
}
|
||||
|
||||
memory_buffer buffer;
|
||||
if (specs.type == presentation_type::hexfloat) {
|
||||
if (specs.type() == presentation_type::hexfloat) {
|
||||
if (sign) buffer.push_back(detail::sign<char>(sign));
|
||||
format_hexfloat(convert_float(value), specs, buffer);
|
||||
return write_bytes<Char, align::right>(out, {buffer.data(), buffer.size()},
|
||||
specs);
|
||||
}
|
||||
|
||||
if (specs.type == presentation_type::exp) {
|
||||
if (specs.type() == presentation_type::exp) {
|
||||
if (precision == max_value<int>())
|
||||
report_error("number is too big");
|
||||
else
|
||||
++precision;
|
||||
specs.alt |= specs.precision != 0;
|
||||
} else if (specs.type == presentation_type::fixed) {
|
||||
specs.alt |= specs.precision != 0;
|
||||
if (specs.precision != 0) specs.set_alt();
|
||||
} else if (specs.type() == presentation_type::fixed) {
|
||||
if (specs.precision != 0) specs.set_alt();
|
||||
} else if (precision == 0) {
|
||||
precision = 1;
|
||||
}
|
||||
@ -3517,7 +3517,7 @@ template <typename Char, typename OutputIt, typename T,
|
||||
FMT_CONSTEXPR20 auto write(OutputIt out, T value, format_specs specs,
|
||||
locale_ref loc = {}) -> OutputIt {
|
||||
if (const_check(!is_supported_floating_point(value))) return out;
|
||||
return specs.localized && write_loc(out, value, specs, loc)
|
||||
return specs.localized() && write_loc(out, value, specs, loc)
|
||||
? out
|
||||
: write_float<Char>(out, value, specs, loc);
|
||||
}
|
||||
@ -3583,8 +3583,8 @@ template <typename Char, typename OutputIt, typename T,
|
||||
FMT_ENABLE_IF(std::is_same<T, bool>::value)>
|
||||
FMT_CONSTEXPR auto write(OutputIt out, T value, const format_specs& specs = {},
|
||||
locale_ref = {}) -> OutputIt {
|
||||
return specs.type != presentation_type::none &&
|
||||
specs.type != presentation_type::string
|
||||
return specs.type() != presentation_type::none &&
|
||||
specs.type() != presentation_type::string
|
||||
? write<Char>(out, value ? 1 : 0, specs, {})
|
||||
: write_bytes<Char>(out, value ? "true" : "false", specs);
|
||||
}
|
||||
@ -4012,7 +4012,7 @@ template <typename T> struct formatter<group_digits_view<T>> : formatter<T> {
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||
specs.precision_ref, ctx);
|
||||
auto arg = detail::make_write_int_arg(t.value, specs.sign);
|
||||
auto arg = detail::make_write_int_arg(t.value, specs.sign());
|
||||
return detail::write_int(
|
||||
ctx.out(), static_cast<detail::uint64_or_128_t<T>>(arg.abs_value),
|
||||
arg.prefix, specs, detail::digit_grouping<char>("\3", ","));
|
||||
@ -4039,13 +4039,12 @@ struct formatter<nested_view<T, Char>, Char> {
|
||||
|
||||
template <typename T, typename Char = char> struct nested_formatter {
|
||||
private:
|
||||
basic_specs specs_;
|
||||
int width_;
|
||||
detail::fill_t fill_;
|
||||
align_t align_ : 4;
|
||||
formatter<T, Char> formatter_;
|
||||
|
||||
public:
|
||||
constexpr nested_formatter() : width_(0), align_(align_t::none) {}
|
||||
constexpr nested_formatter() : width_(0) {}
|
||||
|
||||
FMT_CONSTEXPR auto parse(basic_format_parse_context<Char>& ctx)
|
||||
-> decltype(ctx.begin()) {
|
||||
@ -4053,8 +4052,7 @@ template <typename T, typename Char = char> struct nested_formatter {
|
||||
if (it == end) return it;
|
||||
auto specs = format_specs();
|
||||
it = detail::parse_align(it, end, specs);
|
||||
fill_ = specs.fill;
|
||||
align_ = specs.align;
|
||||
specs_ = specs;
|
||||
Char c = *it;
|
||||
auto width_ref = detail::arg_ref<Char>();
|
||||
if ((c >= '0' && c <= '9') || c == '{') {
|
||||
@ -4072,8 +4070,9 @@ template <typename T, typename Char = char> struct nested_formatter {
|
||||
write(basic_appender<Char>(buf));
|
||||
auto specs = format_specs();
|
||||
specs.width = width_;
|
||||
specs.fill = fill_;
|
||||
specs.align = align_;
|
||||
specs.set_fill(
|
||||
basic_string_view<Char>(specs_.fill<Char>(), specs_.fill_size()));
|
||||
specs.set_align(specs_.align());
|
||||
return detail::write<Char>(
|
||||
ctx.out(), basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
}
|
||||
@ -4159,7 +4158,7 @@ template <typename Char> struct format_handler {
|
||||
|
||||
auto specs = dynamic_format_specs<Char>();
|
||||
begin = parse_format_specs(begin, end, specs, parse_context, arg.type());
|
||||
if (specs.dynamic != 0) {
|
||||
if (specs.dynamic()) {
|
||||
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs.width_ref,
|
||||
context);
|
||||
handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||
@ -4206,7 +4205,7 @@ template <typename T, typename Char, type TYPE>
|
||||
template <typename FormatContext>
|
||||
FMT_CONSTEXPR FMT_INLINE auto native_formatter<T, Char, TYPE>::format(
|
||||
const T& val, FormatContext& ctx) const -> decltype(ctx.out()) {
|
||||
if (specs_.dynamic == 0)
|
||||
if (!specs_.dynamic())
|
||||
return write<Char>(ctx.out(), val, specs_, ctx.locale());
|
||||
auto specs = format_specs(specs_);
|
||||
handle_dynamic_spec(specs.dynamic_width(), specs.width, specs_.width_ref,
|
||||
|
@ -200,7 +200,7 @@ class printf_width_handler {
|
||||
auto operator()(T value) -> unsigned {
|
||||
auto width = static_cast<uint32_or_64_or_128_t<T>>(value);
|
||||
if (detail::is_negative(value)) {
|
||||
specs_.align = align::left;
|
||||
specs_.set_align(align::left);
|
||||
width = 0 - width;
|
||||
}
|
||||
unsigned int_max = to_unsigned(max_value<int>());
|
||||
@ -234,7 +234,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
|
||||
void write_null_pointer(bool is_string = false) {
|
||||
auto s = this->specs;
|
||||
s.type = presentation_type::none;
|
||||
s.set_type(presentation_type::none);
|
||||
write_bytes<Char>(this->out, is_string ? "(null)" : "(nil)", s);
|
||||
}
|
||||
|
||||
@ -254,16 +254,17 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
return;
|
||||
}
|
||||
format_specs s = this->specs;
|
||||
if (s.type != presentation_type::none && s.type != presentation_type::chr) {
|
||||
if (s.type() != presentation_type::none &&
|
||||
s.type() != presentation_type::chr) {
|
||||
return (*this)(static_cast<int>(value));
|
||||
}
|
||||
s.sign = sign::none;
|
||||
s.alt = false;
|
||||
s.fill = ' '; // Ignore '0' flag for char types.
|
||||
s.set_sign(sign::none);
|
||||
s.clear_alt();
|
||||
s.set_fill(' '); // Ignore '0' flag for char types.
|
||||
// align::numeric needs to be overwritten here since the '0' flag is
|
||||
// ignored for non-numeric types
|
||||
if (s.align == align::none || s.align == align::numeric)
|
||||
s.align = align::right;
|
||||
if (s.align() == align::none || s.align() == align::numeric)
|
||||
s.set_align(align::right);
|
||||
write<Char>(this->out, static_cast<Char>(value), s);
|
||||
}
|
||||
|
||||
@ -276,14 +277,14 @@ class printf_arg_formatter : public arg_formatter<Char> {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else
|
||||
write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
write_null_pointer(this->specs.type() != presentation_type::pointer);
|
||||
}
|
||||
|
||||
void operator()(const wchar_t* value) {
|
||||
if (value)
|
||||
base::operator()(value);
|
||||
else
|
||||
write_null_pointer(this->specs.type != presentation_type::pointer);
|
||||
write_null_pointer(this->specs.type() != presentation_type::pointer);
|
||||
}
|
||||
|
||||
void operator()(basic_string_view<Char> value) { base::operator()(value); }
|
||||
@ -306,19 +307,19 @@ void parse_flags(format_specs& specs, const Char*& it, const Char* end) {
|
||||
for (; it != end; ++it) {
|
||||
switch (*it) {
|
||||
case '-':
|
||||
specs.align = align::left;
|
||||
specs.set_align(align::left);
|
||||
break;
|
||||
case '+':
|
||||
specs.sign = sign::plus;
|
||||
specs.set_sign(sign::plus);
|
||||
break;
|
||||
case '0':
|
||||
specs.fill = '0';
|
||||
specs.set_fill('0');
|
||||
break;
|
||||
case ' ':
|
||||
if (specs.sign != sign::plus) specs.sign = sign::space;
|
||||
if (specs.sign() != sign::plus) specs.set_sign(sign::space);
|
||||
break;
|
||||
case '#':
|
||||
specs.alt = true;
|
||||
specs.set_alt();
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
@ -339,7 +340,7 @@ auto parse_header(const Char*& it, const Char* end, format_specs& specs,
|
||||
++it;
|
||||
arg_index = value != -1 ? value : max_value<int>();
|
||||
} else {
|
||||
if (c == '0') specs.fill = '0';
|
||||
if (c == '0') specs.set_fill('0');
|
||||
if (value != 0) {
|
||||
// Nonzero value means that we parsed width and don't need to
|
||||
// parse it or flags again, so return now.
|
||||
@ -444,7 +445,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
write(out, basic_string_view<Char>(start, to_unsigned(it - 1 - start)));
|
||||
|
||||
auto specs = format_specs();
|
||||
specs.align = align::right;
|
||||
specs.set_align(align::right);
|
||||
|
||||
// Parse argument index, flags and width.
|
||||
int arg_index = parse_header(it, end, specs, get_arg);
|
||||
@ -470,7 +471,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
// specified, the '0' flag is ignored
|
||||
if (specs.precision >= 0 && arg.is_integral()) {
|
||||
// Ignore '0' for non-numeric types or if '-' present.
|
||||
specs.fill = ' ';
|
||||
specs.set_fill(' ');
|
||||
}
|
||||
if (specs.precision >= 0 && arg.type() == type::cstring_type) {
|
||||
auto str = arg.visit(get_cstring<Char>());
|
||||
@ -480,13 +481,14 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
str, to_unsigned(nul != str_end ? nul - str : specs.precision));
|
||||
arg = make_arg<basic_printf_context<Char>>(sv);
|
||||
}
|
||||
if (specs.alt && arg.visit(is_zero_int())) specs.alt = false;
|
||||
if (specs.fill.template get<Char>() == '0') {
|
||||
if (arg.is_arithmetic() && specs.align != align::left)
|
||||
specs.align = align::numeric;
|
||||
else
|
||||
specs.fill = ' '; // Ignore '0' flag for non-numeric types or if '-'
|
||||
// flag is also present.
|
||||
if (specs.alt() && arg.visit(is_zero_int())) specs.clear_alt();
|
||||
if (specs.fill_unit<Char>() == '0') {
|
||||
if (arg.is_arithmetic() && specs.align() != align::left) {
|
||||
specs.set_align(align::numeric);
|
||||
} else {
|
||||
// Ignore '0' flag for non-numeric types or if '-' flag is also present.
|
||||
specs.set_fill(' ');
|
||||
}
|
||||
}
|
||||
|
||||
// Parse length and convert the argument to the required type.
|
||||
@ -545,10 +547,10 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
|
||||
}
|
||||
}
|
||||
bool upper = false;
|
||||
specs.type = parse_printf_presentation_type(type, arg.type(), upper);
|
||||
if (specs.type == presentation_type::none)
|
||||
specs.set_type(parse_printf_presentation_type(type, arg.type(), upper));
|
||||
if (specs.type() == presentation_type::none)
|
||||
report_error("invalid format specifier");
|
||||
specs.upper = upper;
|
||||
if (upper) specs.set_upper();
|
||||
|
||||
start = it;
|
||||
|
||||
|
@ -422,7 +422,7 @@ struct range_formatter<
|
||||
auto buf = basic_memory_buffer<Char>();
|
||||
for (; it != end; ++it) buf.push_back(*it);
|
||||
auto specs = format_specs();
|
||||
specs.type = presentation_type::debug;
|
||||
specs.set_type(presentation_type::debug);
|
||||
return detail::write<Char>(
|
||||
out, basic_string_view<Char>(buf.data(), buf.size()), specs);
|
||||
}
|
||||
|
@ -645,7 +645,7 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
if (c.real() != 0) {
|
||||
*out++ = Char('(');
|
||||
out = detail::write<Char>(out, c.real(), specs, ctx.locale());
|
||||
specs.sign = sign::plus;
|
||||
specs.set_sign(sign::plus);
|
||||
out = detail::write<Char>(out, c.imag(), specs, ctx.locale());
|
||||
if (!detail::isfinite(c.imag())) *out++ = Char(' ');
|
||||
*out++ = Char('i');
|
||||
@ -670,7 +670,7 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
auto format(const std::complex<T>& c, FormatContext& ctx) const
|
||||
-> decltype(ctx.out()) {
|
||||
auto specs = specs_;
|
||||
if (specs.dynamic != 0) {
|
||||
if (specs.dynamic()) {
|
||||
detail::handle_dynamic_spec(specs.dynamic_width(), specs.width,
|
||||
specs.width_ref, ctx);
|
||||
detail::handle_dynamic_spec(specs.dynamic_precision(), specs.precision,
|
||||
@ -682,12 +682,14 @@ template <typename T, typename Char> struct formatter<std::complex<T>, Char> {
|
||||
|
||||
auto outer_specs = format_specs();
|
||||
outer_specs.width = specs.width;
|
||||
outer_specs.fill = specs.fill;
|
||||
outer_specs.align = specs.align;
|
||||
auto fill = specs.template fill<Char>();
|
||||
if (fill)
|
||||
outer_specs.set_fill(basic_string_view<Char>(fill, specs.fill_size()));
|
||||
outer_specs.set_align(specs.align());
|
||||
|
||||
specs.width = 0;
|
||||
specs.fill = {};
|
||||
specs.align = align::none;
|
||||
specs.set_fill({});
|
||||
specs.set_align(align::none);
|
||||
|
||||
do_format(c, specs, ctx, basic_appender<Char>(buf));
|
||||
return detail::write<Char>(ctx.out(),
|
||||
|
@ -516,19 +516,19 @@ template <size_t N> constexpr auto parse_test_specs(const char (&s)[N]) {
|
||||
}
|
||||
|
||||
TEST(base_test, constexpr_parse_format_specs) {
|
||||
static_assert(parse_test_specs("<").align == fmt::align::left, "");
|
||||
static_assert(parse_test_specs("*^").fill.get<char>() == '*', "");
|
||||
static_assert(parse_test_specs("+").sign == fmt::sign::plus, "");
|
||||
static_assert(parse_test_specs("-").sign == fmt::sign::none, "");
|
||||
static_assert(parse_test_specs(" ").sign == fmt::sign::space, "");
|
||||
static_assert(parse_test_specs("#").alt, "");
|
||||
static_assert(parse_test_specs("0").align == fmt::align::numeric, "");
|
||||
static_assert(parse_test_specs("L").localized, "");
|
||||
static_assert(parse_test_specs("<").align() == fmt::align::left, "");
|
||||
static_assert(parse_test_specs("*^").fill_unit<char>() == '*', "");
|
||||
static_assert(parse_test_specs("+").sign() == fmt::sign::plus, "");
|
||||
static_assert(parse_test_specs("-").sign() == fmt::sign::none, "");
|
||||
static_assert(parse_test_specs(" ").sign() == fmt::sign::space, "");
|
||||
static_assert(parse_test_specs("#").alt(), "");
|
||||
static_assert(parse_test_specs("0").align() == fmt::align::numeric, "");
|
||||
static_assert(parse_test_specs("L").localized(), "");
|
||||
static_assert(parse_test_specs("42").width == 42, "");
|
||||
static_assert(parse_test_specs("{42}").width_ref.index == 42, "");
|
||||
static_assert(parse_test_specs(".42").precision == 42, "");
|
||||
static_assert(parse_test_specs(".{42}").precision_ref.index == 42, "");
|
||||
static_assert(parse_test_specs("f").type == fmt::presentation_type::fixed,
|
||||
static_assert(parse_test_specs("f").type() == fmt::presentation_type::fixed,
|
||||
"");
|
||||
}
|
||||
|
||||
|
@ -368,7 +368,7 @@ const char* parse_scan_specs(const char* begin, const char* end,
|
||||
switch (to_ascii(*begin)) {
|
||||
// TODO: parse more scan format specifiers
|
||||
case 'x':
|
||||
specs.type = presentation_type::hex;
|
||||
specs.set_type(presentation_type::hex);
|
||||
++begin;
|
||||
break;
|
||||
case '}':
|
||||
@ -437,7 +437,7 @@ auto read_hex(scan_iterator it, T& value) -> scan_iterator {
|
||||
template <typename T, FMT_ENABLE_IF(std::is_unsigned<T>::value)>
|
||||
auto read(scan_iterator it, T& value, const format_specs& specs)
|
||||
-> scan_iterator {
|
||||
if (specs.type == presentation_type::hex) return read_hex(it, value);
|
||||
if (specs.type() == presentation_type::hex) return read_hex(it, value);
|
||||
return read(it, value);
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user