Skip to content

Optimize P3142R0 Printing Blank Lines With println() #4630

@StephanTLavavej

Description

@StephanTLavavej

For followup after #4611 implementing #4524 is merged.

This PR is implementing the Standard's "Effects equivalent to" wording which is simple and unquestionably correct.

However, blank-line println() is likely to be a popular function to call, and it appears that it goes through a general codepath that does a lot of work:

STL/stl/inc/print

Lines 97 to 117 in 0515a05

template <class... _Types>
void _Print_impl(
const _Add_newline _Add_nl, FILE* const _Stream, const format_string<_Types...> _Fmt, _Types&&... _Args) {
constexpr bool _Has_format_args = sizeof...(_Types) > 0;
if constexpr (_Has_format_args) {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Vprint_unicode_impl(_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_Args...));
} else {
_STD _Vprint_nonunicode_impl(_Add_nl, _Stream, _Fmt.get(), _STD make_format_args(_Args...));
}
} else {
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Print_noformat_unicode(_Stream, _Unescaped_str);
} else {
_STD _Print_noformat_nonunicode(_Stream, _Unescaped_str);
}
}
}

The optimizer is unlikely to see all the way through this.

From a brief glance, it appears that we could provide the newline as a string_view, bypassing the construction of a string _Unescaped_str:

STL/stl/inc/print

Lines 111 to 115 in 0515a05

if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Print_noformat_unicode(_Stream, _Unescaped_str);
} else {
_STD _Print_noformat_nonunicode(_Stream, _Unescaped_str);
}

However, it is unclear to me whether we could further optimize this (without spending tons of complicated code). In particular, because we know that "\n" doesn't contain any exotic characters, could we simply call _Print_noformat_nonunicode?

For <ostream>, I believe that less thought is necessary:

STL/stl/inc/ostream

Lines 1246 to 1263 in 0515a05

template <class... _Types>
void _Print_impl(const _Add_newline _Add_nl, ostream& _Ostr, const format_string<_Types...> _Fmt, _Types&&... _Args) {
constexpr bool _Has_format_args = sizeof...(_Types) > 0;
// This is intentionally kept outside of the try/catch block in _Print_noformat_*()
// (see N4950 [ostream.formatted.print]/3.2).
if constexpr (_Has_format_args) {
if constexpr (_STD _Is_ordinary_literal_encoding_utf8()) {
_STD _Vprint_unicode_impl(_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
} else {
_STD _Vprint_nonunicode_impl(_Add_nl, _Ostr, _Fmt.get(), _STD make_format_args(_Args...));
}
} else {
const string _Unescaped_str{_Unescape_braces(_Add_nl, _Fmt.get())};
_STD _Print_noformat(_Ostr, _Unescaped_str);
}
}

_STD _Print_noformat(_Ostr, _Unescaped_str) eventually switches between Unicode and non-Unicode, but it has to construct ostream::sentry machinery first, so it wouldn't be worth digging any deeper.

Metadata

Metadata

Assignees

No one assigned

    Labels

    fixedSomething works now, yay!performanceMust go faster

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions