[libc++][print] Adds ostream overloads. (#73262)

Finishes implementation of
- P2093R14 Formatted output
- P2539R4 Should the output of std::print to a terminal be synchronized
with the underlying stream?

Differential Revision: https://reviews.llvm.org/D156609
This commit is contained in:
Mark de Wever
2023-12-19 19:32:17 +01:00
committed by GitHub
parent dcd7c8b7c9
commit 2fd4084fca
41 changed files with 3478 additions and 110 deletions

View File

@@ -344,7 +344,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_out_ptr`` *unimplemented*
--------------------------------------------------- -----------------
``__cpp_lib_print`` *unimplemented*
``__cpp_lib_print`` ``202207L``
--------------------------------------------------- -----------------
``__cpp_lib_ranges_as_const`` *unimplemented*
--------------------------------------------------- -----------------

View File

@@ -28,6 +28,29 @@ The Standard allows implementations to automatically update the
This offers a way for users to update the *remote time zone database* and
give them full control over the process.
`[ostream.formatted.print]/3 <http://eel.is/c++draft/ostream.formatted.print#3>`_ A terminal capable of displaying Unicode
--------------------------------------------------------------------------------------------------------------------------
The Standard specifies that the manner in which a stream is determined to refer
to a terminal capable of displaying Unicode is implementation-defined. This is
used for ``std::print`` and similar functions taking an ``ostream&`` argument.
Libc++ determines that a stream is Unicode-capable terminal by:
* First it determines whether the stream's ``rdbuf()`` has an underlying
``FILE*``. This is ``true`` in the following cases:
* The stream is ``std::cout``, ``std::cerr``, or ``std::clog``.
* A ``std::basic_filebuf<CharT, Traits>`` derived from ``std::filebuf``.
* The way to determine whether this ``FILE*`` refers to a terminal capable of
displaying Unicode is the same as specified for `void vprint_unicode(FILE*
stream, string_view fmt, format_args args);
<http://eel.is/c++draft/print.fun#7>`_. This function is used for other
``std::print`` overloads that don't take an ``ostream&`` argument.
Listed in the index of implementation-defined behavior
======================================================

View File

@@ -41,6 +41,8 @@ What's New in Libc++ 18.0.0?
Implemented Papers
------------------
- P2093R14 Formatted output
- P2539R4 Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?
- P2497R0 - Testing for success or failure of ``<charconv>`` functions
- P2697R1 - Interfacing ``bitset`` with ``string_view``

View File

@@ -59,7 +59,7 @@
"`P1467R9 <https://wg21.link/P1467R9>`__","LWG","Extended ``floating-point`` types and standard names","July 2022","",""
"`P1642R11 <https://wg21.link/P1642R11>`__","LWG","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","July 2022","",""
"`P1899R3 <https://wg21.link/P1899R3>`__","LWG","``stride_view``","July 2022","","","|ranges|"
"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","|In Progress|"
"`P2093R14 <https://wg21.link/P2093R14>`__","LWG","Formatted output","July 2022","","|Complete|","18.0"
"`P2165R4 <https://wg21.link/P2165R4>`__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","",""
"`P2278R4 <https://wg21.link/P2278R4>`__","LWG","``cbegin`` should always return a constant iterator","July 2022","","","|ranges|"
"`P2286R8 <https://wg21.link/P2286R8>`__","LWG","Formatting Ranges","July 2022","|Complete|","16.0","|format| |ranges|"
@@ -99,7 +99,7 @@
"`P2167R3 <https://wg21.link/P2167R3>`__","LWG", "Improved Proposed Wording for LWG 2114", "November 2022","","",""
"`P2396R1 <https://wg21.link/P2396R1>`__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|"
"`P2505R5 <https://wg21.link/P2505R5>`__","LWG", "Monadic Functions for ``std::expected``", "November 2022","|Complete|","17.0",""
"`P2539R4 <https://wg21.link/P2539R4>`__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|In Progress|","","|format|"
"`P2539R4 <https://wg21.link/P2539R4>`__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|Complete|","18.0","|format|"
"`P2602R2 <https://wg21.link/P2602R2>`__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|"
"`P2708R1 <https://wg21.link/P2708R1>`__","LWG", "No Further Fundamentals TSes", "November 2022","|Nothing to do|","",""
"","","","","","",""
1 Paper # Group Paper Name Meeting Status First released version Labels
59 `P1467R9 <https://wg21.link/P1467R9>`__ LWG Extended ``floating-point`` types and standard names July 2022
60 `P1642R11 <https://wg21.link/P1642R11>`__ LWG Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]`` July 2022
61 `P1899R3 <https://wg21.link/P1899R3>`__ LWG ``stride_view`` July 2022 |ranges|
62 `P2093R14 <https://wg21.link/P2093R14>`__ LWG Formatted output July 2022 |In Progress| |Complete| 18.0
63 `P2165R4 <https://wg21.link/P2165R4>`__ LWG Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects July 2022
64 `P2278R4 <https://wg21.link/P2278R4>`__ LWG ``cbegin`` should always return a constant iterator July 2022 |ranges|
65 `P2286R8 <https://wg21.link/P2286R8>`__ LWG Formatting Ranges July 2022 |Complete| 16.0 |format| |ranges|
99 `P2167R3 <https://wg21.link/P2167R3>`__ LWG Improved Proposed Wording for LWG 2114 November 2022
100 `P2396R1 <https://wg21.link/P2396R1>`__ LWG Concurrency TS 2 fixes November 2022 |concurrency TS|
101 `P2505R5 <https://wg21.link/P2505R5>`__ LWG Monadic Functions for ``std::expected`` November 2022 |Complete| 17.0
102 `P2539R4 <https://wg21.link/P2539R4>`__ LWG Should the output of ``std::print`` to a terminal be synchronized with the underlying stream? November 2022 |In Progress| |Complete| 18.0 |format|
103 `P2602R2 <https://wg21.link/P2602R2>`__ LWG Poison Pills are Too Toxic November 2022 |ranges|
104 `P2708R1 <https://wg21.link/P2708R1>`__ LWG No Further Fundamentals TSes November 2022 |Nothing to do|
105

View File

@@ -5,11 +5,11 @@ Number,Name,Standard,Assignee,Status,First released version
`P1868 <https://wg21.link/P1868>`_,"width: clarifying units of width and precision in std::format (Implements the unicode support.)","C++20",Mark de Wever,|Complete|,14.0
`P2216 <https://wg21.link/P2216>`_,"std::format improvements","C++20",Mark de Wever,|Complete|,15.0
`P2418 <https://wg21.link/P2418>`__,"Add support for ``std::generator``-like types to ``std::format``","C++20",Mark de Wever,|Complete|,15.0
"`P2093R14 <https://wg21.link/P2093R14>`__","Formatted output","C++23",Mark de Wever,|In Progress|
"`P2093R14 <https://wg21.link/P2093R14>`__","Formatted output","C++23",Mark de Wever,|Complete|,"18.0"
"`P2286R8 <https://wg21.link/P2286R8>`__","Formatting Ranges","C++23","Mark de Wever","|Complete|",16.0
"`P2508R1 <https://wg21.link/P2508R1>`__","Exposing ``std::basic-format-string``","C++23","Mark de Wever","|Complete|",15.0
"`P2585R0 <https://wg21.link/P2585R0>`__","Improving default container formatting","C++23","Mark de Wever","|Complete|",17.0
"`P2539R4 <https://wg21.link/P2539R4>`__","Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?","C++23","Mark de Wever","|In Progress|"
"`P2539R4 <https://wg21.link/P2539R4>`__","Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?","C++23","Mark de Wever","|Complete|","18.0"
"`P2713R1 <https://wg21.link/P2713R1>`__","Escaping improvements in ``std::format``","C++23","Mark de Wever",""
"`P2675R1 <https://wg21.link/P2675R1>`__","``format``'s width estimation is too approximate and not forward compatible","C++23","Mark de Wever","|Complete|",17.0
"`P2572R1 <https://wg21.link/P2572R1>`__","``std::format`` fill character allowances","C++23","Mark de Wever","|Complete|",17.0
1 Number Name Standard Assignee Status First released version
5 `P1868 <https://wg21.link/P1868>`_ width: clarifying units of width and precision in std::format (Implements the unicode support.) C++20 Mark de Wever |Complete| 14.0
6 `P2216 <https://wg21.link/P2216>`_ std::format improvements C++20 Mark de Wever |Complete| 15.0
7 `P2418 <https://wg21.link/P2418>`__ Add support for ``std::generator``-like types to ``std::format`` C++20 Mark de Wever |Complete| 15.0
8 `P2093R14 <https://wg21.link/P2093R14>`__ Formatted output C++23 Mark de Wever |In Progress| |Complete| 18.0
9 `P2286R8 <https://wg21.link/P2286R8>`__ Formatting Ranges C++23 Mark de Wever |Complete| 16.0
10 `P2508R1 <https://wg21.link/P2508R1>`__ Exposing ``std::basic-format-string`` C++23 Mark de Wever |Complete| 15.0
11 `P2585R0 <https://wg21.link/P2585R0>`__ Improving default container formatting C++23 Mark de Wever |Complete| 17.0
12 `P2539R4 <https://wg21.link/P2539R4>`__ Should the output of ``std::print`` to a terminal be synchronized with the underlying stream? C++23 Mark de Wever |In Progress| |Complete| 18.0
13 `P2713R1 <https://wg21.link/P2713R1>`__ Escaping improvements in ``std::format`` C++23 Mark de Wever
14 `P2675R1 <https://wg21.link/P2675R1>`__ ``format``'s width estimation is too approximate and not forward compatible C++23 Mark de Wever |Complete| 17.0
15 `P2572R1 <https://wg21.link/P2572R1>`__ ``std::format`` fill character allowances C++23 Mark de Wever |Complete| 17.0

View File

@@ -49,4 +49,4 @@ Section,Description,Dependencies,Assignee,Status,First released version
"`P2093R14 <https://wg21.link/P2093R14>`__","Formatted output"
`[print.fun] <https://wg21.link/print.fun>`__,"Output to ``stdout``",,Mark de Wever,|Complete|, 17.0
`[print.fun] <https://wg21.link/print.fun>`__,"Output to ``FILE*``",,Mark de Wever,|Complete|, 17.0
`[ostream.formatted.print] <https://wg21.link/ostream.formatted.print>`__,"Output to ``ostream``",,Mark de Wever
`[ostream.formatted.print] <https://wg21.link/ostream.formatted.print>`__,"Output to ``ostream``",,Mark de Wever,|Complete|, 18.0
1 Section Description Dependencies Assignee Status First released version
49
50
51
52

View File

@@ -136,6 +136,12 @@
# define _LIBCPP_AVAILABILITY_HAS_TZDB 1
# define _LIBCPP_AVAILABILITY_TZDB
// This controls the availability of C++23 <print>, which
// has a dependency on the built library (it needs access to
// the underlying buffer types of std::cout, std::cerr, and std::clog.
# define _LIBCPP_AVAILABILITY_HAS_PRINT 1
# define _LIBCPP_AVAILABILITY_PRINT
// Enable additional explicit instantiations of iostreams components. This
// reduces the number of weak definitions generated in programs that use
// iostreams by providing a single strong definition in the shared library.
@@ -258,6 +264,9 @@
# define _LIBCPP_AVAILABILITY_HAS_TZDB 0
# define _LIBCPP_AVAILABILITY_TZDB __attribute__((unavailable))
# define _LIBCPP_AVAILABILITY_HAS_PRINT 0
# define _LIBCPP_AVAILABILITY_PRINT __attribute__((unavailable))
// clang-format off
# if (defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 120000) || \
(defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ < 150000) || \

View File

@@ -280,6 +280,8 @@ private:
bool __read_mode();
void __write_mode();
_LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
};
template <class _CharT, class _Traits>

View File

@@ -159,13 +159,24 @@ basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, cons
template<class traits>
basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, const char32_t*) = delete; // since C++20
// [ostream.formatted.print], print functions
template<class... Args> // since C++23
void print(ostream& os, format_string<Args...> fmt, Args&&... args);
template<class... Args> // since C++23
void println(ostream& os, format_string<Args...> fmt, Args&&... args);
void vprint_unicode(ostream& os, string_view fmt, format_args args); // since C++23
void vprint_nonunicode(ostream& os, string_view fmt, format_args args); // since C++23
} // std
*/
#include <__assert> // all public C++ headers provide the assertion handler
#include <__availability>
#include <__config>
#include <__exception/operations.h>
#include <__format/format_args.h>
#include <__format/format_functions.h>
#include <__fwd/ostream.h>
#include <__memory/shared_ptr.h>
#include <__memory/unique_ptr.h>
@@ -176,10 +187,13 @@ basic_ostream<wchar_t, traits>& operator<<(basic_ostream<wchar_t, traits>&, cons
#include <__type_traits/void_t.h>
#include <__utility/declval.h>
#include <bitset>
#include <cstdio>
#include <ios>
#include <locale>
#include <new>
#include <print>
#include <streambuf>
#include <string_view>
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -1005,6 +1019,151 @@ extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostream<char>;
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostream<wchar_t>;
#endif
#if _LIBCPP_STD_VER >= 23
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void
__vprint_nonunicode(ostream& __os, string_view __fmt, format_args __args, bool __write_nl) {
// [ostream.formatted.print]/3
// Effects: Behaves as a formatted output function
// ([ostream.formatted.reqmts]) of os, except that:
// - failure to generate output is reported as specified below, and
// - any exception thrown by the call to vformat is propagated without regard
// to the value of os.exceptions() and without turning on ios_base::badbit
// in the error state of os.
// After constructing a sentry object, the function initializes an automatic
// variable via
// string out = vformat(os.getloc(), fmt, args);
ostream::sentry __s(__os);
if (__s) {
string __o = std::vformat(__os.getloc(), __fmt, __args);
if (__write_nl)
__o += '\n';
const char* __str = __o.data();
size_t __len = __o.size();
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
typedef ostreambuf_iterator<char> _Ip;
if (std::__pad_and_output(
_Ip(__os),
__str,
(__os.flags() & ios_base::adjustfield) == ios_base::left ? __str + __len : __str,
__str + __len,
__os,
__os.fill())
.failed())
__os.setstate(ios_base::badbit | ios_base::failbit);
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
__os.__set_badbit_and_consider_rethrow();
}
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
}
}
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_HIDE_FROM_ABI inline void vprint_nonunicode(ostream& __os, string_view __fmt, format_args __args) {
std::__vprint_nonunicode(__os, __fmt, __args, false);
}
// Returns the FILE* associated with the __os.
// Returns a nullptr when no FILE* is associated with __os.
// This function is in the dylib since the type of the buffer associated
// with std::cout, std::cerr, and std::clog is only known in the dylib.
//
// This function implements part of the implementation-defined behavior
// of [ostream.formatted.print]/3
// If the function is vprint_unicode and os is a stream that refers to
// a terminal capable of displaying Unicode which is determined in an
// implementation-defined manner, writes out to the terminal using the
// native Unicode API;
// Whether the returned FILE* is "a terminal capable of displaying Unicode"
// is determined in the same way as the print(FILE*, ...) overloads.
_LIBCPP_AVAILABILITY_PRINT _LIBCPP_EXPORTED_FROM_ABI FILE* __get_ostream_file(ostream& __os);
# ifndef _LIBCPP_HAS_NO_UNICODE
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_AVAILABILITY_PRINT _LIBCPP_HIDE_FROM_ABI void
__vprint_unicode(ostream& __os, string_view __fmt, format_args __args, bool __write_nl) {
FILE* __file = std::__get_ostream_file(__os);
if (!__file || !__print::__is_terminal(__file))
return std::__vprint_nonunicode(__os, __fmt, __args, __write_nl);
// [ostream.formatted.print]/3
// If the function is vprint_unicode and os is a stream that refers to a
// terminal capable of displaying Unicode which is determined in an
// implementation-defined manner, writes out to the terminal using the
// native Unicode API; if out contains invalid code units, the behavior is
// undefined and implementations are encouraged to diagnose it. If the
// native Unicode API is used, the function flushes os before writing out.
//
// This is the path for the native API, start with flushing.
__os.flush();
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
try {
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
ostream::sentry __s(__os);
if (__s) {
# ifndef _LIBCPP_WIN32API
__print::__vprint_unicode_posix(__file, __fmt, __args, __write_nl, true);
# elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
__print::__vprint_unicode_windows(__file, __fmt, __args, __write_nl, true);
# else
# error "Windows builds with wchar_t disabled are not supported."
# endif
}
# ifndef _LIBCPP_HAS_NO_EXCEPTIONS
} catch (...) {
__os.__set_badbit_and_consider_rethrow();
}
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
}
template <class = void> // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563).
_LIBCPP_AVAILABILITY_PRINT _LIBCPP_HIDE_FROM_ABI inline void
vprint_unicode(ostream& __os, string_view __fmt, format_args __args) {
std::__vprint_unicode(__os, __fmt, __args, false);
}
# endif // _LIBCPP_HAS_NO_UNICODE
template <class... _Args>
_LIBCPP_AVAILABILITY_PRINT _LIBCPP_HIDE_FROM_ABI void
print(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args) {
# ifndef _LIBCPP_HAS_NO_UNICODE
if constexpr (__print::__use_unicode)
std::__vprint_unicode(__os, __fmt.get(), std::make_format_args(__args...), false);
else
std::__vprint_nonunicode(__os, __fmt.get(), std::make_format_args(__args...), false);
# else // _LIBCPP_HAS_NO_UNICODE
std::__vprint_nonunicode(__os, __fmt.get(), std::make_format_args(__args...), false);
# endif // _LIBCPP_HAS_NO_UNICODE
}
template <class... _Args>
_LIBCPP_AVAILABILITY_PRINT _LIBCPP_HIDE_FROM_ABI void
println(ostream& __os, format_string<_Args...> __fmt, _Args&&... __args) {
# ifndef _LIBCPP_HAS_NO_UNICODE
// Note the wording in the Standard is inefficient. The output of
// std::format is a std::string which is then copied. This solution
// just appends a newline at the end of the output.
if constexpr (__print::__use_unicode)
std::__vprint_unicode(__os, __fmt.get(), std::make_format_args(__args...), true);
else
std::__vprint_nonunicode(__os, __fmt.get(), std::make_format_args(__args...), true);
# else // _LIBCPP_HAS_NO_UNICODE
std::__vprint_nonunicode(__os, __fmt.get(), std::make_format_args(__args...), true);
# endif // _LIBCPP_HAS_NO_UNICODE
}
#endif // _LIBCPP_STD_VER >= 23
_LIBCPP_END_NAMESPACE_STD
#if !defined(_LIBCPP_REMOVE_TRANSITIVE_INCLUDES) && _LIBCPP_STD_VER <= 20

View File

@@ -59,7 +59,7 @@ namespace std {
_LIBCPP_BEGIN_NAMESPACE_STD
#ifdef _WIN32
#ifdef _LIBCPP_WIN32API
_LIBCPP_EXPORTED_FROM_ABI bool __is_windows_terminal(FILE* __stream);
# ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
@@ -75,7 +75,7 @@ _LIBCPP_EXPORTED_FROM_ABI bool __is_windows_terminal(FILE* __stream);
_LIBCPP_EXPORTED_FROM_ABI void __write_to_windows_console(FILE* __stream, wstring_view __view);
# endif // _LIBCPP_HAS_NO_WIDE_CHARACTERS
#endif // _WIN32
#endif // _LIBCPP_WIN32API
#if _LIBCPP_STD_VER >= 23
@@ -198,7 +198,11 @@ inline constexpr bool __use_unicode = true;
# endif
_LIBCPP_HIDE_FROM_ABI inline bool __is_terminal(FILE* __stream) {
# ifdef _WIN32
// The macro _LIBCPP_TESTING_PRINT_IS_TERMINAL is used to change
// the behavior in the test. This is not part of the public API.
# ifdef _LIBCPP_TESTING_PRINT_IS_TERMINAL
return _LIBCPP_TESTING_PRINT_IS_TERMINAL(__stream);
# elif defined(_LIBCPP_WIN32API)
return std::__is_windows_terminal(__stream);
# elif __has_include(<unistd.h>)
return isatty(fileno(__stream));
@@ -271,7 +275,7 @@ __vprint_unicode_windows(FILE* __stream, string_view __fmt, format_args __args,
// the behavior in the test. This is not part of the public API.
# ifdef _LIBCPP_TESTING_PRINT_WRITE_TO_WINDOWS_CONSOLE_FUNCTION
_LIBCPP_TESTING_PRINT_WRITE_TO_WINDOWS_CONSOLE_FUNCTION(__stream, __view);
# elif defined(_WIN32)
# elif defined(_LIBCPP_WIN32API)
std::__write_to_windows_console(__stream, __view);
# else
std::__throw_runtime_error("No defintion of _LIBCPP_TESTING_PRINT_WRITE_TO_WINDOWS_CONSOLE_FUNCTION and "
@@ -309,7 +313,7 @@ __vprint_unicode([[maybe_unused]] FILE* __stream,
// so there the call can be forwarded to the non_unicode API. On
// Windows there is a different API. This API requires transcoding.
# ifndef _WIN32
# ifndef _LIBCPP_WIN32API
__print::__vprint_unicode_posix(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream));
# elif !defined(_LIBCPP_HAS_NO_WIDE_CHARACTERS)
__print::__vprint_unicode_windows(__stream, __fmt, __args, __write_nl, __print::__is_terminal(__stream));

View File

@@ -454,7 +454,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
# undef __cpp_lib_optional
# define __cpp_lib_optional 202110L
// # define __cpp_lib_out_ptr 202106L
// # define __cpp_lib_print 202207L
# define __cpp_lib_print 202207L
// # define __cpp_lib_ranges_as_const 202207L
# define __cpp_lib_ranges_as_rvalue 202207L
// # define __cpp_lib_ranges_chunk 202202L

View File

@@ -1465,6 +1465,7 @@
{'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__time_get_storageIcEC1EPKc', 'type': 'FUNC'}

View File

@@ -506,6 +506,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcEC1EPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}

View File

@@ -506,6 +506,7 @@
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'storage_mapping_class': 'DS', 'type': 'FUNC'}
{'import_export': 'EXP', 'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcEC1EPKc', 'storage_mapping_class': 'DS', 'type': 'FUNC'}

View File

@@ -1465,6 +1465,7 @@
{'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '__ZNSt3__118__time_get_storageIcEC1EPKc', 'type': 'FUNC'}

View File

@@ -1160,6 +1160,7 @@
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcEC1EPKc', 'type': 'FUNC'}
@@ -2025,4 +2026,4 @@
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__114basic_iostreamIcNS_11char_traitsIcEEED1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD0Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZTv0_n24_NSt3__19strstreamD1Ev', 'type': 'FUNC'}

View File

@@ -1158,6 +1158,7 @@
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcEC1EPKc', 'type': 'FUNC'}

View File

@@ -1130,6 +1130,7 @@
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIcLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb0EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__117moneypunct_bynameIwLb1EE4initEPKc', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__get_ostream_fileERNS_13basic_ostreamIcNS_11char_traitsIcEEEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE4initERKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcE9__analyzeEcRKNS_5ctypeIcEE', 'type': 'FUNC'}
{'is_defined': True, 'name': '_ZNSt3__118__time_get_storageIcEC1EPKc', 'type': 'FUNC'}

View File

@@ -27,13 +27,14 @@ export namespace std {
# endif
using std::operator<<;
# if 0
# if _LIBCPP_STD_VER >= 23
// [ostream.formatted.print], print functions
using std::print;
using std::println;
using std::vprint_nonunicode;
using std::vprint_unicode;
# endif
# endif // _LIBCPP_STD_VER >= 23
#endif // _LIBCPP_HAS_NO_LOCALIZATION
} // namespace std

View File

@@ -89,6 +89,7 @@ if (LIBCXX_ENABLE_LOCALIZATION)
ios.instantiations.cpp
iostream.cpp
locale.cpp
ostream.cpp
regex.cpp
strstream.cpp
)

42
libcxx/src/ostream.cpp Normal file
View File

@@ -0,0 +1,42 @@
//===----------------------------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include <__availability>
#include <__config>
#ifndef _LIBCPP_HAS_NO_FILESYSTEM
# include <fstream>
#endif
#include <ostream>
#include "std_stream.h"
_LIBCPP_BEGIN_NAMESPACE_STD
_LIBCPP_AVAILABILITY_PRINT _LIBCPP_EXPORTED_FROM_ABI FILE* __get_ostream_file(ostream& __os) {
// dynamic_cast requires RTTI, this only affects users whose vendor builds
// the dylib with RTTI disabled. It does not affect users who build with RTTI
// disabled but use a dylib where the RTTI is enabled.
//
// Returning a nullptr means the stream is not considered a terminal and the
// special terminal handling is not done. The terminal handling is mainly of
// importance on Windows.
#ifndef _LIBCPP_HAS_NO_RTTI
auto* __rdbuf = __os.rdbuf();
# ifndef _LIBCPP_HAS_NO_FILESYSTEM
if (auto* __buffer = dynamic_cast<filebuf*>(__rdbuf))
return __buffer->__file_;
# endif
if (auto* __buffer = dynamic_cast<__stdoutbuf<char>*>(__rdbuf))
return __buffer->__file_;
#endif // _LIBCPP_HAS_NO_RTTI
return nullptr;
}
_LIBCPP_END_NAMESPACE_STD

View File

@@ -269,6 +269,8 @@ private:
__stdoutbuf(const __stdoutbuf&);
__stdoutbuf& operator=(const __stdoutbuf&);
_LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
};
template <class _CharT>

