Adds a factory function for arg_formatter w/ default locale_ref

Use this within printf_arg_formatter constructor as workaround
for XL compiler bug that optimizes away base class initializer.

Also: Reverts conversion of internal `specs` variable back to a const ref

Per PR suggestion.
This commit is contained in:
Kenneth Weiss 2023-01-10 18:17:19 -08:00
parent e4645d2867
commit 4097a242a9
2 changed files with 15 additions and 16 deletions

View File

@ -3580,18 +3580,23 @@ template <typename Char> struct arg_formatter {
using context = buffer_context<Char>; using context = buffer_context<Char>;
iterator out; iterator out;
const format_specs<Char>* specs; const format_specs<Char>& specs;
locale_ref locale; locale_ref locale;
template <typename T> template <typename T>
FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator { FMT_CONSTEXPR FMT_INLINE auto operator()(T value) -> iterator {
return detail::write(out, value, *specs, locale); return detail::write(out, value, specs, locale);
} }
auto operator()(typename basic_format_arg<context>::handle) -> iterator { auto operator()(typename basic_format_arg<context>::handle) -> iterator {
// User-defined types are handled separately because they require access // User-defined types are handled separately because they require access
// to the parse context. // to the parse context.
return out; return out;
} }
static auto make_arg_formatter(iterator iter, format_specs<Char>& s)
-> arg_formatter {
return {iter, s, locale_ref()};
}
}; };
template <typename Char> struct custom_formatter { template <typename Char> struct custom_formatter {
@ -4213,7 +4218,7 @@ void vformat_to(buffer<Char>& buf, basic_string_view<Char> fmt,
specs.precision, specs.precision_ref, context); specs.precision, specs.precision_ref, context);
if (begin == end || *begin != '}') if (begin == end || *begin != '}')
on_error("missing '}' in format string"); on_error("missing '}' in format string");
auto f = arg_formatter<Char>{context.out(), &specs, context.locale()}; auto f = arg_formatter<Char>{context.out(), specs, context.locale()};
context.advance_to(visit_format_arg(f, arg)); context.advance_to(visit_format_arg(f, arg));
return begin; return begin;
} }

View File

@ -228,20 +228,14 @@ class printf_arg_formatter : public arg_formatter<Char> {
context_type& context_; context_type& context_;
OutputIt write_null_pointer(bool is_string = false) { OutputIt write_null_pointer(bool is_string = false) {
auto s = *this->specs; auto s = this->specs;
s.type = presentation_type::none; s.type = presentation_type::none;
return write_bytes(this->out, is_string ? "(null)" : "(nil)", s); return write_bytes(this->out, is_string ? "(null)" : "(nil)", s);
} }
public: public:
printf_arg_formatter(OutputIt iter, format_specs<Char>* s, context_type& ctx) printf_arg_formatter(OutputIt iter, format_specs<Char>& s, context_type& ctx)
: base{iter, s, locale_ref()}, context_(ctx) { : base(base::make_arg_formatter(iter, s)), context_(ctx) {}
#if defined(__ibmxl__)
// Bugfix: XL compiler optimizes out initializer for base
this->out = iter;
this->specs = s;
#endif
}
OutputIt operator()(monostate value) { return base::operator()(value); } OutputIt operator()(monostate value) { return base::operator()(value); }
@ -250,7 +244,7 @@ class printf_arg_formatter : public arg_formatter<Char> {
// MSVC2013 fails to compile separate overloads for bool and Char so use // MSVC2013 fails to compile separate overloads for bool and Char so use
// std::is_same instead. // std::is_same instead.
if (std::is_same<T, Char>::value) { if (std::is_same<T, Char>::value) {
format_specs<Char> fmt_specs = *this->specs; format_specs<Char> fmt_specs = this->specs;
if (fmt_specs.type != presentation_type::none && if (fmt_specs.type != presentation_type::none &&
fmt_specs.type != presentation_type::chr) { fmt_specs.type != presentation_type::chr) {
return (*this)(static_cast<int>(value)); return (*this)(static_cast<int>(value));
@ -275,13 +269,13 @@ class printf_arg_formatter : public arg_formatter<Char> {
/** Formats a null-terminated C string. */ /** Formats a null-terminated C string. */
OutputIt operator()(const char* value) { OutputIt operator()(const char* value) {
if (value) return base::operator()(value); if (value) return base::operator()(value);
return write_null_pointer(this->specs->type != presentation_type::pointer); return write_null_pointer(this->specs.type != presentation_type::pointer);
} }
/** Formats a null-terminated wide C string. */ /** Formats a null-terminated wide C string. */
OutputIt operator()(const wchar_t* value) { OutputIt operator()(const wchar_t* value) {
if (value) return base::operator()(value); if (value) return base::operator()(value);
return write_null_pointer(this->specs->type != presentation_type::pointer); return write_null_pointer(this->specs.type != presentation_type::pointer);
} }
OutputIt operator()(basic_string_view<Char> value) { OutputIt operator()(basic_string_view<Char> value) {
@ -551,7 +545,7 @@ void vprintf(buffer<Char>& buf, basic_string_view<Char> format,
// Format argument. // Format argument.
out = visit_format_arg( out = visit_format_arg(
printf_arg_formatter<iterator, Char>(out, &specs, context), arg); printf_arg_formatter<iterator, Char>(out, specs, context), arg);
} }
write(out, basic_string_view<Char>(start, to_unsigned(it - start))); write(out, basic_string_view<Char>(start, to_unsigned(it - start)));
} }