Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

P2093R14: Formatted Output #3337

Merged
merged 112 commits into from
Mar 24, 2023
Merged

Conversation

tylerbrawl
Copy link
Contributor

@tylerbrawl tylerbrawl commented Jan 9, 2023

This PR contains the complete implementation of P2093R14, along with the changes proposed in P2539R3. If merged, it should also close #2916.

Added Files

Some files were added to implement this PR. These may require internal changes to the MSVC and/or Visual Studio which are outside of my control. The added files are as follows:

  • <print>: This is the public header described in P2093R14 containing the FILE* overloads of std::print() et al..

  • <__msvc_filebuf.hpp>: This is a private, non-core header which contains the definition for std::basic_filebuf, which was initially located in <fstream>. This was necessary in order to define the std::ostream& overloads of std::print() et al. within <ostream>; otherwise, there would be a header circular dependency (<ostream> -> <fstream> -> <istream> -> <ostream> -> ...).

  • <__msvc_print.hpp>: This is a private, core header which declares the C API exposing the functionality for printing to Unicode consoles as described in P2093R14.

  • <__msvc_unicode_iterators.hpp>: This is a private, non-core header which contains the definitions for various Unicode string parsing iterators which were initially located in <format>. The motivation behind this was to enable large strings to be broken down into grapheme clusters so that calls to WriteConsoleW() don't result in bad output.

  • src\print.cpp: This implements the C API declared in <__msvc_print.hpp>.

Implementation Notes

  • I'm not particularly proud of the current method for checking if std::ostream instances refer to Unicode consoles. The proposed implementation uses a dynamic_cast to try to convert the std::streambuf of the std::ostream instance to a std::filebuf, and then extracts its FILE* if successful. I'm open to suggestions as to how this could be improved. The main difficulty is coming up with a solution which doesn't break ABI. (This is also the method taken by the fmt library.)

  • As a result of the aforementioned implementation detail, the std::ostream& overloads of std::print() et al. are currently deleted if RTTI is disabled. (The versions which take a FILE* instead are still available in that case.)

  • Some optimizations were done to improve code generation in common scenarios:

    • For std::println(), rather than making a second std::vformat() call as is proposed in the standard, a newline character is manually added to the std::string generated by the first call to std::vformat() using std::basic_string::operator+().
    • In the case where no formatting arguments are present in the provided string, no call to std::vformat() is ever actually made. Instead, the provided std::format_string itself is parsed to manually remove escaped braces (i.e., {{ and }}), and the generated string is what gets printed. This case is checked at compile time by examining the sizeof... the formatting arguments template parameter pack.

Finally, this PR is currently marked as a draft until test cases are added. As always, let me know if you have any questions.

@cpplearner

This comment was marked as resolved.

stl/inc/xprint.h Outdated Show resolved Hide resolved
@StephanTLavavej StephanTLavavej added format C++20/23 format cxx23 C++23 feature labels Jan 9, 2023
@frederick-vs-ja

This comment was marked as resolved.

@tylerbrawl

This comment was marked as resolved.

@tylerbrawl

This comment was marked as resolved.

@timsong-cpp

This comment was marked as resolved.

stl/src/print.cpp Outdated Show resolved Hide resolved
stl/inc/ostream Outdated Show resolved Hide resolved
stl/inc/__msvc_filebuf.hpp Outdated Show resolved Hide resolved
stl/inc/__msvc_print.hpp Outdated Show resolved Hide resolved
stl/inc/__msvc_print.hpp Outdated Show resolved Hide resolved
stl/inc/__msvc_filebuf.hpp Outdated Show resolved Hide resolved
@StephanTLavavej
Copy link
Member

I've pushed one more round of changes:

  • WinSemaphore => win_semaphore
  • Store last_console_line for easier debugging.
  • Make curr_line_number non-static in test_print_optimizations(), matching what test_invalid_code_points_console() does.
  • Run tests before and after switching the console output codepage.
  • test_invalid_code_points_console() requires UTF-8 behavior.

@StephanTLavavej StephanTLavavej self-assigned this Mar 23, 2023
@StephanTLavavej
Copy link
Member

I'm speculatively mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed.

@StephanTLavavej
Copy link
Member

I had to push a commit to fix the compiler's internal "objsize" test, that verifies that including most STL headers doesn't emit object code. This templates the functions being added to <ostream>, with extra templating to ensure that filebuf machinery (particularly the codecvt::id) isn't eagerly instantiated.

@StephanTLavavej
Copy link
Member

I pushed 3 additional commits to fix the simple but major bug that @cpplearner noticed (thanks again! 😻), added test coverage for empty strings and newlines, and improved the test to avoid leaving temp files behind.

@StephanTLavavej StephanTLavavej merged commit 8a6ec5a into microsoft:main Mar 24, 2023
@StephanTLavavej
Copy link
Member

Thanks for implementing this major C++23 feature! 😻 📜 🎉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
cxx23 C++23 feature format C++20/23 format
Projects
None yet
Development

Successfully merging this pull request may close these issues.

P2093R14 <print>: Formatted Output
9 participants