View File

@@ -0,0 +1,165 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: no-filesystem, no-rtti
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// XFAIL: availability-fp_to_chars-missing
// XFAIL: availability-print-missing
// Clang modules do not work with the definiton of _LIBCPP_TESTING_PRINT_IS_TERMINAL
// XFAIL: clang-modules-build
// <ostream>
// Tests the implementation of
// void __vprint_unicode(ostream& os, string_view fmt,
// format_args args, bool write_nl);
// In the library when std::cout is redirected to a file it is no longer
// considered a terminal and the special terminal handling is no longer
// executed. By testing this function we can "force" emulate a terminal.
// Note write_nl is tested by the public API.
#include <cstdio>
bool is_terminal(FILE*);
#define _LIBCPP_TESTING_PRINT_IS_TERMINAL ::is_terminal
#include "filesystem_test_helper.h"
#include <cassert>
#include <fstream>
#include <iostream>
#include <ostream>
#include <sstream>
#include "test_macros.h"
scoped_test_env env;
std::string filename = env.create_file("output.txt");
int is_terminal_calls = 0;
bool is_terminal_result = false;
bool is_terminal(FILE*) {
++is_terminal_calls;
return is_terminal_result;
}
// When the stream is not a file stream, cout, clog, or cerr the stream does not
// considered to be backed by a FILE*. Then the stream should never check
// whether it's a terminal.
static void test_is_terminal_not_a_file_stream() {
is_terminal_calls = 0;
is_terminal_result = false;
{
std::stringstream stream;
std::print(stream, "test");
}
{
std::ostringstream stream;
std::print(stream, "test");
}
assert(is_terminal_calls == 0);
}
// When the stream is a file stream, its FILE* may be a terminal. Validate this
// is tested.
static void test_is_terminal_file_stream() {
is_terminal_calls = 0;
is_terminal_result = false;
{
std::fstream stream(filename);
assert(stream.is_open());
assert(stream.good());
std::print(stream, "test");
assert(is_terminal_calls == 1);
}
{
std::ofstream stream(filename);
assert(stream.is_open());
assert(stream.good());
std::print(stream, "test");
assert(is_terminal_calls == 2);
}
}
// The same as above, but this time test for derived classes.
static void test_is_terminal_rdbuf_derived_from_filebuf() {
struct my_filebuf : public std::filebuf {};
is_terminal_calls = 0;
is_terminal_result = false;
my_filebuf buf;
buf.open(filename, std::ios_base::out);
assert(buf.is_open());
std::ostream stream(&buf);
std::print(stream, "test");
assert(is_terminal_calls == 1);
}
// When the stream is cout, clog, or cerr, its FILE* may be a terminal. Validate
// this is tested.
static void test_is_terminal_std_cout_cerr_clog() {
is_terminal_calls = 0;
is_terminal_result = false;
{
std::print(std::cout, "test");
assert(is_terminal_calls == 1);
}
{
std::print(std::cerr, "test");
assert(is_terminal_calls == 2);
}
{
std::print(std::clog, "test");
assert(is_terminal_calls == 3);
}
}
// When the stream's FILE* is a terminal the contents need to be flushed before
// writing to the stream.
static void test_is_terminal_is_flushed() {
struct sync_counter : public std::filebuf {
sync_counter() {
open(filename, std::ios_base::out);
assert(is_open());
}
int sync_calls = 0;
protected:
int virtual sync() {
++sync_calls;
return std::basic_streambuf<char>::sync();
}
};
is_terminal_result = false;
sync_counter buf;
std::ostream stream(&buf);
// Not a terminal sync is not called.
std::print(stream, "");
assert(buf.sync_calls == 0);
// A terminal sync is called.
is_terminal_result = true;
std::print(stream, "");
assert(buf.sync_calls == 1); // only called from the destructor of the sentry
}
int main(int, char**) {
test_is_terminal_not_a_file_stream();
test_is_terminal_file_stream();
test_is_terminal_rdbuf_derived_from_filebuf();
test_is_terminal_std_cout_cerr_clog();
test_is_terminal_is_flushed();
return 0;
}

View File

@@ -576,26 +576,29 @@ optional typeinfo
optional utility
optional variant
optional version
ostream array
ostream atomic
ostream bitset
ostream cerrno
ostream cmath
ostream concepts
ostream cstddef
ostream cstdint
ostream cstdio
ostream cstdlib
ostream cstring
ostream initializer_list
ostream ios
ostream iosfwd
ostream iterator
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream string_view
ostream tuple
ostream type_traits
ostream typeinfo
ostream version
print array
print cerrno
1 algorithm atomic
576 optional utility
577 optional variant
578 optional version
579 ostream array
580 ostream atomic
581 ostream bitset
582 ostream cerrno ostream cmath
583 ostream concepts
584 ostream cstddef
585 ostream cstdint
586 ostream cstdio
587 ostream cstdlib
ostream cstring
ostream initializer_list
588 ostream ios
589 ostream iosfwd
590 ostream iterator
591 ostream limits
592 ostream locale
593 ostream new
594 ostream optional
595 ostream print
596 ostream stdexcept
597 ostream streambuf
598 ostream string
599 ostream string_view
600 ostream tuple
601 ostream type_traits
ostream typeinfo
602 ostream version
603 print array
604 print cerrno

View File

@@ -581,26 +581,29 @@ optional typeinfo
optional utility
optional variant
optional version
ostream array
ostream atomic
ostream bitset
ostream cerrno
ostream cmath
ostream concepts
ostream cstddef
ostream cstdint
ostream cstdio
ostream cstdlib
ostream cstring
ostream initializer_list
ostream ios
ostream iosfwd
ostream iterator
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream string_view
ostream tuple
ostream type_traits
ostream typeinfo
ostream version
print array
print cerrno
1 algorithm atomic
581 optional utility
582 optional variant
583 optional version
584 ostream array
585 ostream atomic
586 ostream bitset
587 ostream cerrno ostream cmath
588 ostream concepts
589 ostream cstddef
590 ostream cstdint
591 ostream cstdio
592 ostream cstdlib
ostream cstring
ostream initializer_list
593 ostream ios
594 ostream iosfwd
595 ostream iterator
596 ostream limits
597 ostream locale
598 ostream new
599 ostream optional
600 ostream print
601 ostream stdexcept
602 ostream streambuf
603 ostream string
604 ostream string_view
605 ostream tuple
606 ostream type_traits
ostream typeinfo
607 ostream version
608 print array
609 print cerrno

View File

@@ -583,26 +583,29 @@ optional typeinfo
optional utility
optional variant
optional version
ostream array
ostream atomic
ostream bitset
ostream cerrno
ostream cmath
ostream concepts
ostream cstddef
ostream cstdint
ostream cstdio
ostream cstdlib
ostream cstring
ostream initializer_list
ostream ios
ostream iosfwd
ostream iterator
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream string_view
ostream tuple
ostream type_traits
ostream typeinfo
ostream version
print array
print cerrno
1 algorithm atomic
583 optional utility
584 optional variant
585 optional version
586 ostream array
587 ostream atomic
588 ostream bitset
589 ostream cerrno ostream cmath
590 ostream concepts
591 ostream cstddef
592 ostream cstdint
593 ostream cstdio
594 ostream cstdlib
ostream cstring
ostream initializer_list
595 ostream ios
596 ostream iosfwd
597 ostream iterator
598 ostream limits
599 ostream locale
600 ostream new
601 ostream optional
602 ostream print
603 ostream stdexcept
604 ostream streambuf
605 ostream string
606 ostream string_view
607 ostream tuple
608 ostream type_traits
ostream typeinfo
609 ostream version
610 print array
611 print cerrno

View File

@@ -583,26 +583,29 @@ optional typeinfo
optional utility
optional variant
optional version
ostream array
ostream atomic
ostream bitset
ostream cerrno
ostream cmath
ostream concepts
ostream cstddef
ostream cstdint
ostream cstdio
ostream cstdlib
ostream cstring
ostream initializer_list
ostream ios
ostream iosfwd
ostream iterator
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream string_view
ostream tuple
ostream type_traits
ostream typeinfo
ostream version
print array
print cerrno
1 algorithm atomic
583 optional utility
584 optional variant
585 optional version
586 ostream array
587 ostream atomic
588 ostream bitset
589 ostream cerrno ostream cmath
590 ostream concepts
591 ostream cstddef
592 ostream cstdint
593 ostream cstdio
594 ostream cstdlib
ostream cstring
ostream initializer_list
595 ostream ios
596 ostream iosfwd
597 ostream iterator
598 ostream limits
599 ostream locale
600 ostream new
601 ostream optional
602 ostream print
603 ostream stdexcept
604 ostream streambuf
605 ostream string
606 ostream string_view
607 ostream tuple
608 ostream type_traits
ostream typeinfo
609 ostream version
610 print array
611 print cerrno

View File

@@ -588,26 +588,29 @@ optional typeinfo
optional utility
optional variant
optional version
ostream array
ostream atomic
ostream bitset
ostream cerrno
ostream cmath
ostream concepts
ostream cstddef
ostream cstdint
ostream cstdio
ostream cstdlib
ostream cstring
ostream initializer_list
ostream ios
ostream iosfwd
ostream iterator
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream string_view
ostream tuple
ostream type_traits
ostream typeinfo
ostream version
print array
print cerrno
1 algorithm atomic
588 optional utility
589 optional variant
590 optional version
591 ostream array
592 ostream atomic
593 ostream bitset
594 ostream cerrno ostream cmath
595 ostream concepts
596 ostream cstddef
597 ostream cstdint
598 ostream cstdio
599 ostream cstdlib
ostream cstring
ostream initializer_list
600 ostream ios
601 ostream iosfwd
602 ostream iterator
603 ostream limits
604 ostream locale
605 ostream new
606 ostream optional
607 ostream print
608 ostream stdexcept
609 ostream streambuf
610 ostream string
611 ostream string_view
612 ostream tuple
613 ostream type_traits
ostream typeinfo
614 ostream version
615 print array
616 print cerrno

View File

@@ -398,19 +398,23 @@ optional initializer_list
optional limits
optional new
optional version
ostream array
ostream bitset
ostream cerrno
ostream cmath
ostream cstddef
ostream cstdint
ostream cstring
ostream initializer_list
ostream cstdio
ostream ios
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream typeinfo
ostream string_view
ostream tuple
ostream version
print array
print cerrno
1 algorithm climits
398 optional limits
399 optional new
400 optional version
401 ostream array
402 ostream bitset
403 ostream cerrno ostream cmath
404 ostream cstddef
405 ostream cstdint
406 ostream cstring ostream cstdio
ostream initializer_list
407 ostream ios
408 ostream limits
409 ostream locale
410 ostream new
411 ostream optional
412 ostream print
413 ostream stdexcept
414 ostream streambuf
415 ostream string
416 ostream typeinfo ostream string_view
417 ostream tuple
418 ostream version
419 print array
420 print cerrno

View File

@@ -398,19 +398,23 @@ optional initializer_list
optional limits
optional new
optional version
ostream array
ostream bitset
ostream cerrno
ostream cmath
ostream cstddef
ostream cstdint
ostream cstring
ostream initializer_list
ostream cstdio
ostream ios
ostream limits
ostream locale
ostream new
ostream optional
ostream print
ostream stdexcept
ostream streambuf
ostream string
ostream typeinfo
ostream string_view
ostream tuple
ostream version
print array
print cerrno
1 algorithm climits
398 optional limits
399 optional new
400 optional version
401 ostream array
402 ostream bitset
403 ostream cerrno ostream cmath
404 ostream cstddef
405 ostream cstdint
406 ostream cstring ostream cstdio
ostream initializer_list
407 ostream ios
408 ostream limits
409 ostream locale
410 ostream new
411 ostream optional
412 ostream print
413 ostream stdexcept
414 ostream streambuf
415 ostream string
416 ostream typeinfo ostream string_view
417 ostream tuple
418 ostream version
419 print array
420 print cerrno

View File

@@ -0,0 +1,193 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// TODO PRINT Investigate see https://reviews.llvm.org/D156585
// UNSUPPORTED: no-filesystem
// XFAIL: availability-fp_to_chars-missing
// XFAIL: availability-print-missing
// <ostream>
// template<class... Args>
// void print(ostream& os, format_string<Args...> fmt, Args&&... args);
// [ostream.formatted.print]/3
// If the function is vprint_unicode and os is a stream that refers to
// a terminal capable of displaying Unicode which is determined in an
// implementation-defined manner, writes out to the terminal using the
// native Unicode API;
// This is tested in
// test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
#include <cassert>
#include <ostream>
#include <sstream>
#include "assert_macros.h"
#include "concat_macros.h"
#include "print_tests.h"
#include "test_format_string.h"
#include "test_macros.h"
auto test_file = []<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
std::stringstream sstr;
std::print(sstr, fmt, std::forward<Args>(args)...);
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []<class... Args>(std::string_view, std::string_view, Args&&...) {
// After P2216 most exceptions thrown by std::format become ill-formed.
// Therefore this tests does nothing.
// A basic ill-formed test is done in format.verify.cpp
// The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
};
// [ostream.formatted.print]/3.2
// ...
// After constructing a sentry object, the function initializes an automatic variable via
// string out = vformat(os.getloc(), fmt, args);
// This means if both
// - creating a sentry fails
// - the formatting fails
// the first one "wins" and the format_error is not thrown.
static void test_sentry_failure() {
// In order for the creation of a sentry to fail a tied stream's
// sync operation should fail.
struct sync_failure : public std::basic_streambuf<char> {
protected:
int virtual sync() { return -1; }
};
sync_failure buf_tied;
std::ostream os_tied(&buf_tied);
os_tied.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
std::stringstream os;
os.tie(&os_tied);
os.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::ios_base::failure, std::print(os, "valid"));
os_tied.clear();
TEST_THROWS_TYPE(std::ios_base::failure, std::print(os, "throws exception at run-time {0:{0}}", -10));
os.exceptions(std::stringstream::goodbit);
os.setstate(std::stringstream::failbit);
std::print(os, "not called when the os.good() is false, so no exception is thrown {0:{0}}", -10);
}
// [ostream.formatted.print]/3.2
// any exception thrown by the call to vformat is propagated without
// regard to the value of os.exceptions() and without turning on
// ios_base::badbit in the error state of os.
// Most invalid format strings are checked at compile-time. An invalid
// value for the width can only be tested run-time.
static void test_format_exception() {
std::stringstream sstr;
assert(sstr.good());
TEST_THROWS_TYPE(std::format_error, std::print(sstr, "no output {0:{0}}", -10));
assert(sstr.good());
assert(sstr.str().empty());
sstr.exceptions(std::stringstream::goodbit);
TEST_THROWS_TYPE(std::format_error, std::print(sstr, "no output {0:{0}}", -10));
assert(sstr.good());
assert(sstr.str().empty());
sstr.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::format_error, std::print(sstr, "no output {0:{0}}", -10));
assert(sstr.good());
assert(sstr.str().empty());
}
static void test_write_failure() {
// Stream that fails to write a single character.
struct overflow_failure : public std::basic_streambuf<char> {
protected:
int virtual overflow(int) { return std::char_traits<char>::eof(); }
};
overflow_failure buf;
std::ostream os(&buf);
os.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::ios_base::failure, std::print(os, "valid"));
os.clear();
// When the parser would directly write to the output instead of
// formatting first it would fail writing the first character 't' of
// the string and result in a std::ios_base::failure exception.
TEST_THROWS_TYPE(std::format_error, std::print(os, "throws exception at run-time {0:{0}}", -10));
os.exceptions(std::stringstream::goodbit);
os.clear();
std::print(os, "valid");
assert(os.fail());
}
static void test_stream_formatting() {
std::stringstream sstr;
auto test = [&]<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
sstr.str("");
std::print(sstr, fmt, std::forward<Args>(args)...);
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
test("hello", "{}", "hello");
sstr.width(10);
test(" hello", "{}", "hello");
sstr.fill('+');
sstr.width(10);
test("+++++hello", "{}", "hello");
// *** Test embedded NUL character ***
using namespace std::literals;
sstr.width(15);
test("++++hello\0world"sv, "hello{}{}", '\0', "world");
// *** Test Unicode ***
// Streams count code units not code points
// 2-byte code points
sstr.width(5);
test("+++\u00a1", "{}", "\u00a1"); // INVERTED EXCLAMATION MARK
sstr.width(5);
test("+++\u07ff", "{}", "\u07ff"); // NKO TAMAN SIGN
// 3-byte code points
sstr.width(5);
test("++\u0800", "{}", "\u0800"); // SAMARITAN LETTER ALAF
sstr.width(5);
test("++\ufffd", "{}", "\ufffd"); // REPLACEMENT CHARACTER
// 4-byte code points
sstr.width(5);
test("+\U00010000", "{}", "\U00010000"); // LINEAR B SYLLABLE B008 A
sstr.width(5);
test("+\U0010FFFF", "{}", "\U0010FFFF"); // Undefined Character
}
int main(int, char**) {
print_tests(test_file, test_exception);
test_sentry_failure();
test_format_exception();
test_write_failure();
test_stream_formatting();
return 0;
}

View File

@@ -0,0 +1,83 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_OUTPUT_STREAMS_OSTREAM_FORMATTED_OSTREAM_FORMATTED_PRINT_PRINT_TESTS_H
#define TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_OUTPUT_STREAMS_OSTREAM_FORMATTED_OSTREAM_FORMATTED_PRINT_PRINT_TESTS_H
template <class TestFunction, class ExceptionTest>
void print_tests(TestFunction check, ExceptionTest check_exception) {
// *** Test escaping ***
check("{", "{{");
check("{:^}", "{{:^}}");
check("{: ^}", "{{:{}^}}", ' ');
check("{:{}^}", "{{:{{}}^}}");
check("{:{ }^}", "{{:{{{}}}^}}", ' ');
// *** Test argument ID ***
check("hello false true", "hello {0:} {1:}", false, true);
check("hello true false", "hello {1:} {0:}", false, true);
// *** Test many arguments ***
check(
"1234567890\t1234567890",
"{}{}{}{}{}{}{}{}{}{}\t{}{}{}{}{}{}{}{}{}{}",
1,
2,
3,
4,
5,
6,
7,
8,
9,
0,
1,
2,
3,
4,
5,
6,
7,
8,
9,
0);
// *** Test embedded NUL character ***
using namespace std::literals;
check("hello\0world"sv, "hello{}{}", '\0', "world");
check("hello\0world"sv, "hello\0{}"sv, "world");
check("hello\0world"sv, "hello{}", "\0world"sv);
// *** Test Unicode ***
// 2-byte code points
check("\u00a1"sv, "{}"sv, "\u00a1"); // INVERTED EXCLAMATION MARK
check("\u07ff"sv, "{:}"sv, "\u07ff"); // NKO TAMAN SIGN
// 3-byte code points
check("\u0800"sv, "{}"sv, "\u0800"); // SAMARITAN LETTER ALAF
check("\ufffd"sv, "{}"sv, "\ufffd"); // REPLACEMENT CHARACTER
// 4-byte code points
check("\U00010000"sv, "{}"sv, "\U00010000"); // LINEAR B SYLLABLE B008 A
check("\U0010FFFF"sv, "{}"sv, "\U0010FFFF"); // Undefined Character
// *** Test invalid format strings ***
check_exception("The format string terminates at a '{'", "{");
check_exception("The replacement field misses a terminating '}'", "{:", 42);
check_exception("The format string contains an invalid escape sequence", "}");
check_exception("The format string contains an invalid escape sequence", "{:}-}", 42);
check_exception("The format string contains an invalid escape sequence", "} ");
check_exception("The argument index starts with an invalid character", "{-", 42);
check_exception("The argument index value is too large for the number of arguments supplied", "hello {}");
check_exception("The argument index value is too large for the number of arguments supplied", "hello {0}");
check_exception("The argument index value is too large for the number of arguments supplied", "hello {1}", 42);
}
#endif // TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_OUTPUT_STREAMS_OSTREAM_FORMATTED_OSTREAM_FORMATTED_PRINT_PRINT_TESTS_H

View File

@@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// TODO PRINT Investigate see https://reviews.llvm.org/D156585
// UNSUPPORTED: no-filesystem
// XFAIL: availability-fp_to_chars-missing
// XFAIL: availability-print-missing
// <ostream>
// template<class... Args>
// void println(ostream& os, format_string<Args...> fmt, Args&&... args);
// [ostream.formatted.print]/3
// If the function is vprint_unicode and os is a stream that refers to
// a terminal capable of displaying Unicode which is determined in an
// implementation-defined manner, writes out to the terminal using the
// native Unicode API;
// This is tested in
// test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
#include <cassert>
#include <ostream>
#include <sstream>
#include "assert_macros.h"
#include "concat_macros.h"
#include "print_tests.h"
#include "test_format_string.h"
#include "test_macros.h"
auto test_file = []<class... Args>(std::string_view e, test_format_string<char, Args...> fmt, Args&&... args) {
std::string expected = std::string{e} + '\n';
std::stringstream sstr;
std::println(sstr, fmt, std::forward<Args>(args)...);
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []<class... Args>(std::string_view, std::string_view, Args&&...) {
// After P2216 most exceptions thrown by std::format become ill-formed.
// Therefore this tests does nothing.
// A basic ill-formed test is done in format.verify.cpp
// The exceptions are tested by other functions that don't use the basic-format-string as fmt argument.
};
int main(int, char**) {
print_tests(test_file, test_exception);
return 0;
}

View File

@@ -0,0 +1,209 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// TODO PRINT Investigate see https://reviews.llvm.org/D156585
// UNSUPPORTED: no-filesystem
// XFAIL: availability-fp_to_chars-missing
// XFAIL: availability-print-missing
// <ostream>
// void vprint_nonunicode(ostream& os, string_view fmt, format_args args);
// [ostream.formatted.print]/3
// If the function is vprint_unicode and os is a stream that refers to
// a terminal capable of displaying Unicode which is determined in an
// implementation-defined manner, writes out to the terminal using the
// native Unicode API;
// This is tested in
// test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
#include <cassert>
#include <ostream>
#include <sstream>
#include "assert_macros.h"
#include "concat_macros.h"
#include "print_tests.h"
#include "test_format_string.h"
#include "test_macros.h"
auto test_file = []<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
std::stringstream sstr;
std::vprint_nonunicode(sstr, fmt.get(), std::make_format_args(args...));
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []< class... Args>([[maybe_unused]] std::string_view what,
[[maybe_unused]] std::string_view fmt,
[[maybe_unused]] Args&&... args) {
TEST_VALIDATE_EXCEPTION(
std::format_error,
[&]([[maybe_unused]] const std::format_error& e) {
TEST_LIBCPP_REQUIRE(
e.what() == what,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
},
[&] {
std::stringstream sstr;
std::vprint_nonunicode(sstr, fmt, std::make_format_args(args...));
}());
};
// [ostream.formatted.print]/3.2
// ...
// After constructing a sentry object, the function initializes an automatic variable via
// string out = vformat(os.getloc(), fmt, args);
// This means if both
// - creating a sentry fails
// - the formatting fails
// the first one "wins" and the format_error is not thrown.
static void test_sentry_failure() {
// In order for the creation of a sentry to fail a tied stream's
// sync operation should fail.
struct sync_failure : public std::basic_streambuf<char> {
protected:
int virtual sync() { return -1; }
};
sync_failure buf_tied;
std::ostream os_tied(&buf_tied);
os_tied.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
std::stringstream os;
os.tie(&os_tied);
os.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::ios_base::failure, std::vprint_nonunicode(os, "valid", std::make_format_args()));
os_tied.clear();
[[maybe_unused]] int arg = -10;
TEST_THROWS_TYPE(std::ios_base::failure,
std::vprint_nonunicode(os, "throws exception at run-time {0:{0}}", std::make_format_args(arg)));
os.exceptions(std::stringstream::goodbit);
os.setstate(std::stringstream::failbit);
std::vprint_nonunicode(
os, "not called when the os.good() is false, so no exception is thrown {0:{0}}", std::make_format_args(arg));
}
// [ostream.formatted.print]/3.2
// any exception thrown by the call to vformat is propagated without
// regard to the value of os.exceptions() and without turning on
// ios_base::badbit in the error state of os.
// Most invalid format strings are checked at compile-time. An invalid
// value for the width can only be tested run-time.
static void test_format_exception() {
std::stringstream sstr;
assert(sstr.good());
[[maybe_unused]] int arg = -10;
TEST_THROWS_TYPE(std::format_error, std::vprint_nonunicode(sstr, "no output {0:{0}}", std::make_format_args(arg)));
assert(sstr.good());
assert(sstr.str().empty());
sstr.exceptions(std::stringstream::goodbit);
TEST_THROWS_TYPE(std::format_error, std::vprint_nonunicode(sstr, "no output {0:{0}}", std::make_format_args(arg)));
assert(sstr.good());
assert(sstr.str().empty());
sstr.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::format_error, std::vprint_nonunicode(sstr, "no output {0:{0}}", std::make_format_args(arg)));
assert(sstr.good());
assert(sstr.str().empty());
}
static void test_write_failure() {
// Stream that fails to write a single character.
struct overflow_failure : public std::basic_streambuf<char> {
protected:
int virtual overflow(int) { return std::char_traits<char>::eof(); }
};
overflow_failure buf;
std::ostream os(&buf);
[[maybe_unused]] int arg = -10;
os.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::ios_base::failure, std::vprint_nonunicode(os, "valid", std::make_format_args()));
os.clear();
// When the parser would directly write to the output instead of
// formatting first it would fail writing the first character 't' of
// the string and result in a std::ios_base::failure exception.
TEST_THROWS_TYPE(std::format_error,
std::vprint_nonunicode(os, "throws exception at run-time {0:{0}}", std::make_format_args(arg)));
os.exceptions(std::stringstream::goodbit);
os.clear();
std::vprint_nonunicode(os, "valid", std::make_format_args());
assert(os.fail());
}
static void test_stream_formatting() {
std::stringstream sstr;
auto test = [&]<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
sstr.str("");
std::vprint_nonunicode(sstr, fmt.get(), std::make_format_args(args...));
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
test("hello", "{}", "hello");
sstr.width(10);
test(" hello", "{}", "hello");
sstr.fill('+');
sstr.width(10);
test("+++++hello", "{}", "hello");
// *** Test embedded NUL character ***
using namespace std::literals;
sstr.width(15);
test("++++hello\0world"sv, "hello{}{}", '\0', "world");
// *** Test Unicode ***
// Streams count code units not code points
// 2-byte code points
sstr.width(5);
test("+++\u00a1", "{}", "\u00a1"); // INVERTED EXCLAMATION MARK
sstr.width(5);
test("+++\u07ff", "{}", "\u07ff"); // NKO TAMAN SIGN
// 3-byte code points
sstr.width(5);
test("++\u0800", "{}", "\u0800"); // SAMARITAN LETTER ALAF
sstr.width(5);
test("++\ufffd", "{}", "\ufffd"); // REPLACEMENT CHARACTER
// 4-byte code points
sstr.width(5);
test("+\U00010000", "{}", "\U00010000"); // LINEAR B SYLLABLE B008 A
sstr.width(5);
test("+\U0010FFFF", "{}", "\U0010FFFF"); // Undefined Character
}
int main(int, char**) {
print_tests(test_file, test_exception);
test_sentry_failure();
test_format_exception();
test_write_failure();
test_stream_formatting();
return 0;
}

View File

@@ -0,0 +1,208 @@
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// TODO PRINT Investigate see https://reviews.llvm.org/D156585
// UNSUPPORTED: no-filesystem
// XFAIL: availability-fp_to_chars-missing
// XFAIL: availability-print-missing
// <ostream>
// void vprint_unicode(ostream& os, string_view fmt, format_args args);
// [ostream.formatted.print]/3
// If the function is vprint_unicode and os is a stream that refers to
// a terminal capable of displaying Unicode which is determined in an
// implementation-defined manner, writes out to the terminal using the
// native Unicode API;
// This is tested in
// test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
#include <cassert>
#include <ostream>
#include <sstream>
#include "assert_macros.h"
#include "concat_macros.h"
#include "print_tests.h"
#include "test_format_string.h"
#include "test_macros.h"
auto test_file = []<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
std::stringstream sstr;
std::vprint_unicode(sstr, fmt.get(), std::make_format_args(args...));
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
auto test_exception = []< class... Args>([[maybe_unused]] std::string_view what,
[[maybe_unused]] std::string_view fmt,
[[maybe_unused]] Args&&... args) {
TEST_VALIDATE_EXCEPTION(
std::format_error,
[&]([[maybe_unused]] const std::format_error& e) {
TEST_LIBCPP_REQUIRE(
e.what() == what,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt, "\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
},
[&] {
std::stringstream sstr;
std::vprint_unicode(sstr, fmt, std::make_format_args(args...));
}());
};
// [ostream.formatted.print]/3.2
// ...
// After constructing a sentry object, the function initializes an automatic variable via
// string out = vformat(os.getloc(), fmt, args);
// This means if both
// - creating a sentry fails
// - the formatting fails
// the first one "wins" and the format_error is not thrown.
static void test_sentry_failure() {
// In order for the creation of a sentry to fail a tied stream's
// sync operation should fail.
struct sync_failure : public std::basic_streambuf<char> {
protected:
int virtual sync() { return -1; }
};
sync_failure buf_tied;
std::ostream os_tied(&buf_tied);
os_tied.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
std::stringstream os;
os.tie(&os_tied);
os.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
[[maybe_unused]] int arg = -10;
TEST_THROWS_TYPE(std::ios_base::failure, std::vprint_unicode(os, "valid", std::make_format_args()));
os_tied.clear();
TEST_THROWS_TYPE(std::ios_base::failure,
std::vprint_unicode(os, "throws exception at run-time {0:{0}}", std::make_format_args(arg)));
os.exceptions(std::stringstream::goodbit);
os.setstate(std::stringstream::failbit);
std::vprint_unicode(
os, "not called when the os.good() is false, so no exception is thrown {0:{0}}", std::make_format_args(arg));
}
// [ostream.formatted.print]/3.2
// any exception thrown by the call to vformat is propagated without
// regard to the value of os.exceptions() and without turning on
// ios_base::badbit in the error state of os.
// Most invalid format strings are checked at compile-time. An invalid
// value for the width can only be tested run-time.
static void test_format_exception() {
std::stringstream sstr;
assert(sstr.good());
[[maybe_unused]] int arg = -10;
TEST_THROWS_TYPE(std::format_error, std::vprint_unicode(sstr, "no output {0:{0}}", std::make_format_args(arg)));
assert(sstr.good());
assert(sstr.str().empty());
sstr.exceptions(std::stringstream::goodbit);
TEST_THROWS_TYPE(std::format_error, std::vprint_unicode(sstr, "no output {0:{0}}", std::make_format_args(arg)));
assert(sstr.good());
assert(sstr.str().empty());
sstr.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::format_error, std::vprint_unicode(sstr, "no output {0:{0}}", std::make_format_args(arg)));
assert(sstr.good());
assert(sstr.str().empty());
}
static void test_write_failure() {
// Stream that fails to write a single character.
struct overflow_failure : public std::basic_streambuf<char> {
protected:
int virtual overflow(int) { return std::char_traits<char>::eof(); }
};
overflow_failure buf;
std::ostream os(&buf);
os.exceptions(std::stringstream::failbit | std::stringstream::badbit | std::stringstream::eofbit);
TEST_THROWS_TYPE(std::ios_base::failure, std::vprint_unicode(os, "valid", std::make_format_args()));
os.clear();
// When the parser would directly write to the output instead of
// formatting first it would fail writing the first character 't' of
// the string and result in a std::ios_base::failure exception.
[[maybe_unused]] int arg = -10;
TEST_THROWS_TYPE(
std::format_error, std::vprint_unicode(os, "throws exception at run-time {0:{0}}", std::make_format_args(arg)));
os.exceptions(std::stringstream::goodbit);
os.clear();
std::vprint_unicode(os, "valid", std::make_format_args());
assert(os.fail());
}
static void test_stream_formatting() {
std::stringstream sstr;
auto test = [&]<class... Args>(std::string_view expected, test_format_string<char, Args...> fmt, Args&&... args) {
sstr.str("");
std::vprint_unicode(sstr, fmt.get(), std::make_format_args(args...));
std::string out = sstr.str();
TEST_REQUIRE(out == expected,
TEST_WRITE_CONCATENATED(
"\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
};
test("hello", "{}", "hello");
sstr.width(10);
test(" hello", "{}", "hello");
sstr.fill('+');
sstr.width(10);
test("+++++hello", "{}", "hello");
// *** Test embedded NUL character ***
using namespace std::literals;
sstr.width(15);
test("++++hello\0world"sv, "hello{}{}", '\0', "world");
// *** Test Unicode ***
// Streams count code units not code points
// 2-byte code points
sstr.width(5);
test("+++\u00a1", "{}", "\u00a1"); // INVERTED EXCLAMATION MARK
sstr.width(5);
test("+++\u07ff", "{}", "\u07ff"); // NKO TAMAN SIGN
// 3-byte code points
sstr.width(5);
test("++\u0800", "{}", "\u0800"); // SAMARITAN LETTER ALAF
sstr.width(5);
test("++\ufffd", "{}", "\ufffd"); // REPLACEMENT CHARACTER
// 4-byte code points
sstr.width(5);
test("+\U00010000", "{}", "\U00010000"); // LINEAR B SYLLABLE B008 A
sstr.width(5);
test("+\U0010FFFF", "{}", "\U0010FFFF"); // Undefined Character
}
int main(int, char**) {
print_tests(test_file, test_exception);
test_sentry_failure();
test_format_exception();
test_write_failure();
test_stream_formatting();
return 0;
}

View File

@@ -89,17 +89,11 @@
# endif
# endif
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++23"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++23"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_print
# error "__cpp_lib_print should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++23"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++23"
# endif
#elif TEST_STD_VER > 23
@@ -117,17 +111,11 @@
# endif
# endif
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++26"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_print
# error "__cpp_lib_print should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++26"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++26"
# endif
#endif // TEST_STD_VER > 23

View File

@@ -50,32 +50,20 @@
#elif TEST_STD_VER == 23
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++23"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++23"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_print
# error "__cpp_lib_print should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++23"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++23"
# endif
#elif TEST_STD_VER > 23
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++26"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_print
# error "__cpp_lib_print should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++26"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++26"
# endif
#endif // TEST_STD_VER > 23

View File

@@ -5243,17 +5243,11 @@
# endif
# endif
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++23"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++23"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_print
# error "__cpp_lib_print should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++23"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++23"
# endif
# ifndef __cpp_lib_quoted_string_io
@@ -6950,17 +6944,11 @@
# endif
# endif
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++26"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++26"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_print
# error "__cpp_lib_print should not be defined because it is unimplemented in libc++!"
# endif
# ifndef __cpp_lib_print
# error "__cpp_lib_print should be defined in c++26"
# endif
# if __cpp_lib_print != 202207L
# error "__cpp_lib_print should have the value 202207L in c++26"
# endif
# ifndef __cpp_lib_quoted_string_io

View File

@@ -875,7 +875,6 @@ feature_test_macros = [
"name": "__cpp_lib_print",
"values": {"c++23": 202207},
"headers": ["ostream", "print"],
"unimplemented": True,
},
{
"name": "__cpp_lib_quoted_string_io",

View File

@@ -586,4 +586,13 @@ DEFAULT_FEATURES += [
cfg.available_features,
),
),
# Tests that require support for <print> and std::print in <ostream> in the built library.
Feature(
name="availability-print-missing",
when=lambda cfg: BooleanExpression.evaluate(
# TODO(ldionne) Please provide the correct value.
"stdlib=apple-libc++ && target={{.+}}-apple-macosx{{(10.9|10.10|10.11|10.12|10.13|10.14|10.15|11.0|12.0|13.0)(.0)?}}",
cfg.available_features,
),
),
]