[libcxx-commits] [libcxx] [libc++][print] Adds ostream overloads. (PR #73262)
Mark de Wever via libcxx-commits
libcxx-commits at lists.llvm.org
Sat Dec 16 04:38:19 PST 2023
https://github.com/mordante updated https://github.com/llvm/llvm-project/pull/73262
>From c0c15902b2cd0dc6d41e22210ae13fea298c6348 Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sun, 23 Jul 2023 14:49:12 +0200
Subject: [PATCH 1/2] [libc++][print] Adds ostream overloads.
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
---
libcxx/docs/FeatureTestMacroTable.rst | 2 +-
libcxx/docs/ImplementationDefinedBehavior.rst | 23 +
libcxx/docs/ReleaseNotes/18.rst | 2 +
libcxx/docs/Status/Cxx23Papers.csv | 4 +-
libcxx/docs/Status/FormatIssues.csv | 4 +-
libcxx/docs/Status/FormatPaper.csv | 2 +-
libcxx/include/__availability | 9 +
libcxx/include/fstream | 2 +
libcxx/include/ostream | 148 ++
libcxx/include/print | 6 +-
libcxx/include/version | 2 +-
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...bcxxabi.v1.stable.exceptions.nonew.abilist | 3 +-
...bcxxabi.v1.stable.exceptions.nonew.abilist | 1 +
...xxabi.v1.stable.noexceptions.nonew.abilist | 1 +
libcxx/modules/std/ostream.inc | 5 +-
libcxx/src/CMakeLists.txt | 1 +
libcxx/src/ostream.cpp | 42 +
libcxx/src/std_stream.h | 4 +-
.../vprint_unicode.pass.cpp | 165 ++
.../test/libcxx/transitive_includes/cxx03.csv | 11 +-
.../test/libcxx/transitive_includes/cxx11.csv | 11 +-
.../test/libcxx/transitive_includes/cxx14.csv | 11 +-
.../test/libcxx/transitive_includes/cxx17.csv | 11 +-
.../test/libcxx/transitive_includes/cxx20.csv | 11 +-
.../test/libcxx/transitive_includes/cxx23.csv | 12 +-
.../test/libcxx/transitive_includes/cxx26.csv | 12 +-
.../locale-specific_form.pass.cpp | 2200 +++++++++++++++++
.../ostream.formatted.print/print.pass.cpp | 193 ++
.../ostream.formatted.print/print_tests.h | 83 +
.../ostream.formatted.print/println.pass.cpp | 63 +
.../vprint_nonunicode.pass.cpp | 198 ++
.../vprint_unicode.pass.cpp | 197 ++
.../ostream.version.compile.pass.cpp | 32 +-
.../print.version.compile.pass.cpp | 32 +-
.../version.version.compile.pass.cpp | 32 +-
.../generate_feature_test_macro_components.py | 1 -
libcxx/utils/libcxx/test/features.py | 11 +
41 files changed, 3444 insertions(+), 107 deletions(-)
create mode 100644 libcxx/src/ostream.cpp
create mode 100644 libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h
create mode 100644 libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp
create mode 100644 libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst
index d09f65b7cadc0e..ad12b109023154 100644
--- a/libcxx/docs/FeatureTestMacroTable.rst
+++ b/libcxx/docs/FeatureTestMacroTable.rst
@@ -344,7 +344,7 @@ Status
--------------------------------------------------- -----------------
``__cpp_lib_out_ptr`` *unimplemented*
--------------------------------------------------- -----------------
- ``__cpp_lib_print`` *unimplemented*
+ ``__cpp_lib_print`` ``202207L``
--------------------------------------------------- -----------------
``__cpp_lib_ranges_as_const`` *unimplemented*
--------------------------------------------------- -----------------
diff --git a/libcxx/docs/ImplementationDefinedBehavior.rst b/libcxx/docs/ImplementationDefinedBehavior.rst
index c1f13d7f1cf160..3000bb7cfa4680 100644
--- a/libcxx/docs/ImplementationDefinedBehavior.rst
+++ b/libcxx/docs/ImplementationDefinedBehavior.rst
@@ -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
======================================================
diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst
index 9e509db6359c4a..79608c631f1e62 100644
--- a/libcxx/docs/ReleaseNotes/18.rst
+++ b/libcxx/docs/ReleaseNotes/18.rst
@@ -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``
diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv
index e03cbff2a08bbf..b1fae06e74b5c7 100644
--- a/libcxx/docs/Status/Cxx23Papers.csv
+++ b/libcxx/docs/Status/Cxx23Papers.csv
@@ -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|","",""
"","","","","","",""
diff --git a/libcxx/docs/Status/FormatIssues.csv b/libcxx/docs/Status/FormatIssues.csv
index efb3e484f357e7..513988d08036ca 100644
--- a/libcxx/docs/Status/FormatIssues.csv
+++ b/libcxx/docs/Status/FormatIssues.csv
@@ -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
diff --git a/libcxx/docs/Status/FormatPaper.csv b/libcxx/docs/Status/FormatPaper.csv
index 0acde337ccafe1..82da54284c7386 100644
--- a/libcxx/docs/Status/FormatPaper.csv
+++ b/libcxx/docs/Status/FormatPaper.csv
@@ -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
diff --git a/libcxx/include/__availability b/libcxx/include/__availability
index b5230b3f56b8d8..e51e324e2b56aa 100644
--- a/libcxx/include/__availability
+++ b/libcxx/include/__availability
@@ -139,6 +139,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.
@@ -262,6 +268,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) || \
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 468ff42dc9bc12..812225d549eab6 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -256,6 +256,8 @@ public:
inline static const char*
__make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
+ _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI FILE* __file() { return __file_; }
+
protected:
// 27.9.1.5 Overridden virtual functions:
int_type underflow() override;
diff --git a/libcxx/include/ostream b/libcxx/include/ostream
index ef74f5ddc66c70..5c5c30de006857 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -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)
@@ -1195,6 +1209,140 @@ 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::sentry __s(__os);
+ if (__s) {
+ string __o = 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 _WIN32
+ __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
diff --git a/libcxx/include/print b/libcxx/include/print
index d119c8bda74976..2174557794e4df 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -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(_WIN32)
return std::__is_windows_terminal(__stream);
# elif __has_include(<unistd.h>)
return isatty(fileno(__stream));
diff --git a/libcxx/include/version b/libcxx/include/version
index a91c344c436090..a463ce575912ba 100644
--- a/libcxx/include/version
+++ b/libcxx/include/version
@@ -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
diff --git a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 8daad89f52e6f7..b51af1bb0f9ef2 100644
--- a/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/arm64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 91976f500539da..55987d4c913bbe 100644
--- a/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
index 8a98d42a2a1aa0..d861d890861bf6 100644
--- a/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/powerpc64-ibm-aix.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
index 0c06b5097b83f8..ce0a2e354d6d23 100644
--- a/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-apple-darwin.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
index 16658fdff54932..f55dffc3120905 100644
--- a/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-freebsd.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
\ No newline at end of file
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
index 49e3579614ee8c..74408ca930c904 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.exceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
index 764e7c37daacb7..618d2968d1a642 100644
--- a/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
+++ b/libcxx/lib/abi/x86_64-unknown-linux-gnu.libcxxabi.v1.stable.noexceptions.nonew.abilist
@@ -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'}
diff --git a/libcxx/modules/std/ostream.inc b/libcxx/modules/std/ostream.inc
index e8989788b7a544..8fcbfb4bdc1828 100644
--- a/libcxx/modules/std/ostream.inc
+++ b/libcxx/modules/std/ostream.inc
@@ -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
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index be0113e6b0a585..329964a001363b 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -89,6 +89,7 @@ if (LIBCXX_ENABLE_LOCALIZATION)
ios.instantiations.cpp
iostream.cpp
locale.cpp
+ ostream.cpp
regex.cpp
strstream.cpp
)
diff --git a/libcxx/src/ostream.cpp b/libcxx/src/ostream.cpp
new file mode 100644
index 00000000000000..b91cb57d607caa
--- /dev/null
+++ b/libcxx/src/ostream.cpp
@@ -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 why build with RTTI
+ // disabled with a dylib with RTTI enabled.
+ //
+ // Not returning a FILE* 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
diff --git a/libcxx/src/std_stream.h b/libcxx/src/std_stream.h
index 39a2b70b4f47fd..21388e19a9656a 100644
--- a/libcxx/src/std_stream.h
+++ b/libcxx/src/std_stream.h
@@ -286,7 +286,9 @@ class _LIBCPP_HIDDEN __stdoutbuf
__stdoutbuf(FILE* __fp, state_type* __st);
-protected:
+ [[nodiscard]] FILE* __file() { return __file_; }
+
+ protected:
virtual int_type overflow (int_type __c = traits_type::eof());
virtual streamsize xsputn(const char_type* __s, streamsize __n);
virtual int sync();
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
new file mode 100644
index 00000000000000..6243b250dec393
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -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
+// 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 the 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"
+
+#include <print> // TODO REMOVE
+
+scoped_test_env env;
+std::string filename = env.create_file("output.txt");
+
+int is_terminal_calls = 0;
+bool should_call_is_terminal = false;
+bool is_terminal_result = false;
+bool is_terminal(FILE*) {
+ ++is_terminal_calls;
+ assert(should_call_is_terminal);
+ return is_terminal_result;
+}
+
+static void test_is_terminal_not_a_file_stream() {
+ is_terminal_calls = 0;
+ should_call_is_terminal = false;
+ is_terminal_result = false;
+ {
+ std::stringstream stream;
+ std::print(stream, "test");
+ }
+ {
+ std::ostringstream stream;
+ std::print(stream, "test");
+ }
+ assert(is_terminal_calls == 0);
+}
+
+static void test_is_terminal_file_stream() {
+ is_terminal_calls = 0;
+ should_call_is_terminal = true;
+ 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);
+ }
+}
+
+static void test_is_terminal_rdbuf_derived_from_filebuf() {
+ struct my_filebuf : public std::filebuf {};
+
+ is_terminal_calls = 0;
+ should_call_is_terminal = true;
+ 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);
+}
+
+static void test_is_terminal_std_cout_cerr_clog() {
+ is_terminal_calls = 0;
+ should_call_is_terminal = true;
+ 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);
+ }
+}
+
+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();
+ }
+ };
+
+ should_call_is_terminal = true;
+ 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;
+}
diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv
index 7066de65a91372..3f066342717624 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx03.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv
@@ -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
diff --git a/libcxx/test/libcxx/transitive_includes/cxx11.csv b/libcxx/test/libcxx/transitive_includes/cxx11.csv
index c4dc664d6ca817..7b443e5a0ec0f9 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx11.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv
@@ -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
diff --git a/libcxx/test/libcxx/transitive_includes/cxx14.csv b/libcxx/test/libcxx/transitive_includes/cxx14.csv
index 20ee43722d894b..a5b77ec79bb5c3 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx14.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv
@@ -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
diff --git a/libcxx/test/libcxx/transitive_includes/cxx17.csv b/libcxx/test/libcxx/transitive_includes/cxx17.csv
index 20ee43722d894b..a5b77ec79bb5c3 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx17.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv
@@ -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
diff --git a/libcxx/test/libcxx/transitive_includes/cxx20.csv b/libcxx/test/libcxx/transitive_includes/cxx20.csv
index d256370aac4a4a..c8c84867fda459 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx20.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv
@@ -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
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 9edc283236480e..a4fa50dc014aba 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -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
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 9edc283236480e..a4fa50dc014aba 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -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
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp
new file mode 100644
index 00000000000000..7e1156acf8335b
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/locale-specific_form.pass.cpp
@@ -0,0 +1,2200 @@
+//===----------------------------------------------------------------------===//
+// 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-localization
+// 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
+
+// Bionic has minimal locale support, investigate this later.
+// XFAIL: LIBCXX-ANDROID-FIXME
+
+// REQUIRES: locale.en_US.UTF-8
+
+// <format>
+
+// This test checks the locale-specific form for these print functions:
+// template<class... Args>
+// void print(ostream& os, format_string<Args...> fmt, Args&&... args);
+// template<class... Args>
+// void println(ostream& os, format_string<Args...> fmt, Args&&... args);
+//
+// void vprint_unicode(ostream& os, string_view fmt, format_args args);
+// void vprint_nonunicode(ostream& os, string_view fmt, format_args args);
+
+#include <cassert>
+#include <ostream>
+
+#include "test_macros.h"
+#include "make_string.h"
+#include "platform_support.h" // locale name macros
+#include "test_format_string.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+template <class CharT>
+struct numpunct;
+
+template <>
+struct numpunct<char> : std::numpunct<char> {
+ string_type do_truename() const override { return "yes"; }
+ string_type do_falsename() const override { return "no"; }
+
+ std::string do_grouping() const override { return "\1\2\3\2\1"; };
+ char do_thousands_sep() const override { return '_'; }
+ char do_decimal_point() const override { return '#'; }
+};
+
+template <class... Args>
+static void
+test(std::stringstream& stream, std::string expected, test_format_string<char, Args...> fmt, Args&&... args) {
+ // *** print ***
+ {
+ std::print(stream, fmt, std::forward<Args>(args)...);
+ std::string out = stream.str();
+ TEST_REQUIRE(out == expected,
+ TEST_WRITE_CONCATENATED(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
+ }
+ // *** vprint_unicode ***
+ {
+ stream.str("");
+ ;
+ std::vprint_unicode(stream, fmt.get(), std::make_format_args(args...));
+ std::string out = stream.str();
+ TEST_REQUIRE(out == expected,
+ TEST_WRITE_CONCATENATED(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
+ }
+ // *** vprint_nonunicode ***
+ {
+ stream.str("");
+ ;
+ std::vprint_nonunicode(stream, fmt.get(), std::make_format_args(args...));
+ std::string out = stream.str();
+ TEST_REQUIRE(out == expected,
+ TEST_WRITE_CONCATENATED(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
+ }
+ // *** println ***
+ {
+ expected += '\n'; // Tested last since it changes the expected value.
+ stream.str("");
+ ;
+ std::println(stream, fmt, std::forward<Args>(args)...);
+ std::string out = stream.str();
+ TEST_REQUIRE(out == expected,
+ TEST_WRITE_CONCATENATED(
+ "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n'));
+ }
+}
+
+template <class... Args>
+static void test(std::string expected, test_format_string<char, Args...> fmt, Args&&... args) {
+ std::stringstream stream;
+ test(stream, std::move(expected), fmt, std::forward<Args>(args)...);
+}
+
+template <class... Args>
+static void test(std::string expected, std::locale loc, test_format_string<char, Args...> fmt, Args&&... args) {
+ std::stringstream stream;
+ stream.imbue(loc);
+ test(stream, std::move(expected), fmt, std::forward<Args>(args)...);
+}
+
+#ifndef TEST_HAS_NO_UNICODE
+struct numpunct_unicode : std::numpunct<char> {
+ string_type do_truename() const override { return "gültig"; }
+ string_type do_falsename() const override { return "ungültig"; }
+};
+
+#endif // TEST_HAS_NO_UNICODE
+
+static void test_bool() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+
+ std::locale::global(std::locale(LOCALE_en_US_UTF_8));
+ assert(std::locale().name() == LOCALE_en_US_UTF_8);
+ test("true", "{:L}", true);
+ test("false", "{:L}", false);
+
+ test("yes", loc, "{:L}", true);
+ test("no", loc, "{:L}", false);
+
+ std::locale::global(loc);
+ test("yes", "{:L}", true);
+ test("no", "{:L}", false);
+
+ test("true", std::locale(LOCALE_en_US_UTF_8), "{:L}", true);
+ test("false", std::locale(LOCALE_en_US_UTF_8), "{:L}", false);
+
+#ifndef TEST_HAS_NO_UNICODE
+ std::locale loc_unicode = std::locale(std::locale(), new numpunct_unicode());
+
+ test("gültig", loc_unicode, "{:L}", true);
+ test("ungültig", loc_unicode, "{:L}", false);
+
+ test("gültig ", loc_unicode, "{:9L}", true);
+ test("gültig!!!", loc_unicode, "{:!<9L}", true);
+ test("_gültig__", loc_unicode, "{:_^9L}", true);
+ test(" gültig", loc_unicode, "{:>9L}", true);
+#endif // TEST_HAS_NO_UNICODE
+}
+
+static void test_integer() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Decimal ***
+ std::locale::global(en_US);
+ test("0", "{:L}", 0);
+ test("1", "{:L}", 1);
+ test("10", "{:L}", 10);
+ test("100", "{:L}", 100);
+ test("1,000", "{:L}", 1'000);
+ test("10,000", "{:L}", 10'000);
+ test("100,000", "{:L}", 100'000);
+ test("1,000,000", "{:L}", 1'000'000);
+ test("10,000,000", "{:L}", 10'000'000);
+ test("100,000,000", "{:L}", 100'000'000);
+ test("1,000,000,000", "{:L}", 1'000'000'000);
+
+ test("-1", "{:L}", -1);
+ test("-10", "{:L}", -10);
+ test("-100", "{:L}", -100);
+ test("-1,000", "{:L}", -1'000);
+ test("-10,000", "{:L}", -10'000);
+ test("-100,000", "{:L}", -100'000);
+ test("-1,000,000", "{:L}", -1'000'000);
+ test("-10,000,000", "{:L}", -10'000'000);
+ test("-100,000,000", "{:L}", -100'000'000);
+ test("-1,000,000,000", "{:L}", -1'000'000'000);
+
+ std::locale::global(loc);
+ test("0", "{:L}", 0);
+ test("1", "{:L}", 1);
+ test("1_0", "{:L}", 10);
+ test("10_0", "{:L}", 100);
+ test("1_00_0", "{:L}", 1'000);
+ test("10_00_0", "{:L}", 10'000);
+ test("100_00_0", "{:L}", 100'000);
+ test("1_000_00_0", "{:L}", 1'000'000);
+ test("10_000_00_0", "{:L}", 10'000'000);
+ test("1_00_000_00_0", "{:L}", 100'000'000);
+ test("1_0_00_000_00_0", "{:L}", 1'000'000'000);
+
+ test("-1", "{:L}", -1);
+ test("-1_0", "{:L}", -10);
+ test("-10_0", "{:L}", -100);
+ test("-1_00_0", "{:L}", -1'000);
+ test("-10_00_0", "{:L}", -10'000);
+ test("-100_00_0", "{:L}", -100'000);
+ test("-1_000_00_0", "{:L}", -1'000'000);
+ test("-10_000_00_0", "{:L}", -10'000'000);
+ test("-1_00_000_00_0", "{:L}", -100'000'000);
+ test("-1_0_00_000_00_0", "{:L}", -1'000'000'000);
+
+ test("0", en_US, "{:L}", 0);
+ test("1", en_US, "{:L}", 1);
+ test("10", en_US, "{:L}", 10);
+ test("100", en_US, "{:L}", 100);
+ test("1,000", en_US, "{:L}", 1'000);
+ test("10,000", en_US, "{:L}", 10'000);
+ test("100,000", en_US, "{:L}", 100'000);
+ test("1,000,000", en_US, "{:L}", 1'000'000);
+ test("10,000,000", en_US, "{:L}", 10'000'000);
+ test("100,000,000", en_US, "{:L}", 100'000'000);
+ test("1,000,000,000", en_US, "{:L}", 1'000'000'000);
+
+ test("-1", en_US, "{:L}", -1);
+ test("-10", en_US, "{:L}", -10);
+ test("-100", en_US, "{:L}", -100);
+ test("-1,000", en_US, "{:L}", -1'000);
+ test("-10,000", en_US, "{:L}", -10'000);
+ test("-100,000", en_US, "{:L}", -100'000);
+ test("-1,000,000", en_US, "{:L}", -1'000'000);
+ test("-10,000,000", en_US, "{:L}", -10'000'000);
+ test("-100,000,000", en_US, "{:L}", -100'000'000);
+ test("-1,000,000,000", en_US, "{:L}", -1'000'000'000);
+
+ std::locale::global(en_US);
+ test("0", loc, "{:L}", 0);
+ test("1", loc, "{:L}", 1);
+ test("1_0", loc, "{:L}", 10);
+ test("10_0", loc, "{:L}", 100);
+ test("1_00_0", loc, "{:L}", 1'000);
+ test("10_00_0", loc, "{:L}", 10'000);
+ test("100_00_0", loc, "{:L}", 100'000);
+ test("1_000_00_0", loc, "{:L}", 1'000'000);
+ test("10_000_00_0", loc, "{:L}", 10'000'000);
+ test("1_00_000_00_0", loc, "{:L}", 100'000'000);
+ test("1_0_00_000_00_0", loc, "{:L}", 1'000'000'000);
+
+ test("-1", loc, "{:L}", -1);
+ test("-1_0", loc, "{:L}", -10);
+ test("-10_0", loc, "{:L}", -100);
+ test("-1_00_0", loc, "{:L}", -1'000);
+ test("-10_00_0", loc, "{:L}", -10'000);
+ test("-100_00_0", loc, "{:L}", -100'000);
+ test("-1_000_00_0", loc, "{:L}", -1'000'000);
+ test("-10_000_00_0", loc, "{:L}", -10'000'000);
+ test("-1_00_000_00_0", loc, "{:L}", -100'000'000);
+ test("-1_0_00_000_00_0", loc, "{:L}", -1'000'000'000);
+
+ // *** Binary ***
+ std::locale::global(en_US);
+ test("0", "{:Lb}", 0b0);
+ test("1", "{:Lb}", 0b1);
+ test("1,000,000,000", "{:Lb}", 0b1'000'000'000);
+
+ test("0b0", "{:#Lb}", 0b0);
+ test("0b1", "{:#Lb}", 0b1);
+ test("0b1,000,000,000", "{:#Lb}", 0b1'000'000'000);
+
+ test("-1", "{:LB}", -0b1);
+ test("-1,000,000,000", "{:LB}", -0b1'000'000'000);
+
+ test("-0B1", "{:#LB}", -0b1);
+ test("-0B1,000,000,000", "{:#LB}", -0b1'000'000'000);
+
+ std::locale::global(loc);
+ test("0", "{:Lb}", 0b0);
+ test("1", "{:Lb}", 0b1);
+ test("1_0_00_000_00_0", "{:Lb}", 0b1'000'000'000);
+
+ test("0b0", "{:#Lb}", 0b0);
+ test("0b1", "{:#Lb}", 0b1);
+ test("0b1_0_00_000_00_0", "{:#Lb}", 0b1'000'000'000);
+
+ test("-1", "{:LB}", -0b1);
+ test("-1_0_00_000_00_0", "{:LB}", -0b1'000'000'000);
+
+ test("-0B1", "{:#LB}", -0b1);
+ test("-0B1_0_00_000_00_0", "{:#LB}", -0b1'000'000'000);
+
+ test("0", en_US, "{:Lb}", 0b0);
+ test("1", en_US, "{:Lb}", 0b1);
+ test("1,000,000,000", en_US, "{:Lb}", 0b1'000'000'000);
+
+ test("0b0", en_US, "{:#Lb}", 0b0);
+ test("0b1", en_US, "{:#Lb}", 0b1);
+ test("0b1,000,000,000", en_US, "{:#Lb}", 0b1'000'000'000);
+
+ test("-1", en_US, "{:LB}", -0b1);
+ test("-1,000,000,000", en_US, "{:LB}", -0b1'000'000'000);
+
+ test("-0B1", en_US, "{:#LB}", -0b1);
+ test("-0B1,000,000,000", en_US, "{:#LB}", -0b1'000'000'000);
+
+ std::locale::global(en_US);
+ test("0", loc, "{:Lb}", 0b0);
+ test("1", loc, "{:Lb}", 0b1);
+ test("1_0_00_000_00_0", loc, "{:Lb}", 0b1'000'000'000);
+
+ test("0b0", loc, "{:#Lb}", 0b0);
+ test("0b1", loc, "{:#Lb}", 0b1);
+ test("0b1_0_00_000_00_0", loc, "{:#Lb}", 0b1'000'000'000);
+
+ test("-1", loc, "{:LB}", -0b1);
+ test("-1_0_00_000_00_0", loc, "{:LB}", -0b1'000'000'000);
+
+ test("-0B1", loc, "{:#LB}", -0b1);
+ test("-0B1_0_00_000_00_0", loc, "{:#LB}", -0b1'000'000'000);
+
+ // *** Octal ***
+ std::locale::global(en_US);
+ test("0", "{:Lo}", 00);
+ test("1", "{:Lo}", 01);
+ test("1,000,000,000", "{:Lo}", 01'000'000'000);
+
+ test("0", "{:#Lo}", 00);
+ test("01", "{:#Lo}", 01);
+ test("01,000,000,000", "{:#Lo}", 01'000'000'000);
+
+ test("-1", "{:Lo}", -01);
+ test("-1,000,000,000", "{:Lo}", -01'000'000'000);
+
+ test("-01", "{:#Lo}", -01);
+ test("-01,000,000,000", "{:#Lo}", -01'000'000'000);
+
+ std::locale::global(loc);
+ test("0", "{:Lo}", 00);
+ test("1", "{:Lo}", 01);
+ test("1_0_00_000_00_0", "{:Lo}", 01'000'000'000);
+
+ test("0", "{:#Lo}", 00);
+ test("01", "{:#Lo}", 01);
+ test("01_0_00_000_00_0", "{:#Lo}", 01'000'000'000);
+
+ test("-1", "{:Lo}", -01);
+ test("-1_0_00_000_00_0", "{:Lo}", -01'000'000'000);
+
+ test("-01", "{:#Lo}", -01);
+ test("-01_0_00_000_00_0", "{:#Lo}", -01'000'000'000);
+
+ test("0", en_US, "{:Lo}", 00);
+ test("1", en_US, "{:Lo}", 01);
+ test("1,000,000,000", en_US, "{:Lo}", 01'000'000'000);
+
+ test("0", en_US, "{:#Lo}", 00);
+ test("01", en_US, "{:#Lo}", 01);
+ test("01,000,000,000", en_US, "{:#Lo}", 01'000'000'000);
+
+ test("-1", en_US, "{:Lo}", -01);
+ test("-1,000,000,000", en_US, "{:Lo}", -01'000'000'000);
+
+ test("-01", en_US, "{:#Lo}", -01);
+ test("-01,000,000,000", en_US, "{:#Lo}", -01'000'000'000);
+
+ std::locale::global(en_US);
+ test("0", loc, "{:Lo}", 00);
+ test("1", loc, "{:Lo}", 01);
+ test("1_0_00_000_00_0", loc, "{:Lo}", 01'000'000'000);
+
+ test("0", loc, "{:#Lo}", 00);
+ test("01", loc, "{:#Lo}", 01);
+ test("01_0_00_000_00_0", loc, "{:#Lo}", 01'000'000'000);
+
+ test("-1", loc, "{:Lo}", -01);
+ test("-1_0_00_000_00_0", loc, "{:Lo}", -01'000'000'000);
+
+ test("-01", loc, "{:#Lo}", -01);
+ test("-01_0_00_000_00_0", loc, "{:#Lo}", -01'000'000'000);
+
+ // *** Hexadecimal ***
+ std::locale::global(en_US);
+ test("0", "{:Lx}", 0x0);
+ test("1", "{:Lx}", 0x1);
+ test("1,000,000,000", "{:Lx}", 0x1'000'000'000);
+
+ test("0x0", "{:#Lx}", 0x0);
+ test("0x1", "{:#Lx}", 0x1);
+ test("0x1,000,000,000", "{:#Lx}", 0x1'000'000'000);
+
+ test("-1", "{:LX}", -0x1);
+ test("-1,000,000,000", "{:LX}", -0x1'000'000'000);
+
+ test("-0X1", "{:#LX}", -0x1);
+ test("-0X1,000,000,000", "{:#LX}", -0x1'000'000'000);
+
+ std::locale::global(loc);
+ test("0", "{:Lx}", 0x0);
+ test("1", "{:Lx}", 0x1);
+ test("1_0_00_000_00_0", "{:Lx}", 0x1'000'000'000);
+
+ test("0x0", "{:#Lx}", 0x0);
+ test("0x1", "{:#Lx}", 0x1);
+ test("0x1_0_00_000_00_0", "{:#Lx}", 0x1'000'000'000);
+
+ test("-1", "{:LX}", -0x1);
+ test("-1_0_00_000_00_0", "{:LX}", -0x1'000'000'000);
+
+ test("-0X1", "{:#LX}", -0x1);
+ test("-0X1_0_00_000_00_0", "{:#LX}", -0x1'000'000'000);
+
+ test("0", en_US, "{:Lx}", 0x0);
+ test("1", en_US, "{:Lx}", 0x1);
+ test("1,000,000,000", en_US, "{:Lx}", 0x1'000'000'000);
+
+ test("0x0", en_US, "{:#Lx}", 0x0);
+ test("0x1", en_US, "{:#Lx}", 0x1);
+ test("0x1,000,000,000", en_US, "{:#Lx}", 0x1'000'000'000);
+
+ test("-1", en_US, "{:LX}", -0x1);
+ test("-1,000,000,000", en_US, "{:LX}", -0x1'000'000'000);
+
+ test("-0X1", en_US, "{:#LX}", -0x1);
+ test("-0X1,000,000,000", en_US, "{:#LX}", -0x1'000'000'000);
+
+ std::locale::global(en_US);
+ test("0", loc, "{:Lx}", 0x0);
+ test("1", loc, "{:Lx}", 0x1);
+ test("1_0_00_000_00_0", loc, "{:Lx}", 0x1'000'000'000);
+
+ test("0x0", loc, "{:#Lx}", 0x0);
+ test("0x1", loc, "{:#Lx}", 0x1);
+ test("0x1_0_00_000_00_0", loc, "{:#Lx}", 0x1'000'000'000);
+
+ test("-1", loc, "{:LX}", -0x1);
+ test("-1_0_00_000_00_0", loc, "{:LX}", -0x1'000'000'000);
+
+ test("-0X1", loc, "{:#LX}", -0x1);
+ test("-0X1_0_00_000_00_0", loc, "{:#LX}", -0x1'000'000'000);
+
+ // *** align-fill & width ***
+ test("4_2", loc, "{:L}", 42);
+
+ test(" 4_2", loc, "{:6L}", 42);
+ test("4_2 ", loc, "{:<6L}", 42);
+ test(" 4_2 ", loc, "{:^6L}", 42);
+ test(" 4_2", loc, "{:>6L}", 42);
+
+ test("4_2***", loc, "{:*<6L}", 42);
+ test("*4_2**", loc, "{:*^6L}", 42);
+ test("***4_2", loc, "{:*>6L}", 42);
+
+ test("4_a*****", loc, "{:*<8Lx}", 0x4a);
+ test("**4_a***", loc, "{:*^8Lx}", 0x4a);
+ test("*****4_a", loc, "{:*>8Lx}", 0x4a);
+
+ test("0x4_a***", loc, "{:*<#8Lx}", 0x4a);
+ test("*0x4_a**", loc, "{:*^#8Lx}", 0x4a);
+ test("***0x4_a", loc, "{:*>#8Lx}", 0x4a);
+
+ test("4_A*****", loc, "{:*<8LX}", 0x4a);
+ test("**4_A***", loc, "{:*^8LX}", 0x4a);
+ test("*****4_A", loc, "{:*>8LX}", 0x4a);
+
+ test("0X4_A***", loc, "{:*<#8LX}", 0x4a);
+ test("*0X4_A**", loc, "{:*^#8LX}", 0x4a);
+ test("***0X4_A", loc, "{:*>#8LX}", 0x4a);
+
+ // Test whether zero padding is ignored
+ test("4_2 ", loc, "{:<06L}", 42);
+ test(" 4_2 ", loc, "{:^06L}", 42);
+ test(" 4_2", loc, "{:>06L}", 42);
+
+ // *** zero-padding & width ***
+ test(" 4_2", loc, "{:6L}", 42);
+ test("0004_2", loc, "{:06L}", 42);
+ test("-004_2", loc, "{:06L}", -42);
+
+ test("000004_a", loc, "{:08Lx}", 0x4a);
+ test("0x0004_a", loc, "{:#08Lx}", 0x4a);
+ test("0X0004_A", loc, "{:#08LX}", 0x4a);
+
+ test("-00004_a", loc, "{:08Lx}", -0x4a);
+ test("-0x004_a", loc, "{:#08Lx}", -0x4a);
+ test("-0X004_A", loc, "{:#08LX}", -0x4a);
+}
+
+template <class F>
+static void test_floating_point_hex_lower_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.23456p-3", "{:La}", F(0x1.23456p-3));
+ test("1.23456p-2", "{:La}", F(0x1.23456p-2));
+ test("1.23456p-1", "{:La}", F(0x1.23456p-1));
+ test("1.23456p+0", "{:La}", F(0x1.23456p0));
+ test("1.23456p+1", "{:La}", F(0x1.23456p+1));
+ test("1.23456p+2", "{:La}", F(0x1.23456p+2));
+ test("1.23456p+3", "{:La}", F(0x1.23456p+3));
+ test("1.23456p+20", "{:La}", F(0x1.23456p+20));
+
+ std::locale::global(loc);
+ test("1#23456p-3", "{:La}", F(0x1.23456p-3));
+ test("1#23456p-2", "{:La}", F(0x1.23456p-2));
+ test("1#23456p-1", "{:La}", F(0x1.23456p-1));
+ test("1#23456p+0", "{:La}", F(0x1.23456p0));
+ test("1#23456p+1", "{:La}", F(0x1.23456p+1));
+ test("1#23456p+2", "{:La}", F(0x1.23456p+2));
+ test("1#23456p+3", "{:La}", F(0x1.23456p+3));
+ test("1#23456p+20", "{:La}", F(0x1.23456p+20));
+
+ test("1.23456p-3", en_US, "{:La}", F(0x1.23456p-3));
+ test("1.23456p-2", en_US, "{:La}", F(0x1.23456p-2));
+ test("1.23456p-1", en_US, "{:La}", F(0x1.23456p-1));
+ test("1.23456p+0", en_US, "{:La}", F(0x1.23456p0));
+ test("1.23456p+1", en_US, "{:La}", F(0x1.23456p+1));
+ test("1.23456p+2", en_US, "{:La}", F(0x1.23456p+2));
+ test("1.23456p+3", en_US, "{:La}", F(0x1.23456p+3));
+ test("1.23456p+20", en_US, "{:La}", F(0x1.23456p+20));
+
+ std::locale::global(en_US);
+ test("1#23456p-3", loc, "{:La}", F(0x1.23456p-3));
+ test("1#23456p-2", loc, "{:La}", F(0x1.23456p-2));
+ test("1#23456p-1", loc, "{:La}", F(0x1.23456p-1));
+ test("1#23456p+0", loc, "{:La}", F(0x1.23456p0));
+ test("1#23456p+1", loc, "{:La}", F(0x1.23456p+1));
+ test("1#23456p+2", loc, "{:La}", F(0x1.23456p+2));
+ test("1#23456p+3", loc, "{:La}", F(0x1.23456p+3));
+ test("1#23456p+20", loc, "{:La}", F(0x1.23456p+20));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1.23456p+3$$$", "{:$<13La}", F(0x1.23456p3));
+ test("$$$1.23456p+3", "{:$>13La}", F(0x1.23456p3));
+ test("$1.23456p+3$$", "{:$^13La}", F(0x1.23456p3));
+ test("0001.23456p+3", "{:013La}", F(0x1.23456p3));
+ test("-1.23456p+3$$$", "{:$<14La}", F(-0x1.23456p3));
+ test("$$$-1.23456p+3", "{:$>14La}", F(-0x1.23456p3));
+ test("$-1.23456p+3$$", "{:$^14La}", F(-0x1.23456p3));
+ test("-0001.23456p+3", "{:014La}", F(-0x1.23456p3));
+
+ std::locale::global(loc);
+ test("1#23456p+3$$$", "{:$<13La}", F(0x1.23456p3));
+ test("$$$1#23456p+3", "{:$>13La}", F(0x1.23456p3));
+ test("$1#23456p+3$$", "{:$^13La}", F(0x1.23456p3));
+ test("0001#23456p+3", "{:013La}", F(0x1.23456p3));
+ test("-1#23456p+3$$$", "{:$<14La}", F(-0x1.23456p3));
+ test("$$$-1#23456p+3", "{:$>14La}", F(-0x1.23456p3));
+ test("$-1#23456p+3$$", "{:$^14La}", F(-0x1.23456p3));
+ test("-0001#23456p+3", "{:014La}", F(-0x1.23456p3));
+
+ test("1.23456p+3$$$", en_US, "{:$<13La}", F(0x1.23456p3));
+ test("$$$1.23456p+3", en_US, "{:$>13La}", F(0x1.23456p3));
+ test("$1.23456p+3$$", en_US, "{:$^13La}", F(0x1.23456p3));
+ test("0001.23456p+3", en_US, "{:013La}", F(0x1.23456p3));
+ test("-1.23456p+3$$$", en_US, "{:$<14La}", F(-0x1.23456p3));
+ test("$$$-1.23456p+3", en_US, "{:$>14La}", F(-0x1.23456p3));
+ test("$-1.23456p+3$$", en_US, "{:$^14La}", F(-0x1.23456p3));
+ test("-0001.23456p+3", en_US, "{:014La}", F(-0x1.23456p3));
+
+ std::locale::global(en_US);
+ test("1#23456p+3$$$", loc, "{:$<13La}", F(0x1.23456p3));
+ test("$$$1#23456p+3", loc, "{:$>13La}", F(0x1.23456p3));
+ test("$1#23456p+3$$", loc, "{:$^13La}", F(0x1.23456p3));
+ test("0001#23456p+3", loc, "{:013La}", F(0x1.23456p3));
+ test("-1#23456p+3$$$", loc, "{:$<14La}", F(-0x1.23456p3));
+ test("$$$-1#23456p+3", loc, "{:$>14La}", F(-0x1.23456p3));
+ test("$-1#23456p+3$$", loc, "{:$^14La}", F(-0x1.23456p3));
+ test("-0001#23456p+3", loc, "{:014La}", F(-0x1.23456p3));
+}
+
+template <class F>
+static void test_floating_point_hex_upper_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.23456P-3", "{:LA}", F(0x1.23456p-3));
+ test("1.23456P-2", "{:LA}", F(0x1.23456p-2));
+ test("1.23456P-1", "{:LA}", F(0x1.23456p-1));
+ test("1.23456P+0", "{:LA}", F(0x1.23456p0));
+ test("1.23456P+1", "{:LA}", F(0x1.23456p+1));
+ test("1.23456P+2", "{:LA}", F(0x1.23456p+2));
+ test("1.23456P+3", "{:LA}", F(0x1.23456p+3));
+ test("1.23456P+20", "{:LA}", F(0x1.23456p+20));
+
+ std::locale::global(loc);
+ test("1#23456P-3", "{:LA}", F(0x1.23456p-3));
+ test("1#23456P-2", "{:LA}", F(0x1.23456p-2));
+ test("1#23456P-1", "{:LA}", F(0x1.23456p-1));
+ test("1#23456P+0", "{:LA}", F(0x1.23456p0));
+ test("1#23456P+1", "{:LA}", F(0x1.23456p+1));
+ test("1#23456P+2", "{:LA}", F(0x1.23456p+2));
+ test("1#23456P+3", "{:LA}", F(0x1.23456p+3));
+ test("1#23456P+20", "{:LA}", F(0x1.23456p+20));
+
+ test("1.23456P-3", en_US, "{:LA}", F(0x1.23456p-3));
+ test("1.23456P-2", en_US, "{:LA}", F(0x1.23456p-2));
+ test("1.23456P-1", en_US, "{:LA}", F(0x1.23456p-1));
+ test("1.23456P+0", en_US, "{:LA}", F(0x1.23456p0));
+ test("1.23456P+1", en_US, "{:LA}", F(0x1.23456p+1));
+ test("1.23456P+2", en_US, "{:LA}", F(0x1.23456p+2));
+ test("1.23456P+3", en_US, "{:LA}", F(0x1.23456p+3));
+ test("1.23456P+20", en_US, "{:LA}", F(0x1.23456p+20));
+
+ std::locale::global(en_US);
+ test("1#23456P-3", loc, "{:LA}", F(0x1.23456p-3));
+ test("1#23456P-2", loc, "{:LA}", F(0x1.23456p-2));
+ test("1#23456P-1", loc, "{:LA}", F(0x1.23456p-1));
+ test("1#23456P+0", loc, "{:LA}", F(0x1.23456p0));
+ test("1#23456P+1", loc, "{:LA}", F(0x1.23456p+1));
+ test("1#23456P+2", loc, "{:LA}", F(0x1.23456p+2));
+ test("1#23456P+3", loc, "{:LA}", F(0x1.23456p+3));
+ test("1#23456P+20", loc, "{:LA}", F(0x1.23456p+20));
+
+ // *** Fill, align, zero Padding ***
+ std::locale::global(en_US);
+ test("1.23456P+3$$$", "{:$<13LA}", F(0x1.23456p3));
+ test("$$$1.23456P+3", "{:$>13LA}", F(0x1.23456p3));
+ test("$1.23456P+3$$", "{:$^13LA}", F(0x1.23456p3));
+ test("0001.23456P+3", "{:013LA}", F(0x1.23456p3));
+ test("-1.23456P+3$$$", "{:$<14LA}", F(-0x1.23456p3));
+ test("$$$-1.23456P+3", "{:$>14LA}", F(-0x1.23456p3));
+ test("$-1.23456P+3$$", "{:$^14LA}", F(-0x1.23456p3));
+ test("-0001.23456P+3", "{:014LA}", F(-0x1.23456p3));
+
+ std::locale::global(loc);
+ test("1#23456P+3$$$", "{:$<13LA}", F(0x1.23456p3));
+ test("$$$1#23456P+3", "{:$>13LA}", F(0x1.23456p3));
+ test("$1#23456P+3$$", "{:$^13LA}", F(0x1.23456p3));
+ test("0001#23456P+3", "{:013LA}", F(0x1.23456p3));
+ test("-1#23456P+3$$$", "{:$<14LA}", F(-0x1.23456p3));
+ test("$$$-1#23456P+3", "{:$>14LA}", F(-0x1.23456p3));
+ test("$-1#23456P+3$$", "{:$^14LA}", F(-0x1.23456p3));
+ test("-0001#23456P+3", "{:014LA}", F(-0x1.23456p3));
+
+ test("1.23456P+3$$$", en_US, "{:$<13LA}", F(0x1.23456p3));
+ test("$$$1.23456P+3", en_US, "{:$>13LA}", F(0x1.23456p3));
+ test("$1.23456P+3$$", en_US, "{:$^13LA}", F(0x1.23456p3));
+ test("0001.23456P+3", en_US, "{:013LA}", F(0x1.23456p3));
+ test("-1.23456P+3$$$", en_US, "{:$<14LA}", F(-0x1.23456p3));
+ test("$$$-1.23456P+3", en_US, "{:$>14LA}", F(-0x1.23456p3));
+ test("$-1.23456P+3$$", en_US, "{:$^14LA}", F(-0x1.23456p3));
+ test("-0001.23456P+3", en_US, "{:014LA}", F(-0x1.23456p3));
+
+ std::locale::global(en_US);
+ test("1#23456P+3$$$", loc, "{:$<13LA}", F(0x1.23456p3));
+ test("$$$1#23456P+3", loc, "{:$>13LA}", F(0x1.23456p3));
+ test("$1#23456P+3$$", loc, "{:$^13LA}", F(0x1.23456p3));
+ test("0001#23456P+3", loc, "{:013LA}", F(0x1.23456p3));
+ test("-1#23456P+3$$$", loc, "{:$<14LA}", F(-0x1.23456p3));
+ test("$$$-1#23456P+3", loc, "{:$>14LA}", F(-0x1.23456p3));
+ test("$-1#23456P+3$$", loc, "{:$^14LA}", F(-0x1.23456p3));
+ test("-0001#23456P+3", loc, "{:014LA}", F(-0x1.23456p3));
+}
+
+template <class F>
+static void test_floating_point_hex_lower_case_precision() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.234560p-3", "{:.6La}", F(0x1.23456p-3));
+ test("1.234560p-2", "{:.6La}", F(0x1.23456p-2));
+ test("1.234560p-1", "{:.6La}", F(0x1.23456p-1));
+ test("1.234560p+0", "{:.6La}", F(0x1.23456p0));
+ test("1.234560p+1", "{:.6La}", F(0x1.23456p+1));
+ test("1.234560p+2", "{:.6La}", F(0x1.23456p+2));
+ test("1.234560p+3", "{:.6La}", F(0x1.23456p+3));
+ test("1.234560p+20", "{:.6La}", F(0x1.23456p+20));
+
+ std::locale::global(loc);
+ test("1#234560p-3", "{:.6La}", F(0x1.23456p-3));
+ test("1#234560p-2", "{:.6La}", F(0x1.23456p-2));
+ test("1#234560p-1", "{:.6La}", F(0x1.23456p-1));
+ test("1#234560p+0", "{:.6La}", F(0x1.23456p0));
+ test("1#234560p+1", "{:.6La}", F(0x1.23456p+1));
+ test("1#234560p+2", "{:.6La}", F(0x1.23456p+2));
+ test("1#234560p+3", "{:.6La}", F(0x1.23456p+3));
+ test("1#234560p+20", "{:.6La}", F(0x1.23456p+20));
+
+ test("1.234560p-3", en_US, "{:.6La}", F(0x1.23456p-3));
+ test("1.234560p-2", en_US, "{:.6La}", F(0x1.23456p-2));
+ test("1.234560p-1", en_US, "{:.6La}", F(0x1.23456p-1));
+ test("1.234560p+0", en_US, "{:.6La}", F(0x1.23456p0));
+ test("1.234560p+1", en_US, "{:.6La}", F(0x1.23456p+1));
+ test("1.234560p+2", en_US, "{:.6La}", F(0x1.23456p+2));
+ test("1.234560p+3", en_US, "{:.6La}", F(0x1.23456p+3));
+ test("1.234560p+20", en_US, "{:.6La}", F(0x1.23456p+20));
+
+ std::locale::global(en_US);
+ test("1#234560p-3", loc, "{:.6La}", F(0x1.23456p-3));
+ test("1#234560p-2", loc, "{:.6La}", F(0x1.23456p-2));
+ test("1#234560p-1", loc, "{:.6La}", F(0x1.23456p-1));
+ test("1#234560p+0", loc, "{:.6La}", F(0x1.23456p0));
+ test("1#234560p+1", loc, "{:.6La}", F(0x1.23456p+1));
+ test("1#234560p+2", loc, "{:.6La}", F(0x1.23456p+2));
+ test("1#234560p+3", loc, "{:.6La}", F(0x1.23456p+3));
+ test("1#234560p+20", loc, "{:.6La}", F(0x1.23456p+20));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1.234560p+3$$$", "{:$<14.6La}", F(0x1.23456p3));
+ test("$$$1.234560p+3", "{:$>14.6La}", F(0x1.23456p3));
+ test("$1.234560p+3$$", "{:$^14.6La}", F(0x1.23456p3));
+ test("0001.234560p+3", "{:014.6La}", F(0x1.23456p3));
+ test("-1.234560p+3$$$", "{:$<15.6La}", F(-0x1.23456p3));
+ test("$$$-1.234560p+3", "{:$>15.6La}", F(-0x1.23456p3));
+ test("$-1.234560p+3$$", "{:$^15.6La}", F(-0x1.23456p3));
+ test("-0001.234560p+3", "{:015.6La}", F(-0x1.23456p3));
+
+ std::locale::global(loc);
+ test("1#234560p+3$$$", "{:$<14.6La}", F(0x1.23456p3));
+ test("$$$1#234560p+3", "{:$>14.6La}", F(0x1.23456p3));
+ test("$1#234560p+3$$", "{:$^14.6La}", F(0x1.23456p3));
+ test("0001#234560p+3", "{:014.6La}", F(0x1.23456p3));
+ test("-1#234560p+3$$$", "{:$<15.6La}", F(-0x1.23456p3));
+ test("$$$-1#234560p+3", "{:$>15.6La}", F(-0x1.23456p3));
+ test("$-1#234560p+3$$", "{:$^15.6La}", F(-0x1.23456p3));
+ test("-0001#234560p+3", "{:015.6La}", F(-0x1.23456p3));
+
+ test("1.234560p+3$$$", en_US, "{:$<14.6La}", F(0x1.23456p3));
+ test("$$$1.234560p+3", en_US, "{:$>14.6La}", F(0x1.23456p3));
+ test("$1.234560p+3$$", en_US, "{:$^14.6La}", F(0x1.23456p3));
+ test("0001.234560p+3", en_US, "{:014.6La}", F(0x1.23456p3));
+ test("-1.234560p+3$$$", en_US, "{:$<15.6La}", F(-0x1.23456p3));
+ test("$$$-1.234560p+3", en_US, "{:$>15.6La}", F(-0x1.23456p3));
+ test("$-1.234560p+3$$", en_US, "{:$^15.6La}", F(-0x1.23456p3));
+ test("-0001.234560p+3", en_US, "{:015.6La}", F(-0x1.23456p3));
+
+ std::locale::global(en_US);
+ test("1#234560p+3$$$", loc, "{:$<14.6La}", F(0x1.23456p3));
+ test("$$$1#234560p+3", loc, "{:$>14.6La}", F(0x1.23456p3));
+ test("$1#234560p+3$$", loc, "{:$^14.6La}", F(0x1.23456p3));
+ test("0001#234560p+3", loc, "{:014.6La}", F(0x1.23456p3));
+ test("-1#234560p+3$$$", loc, "{:$<15.6La}", F(-0x1.23456p3));
+ test("$$$-1#234560p+3", loc, "{:$>15.6La}", F(-0x1.23456p3));
+ test("$-1#234560p+3$$", loc, "{:$^15.6La}", F(-0x1.23456p3));
+ test("-0001#234560p+3", loc, "{:015.6La}", F(-0x1.23456p3));
+}
+
+template <class F>
+static void test_floating_point_hex_upper_case_precision() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.234560P-3", "{:.6LA}", F(0x1.23456p-3));
+ test("1.234560P-2", "{:.6LA}", F(0x1.23456p-2));
+ test("1.234560P-1", "{:.6LA}", F(0x1.23456p-1));
+ test("1.234560P+0", "{:.6LA}", F(0x1.23456p0));
+ test("1.234560P+1", "{:.6LA}", F(0x1.23456p+1));
+ test("1.234560P+2", "{:.6LA}", F(0x1.23456p+2));
+ test("1.234560P+3", "{:.6LA}", F(0x1.23456p+3));
+ test("1.234560P+20", "{:.6LA}", F(0x1.23456p+20));
+
+ std::locale::global(loc);
+ test("1#234560P-3", "{:.6LA}", F(0x1.23456p-3));
+ test("1#234560P-2", "{:.6LA}", F(0x1.23456p-2));
+ test("1#234560P-1", "{:.6LA}", F(0x1.23456p-1));
+ test("1#234560P+0", "{:.6LA}", F(0x1.23456p0));
+ test("1#234560P+1", "{:.6LA}", F(0x1.23456p+1));
+ test("1#234560P+2", "{:.6LA}", F(0x1.23456p+2));
+ test("1#234560P+3", "{:.6LA}", F(0x1.23456p+3));
+ test("1#234560P+20", "{:.6LA}", F(0x1.23456p+20));
+
+ test("1.234560P-3", en_US, "{:.6LA}", F(0x1.23456p-3));
+ test("1.234560P-2", en_US, "{:.6LA}", F(0x1.23456p-2));
+ test("1.234560P-1", en_US, "{:.6LA}", F(0x1.23456p-1));
+ test("1.234560P+0", en_US, "{:.6LA}", F(0x1.23456p0));
+ test("1.234560P+1", en_US, "{:.6LA}", F(0x1.23456p+1));
+ test("1.234560P+2", en_US, "{:.6LA}", F(0x1.23456p+2));
+ test("1.234560P+3", en_US, "{:.6LA}", F(0x1.23456p+3));
+ test("1.234560P+20", en_US, "{:.6LA}", F(0x1.23456p+20));
+
+ std::locale::global(en_US);
+ test("1#234560P-3", loc, "{:.6LA}", F(0x1.23456p-3));
+ test("1#234560P-2", loc, "{:.6LA}", F(0x1.23456p-2));
+ test("1#234560P-1", loc, "{:.6LA}", F(0x1.23456p-1));
+ test("1#234560P+0", loc, "{:.6LA}", F(0x1.23456p0));
+ test("1#234560P+1", loc, "{:.6LA}", F(0x1.23456p+1));
+ test("1#234560P+2", loc, "{:.6LA}", F(0x1.23456p+2));
+ test("1#234560P+3", loc, "{:.6LA}", F(0x1.23456p+3));
+ test("1#234560P+20", loc, "{:.6LA}", F(0x1.23456p+20));
+
+ // *** Fill, align, zero Padding ***
+ std::locale::global(en_US);
+ test("1.234560P+3$$$", "{:$<14.6LA}", F(0x1.23456p3));
+ test("$$$1.234560P+3", "{:$>14.6LA}", F(0x1.23456p3));
+ test("$1.234560P+3$$", "{:$^14.6LA}", F(0x1.23456p3));
+ test("0001.234560P+3", "{:014.6LA}", F(0x1.23456p3));
+ test("-1.234560P+3$$$", "{:$<15.6LA}", F(-0x1.23456p3));
+ test("$$$-1.234560P+3", "{:$>15.6LA}", F(-0x1.23456p3));
+ test("$-1.234560P+3$$", "{:$^15.6LA}", F(-0x1.23456p3));
+ test("-0001.234560P+3", "{:015.6LA}", F(-0x1.23456p3));
+
+ std::locale::global(loc);
+ test("1#234560P+3$$$", "{:$<14.6LA}", F(0x1.23456p3));
+ test("$$$1#234560P+3", "{:$>14.6LA}", F(0x1.23456p3));
+ test("$1#234560P+3$$", "{:$^14.6LA}", F(0x1.23456p3));
+ test("0001#234560P+3", "{:014.6LA}", F(0x1.23456p3));
+ test("-1#234560P+3$$$", "{:$<15.6LA}", F(-0x1.23456p3));
+ test("$$$-1#234560P+3", "{:$>15.6LA}", F(-0x1.23456p3));
+ test("$-1#234560P+3$$", "{:$^15.6LA}", F(-0x1.23456p3));
+ test("-0001#234560P+3", "{:015.6LA}", F(-0x1.23456p3));
+
+ test("1.234560P+3$$$", en_US, "{:$<14.6LA}", F(0x1.23456p3));
+ test("$$$1.234560P+3", en_US, "{:$>14.6LA}", F(0x1.23456p3));
+ test("$1.234560P+3$$", en_US, "{:$^14.6LA}", F(0x1.23456p3));
+ test("0001.234560P+3", en_US, "{:014.6LA}", F(0x1.23456p3));
+ test("-1.234560P+3$$$", en_US, "{:$<15.6LA}", F(-0x1.23456p3));
+ test("$$$-1.234560P+3", en_US, "{:$>15.6LA}", F(-0x1.23456p3));
+ test("$-1.234560P+3$$", en_US, "{:$^15.6LA}", F(-0x1.23456p3));
+ test("-0001.234560P+3", en_US, "{:015.6LA}", F(-0x1.23456p3));
+
+ std::locale::global(en_US);
+ test("1#234560P+3$$$", loc, "{:$<14.6LA}", F(0x1.23456p3));
+ test("$$$1#234560P+3", loc, "{:$>14.6LA}", F(0x1.23456p3));
+ test("$1#234560P+3$$", loc, "{:$^14.6LA}", F(0x1.23456p3));
+ test("0001#234560P+3", loc, "{:014.6LA}", F(0x1.23456p3));
+ test("-1#234560P+3$$$", loc, "{:$<15.6LA}", F(-0x1.23456p3));
+ test("$$$-1#234560P+3", loc, "{:$>15.6LA}", F(-0x1.23456p3));
+ test("$-1#234560P+3$$", loc, "{:$^15.6LA}", F(-0x1.23456p3));
+ test("-0001#234560P+3", loc, "{:015.6LA}", F(-0x1.23456p3));
+}
+
+template <class F>
+static void test_floating_point_scientific_lower_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.234567e-03", "{:.6Le}", F(1.234567e-3));
+ test("1.234567e-02", "{:.6Le}", F(1.234567e-2));
+ test("1.234567e-01", "{:.6Le}", F(1.234567e-1));
+ test("1.234567e+00", "{:.6Le}", F(1.234567e0));
+ test("1.234567e+01", "{:.6Le}", F(1.234567e1));
+ test("1.234567e+02", "{:.6Le}", F(1.234567e2));
+ test("1.234567e+03", "{:.6Le}", F(1.234567e3));
+ test("1.234567e+20", "{:.6Le}", F(1.234567e20));
+ test("-1.234567e-03", "{:.6Le}", F(-1.234567e-3));
+ test("-1.234567e-02", "{:.6Le}", F(-1.234567e-2));
+ test("-1.234567e-01", "{:.6Le}", F(-1.234567e-1));
+ test("-1.234567e+00", "{:.6Le}", F(-1.234567e0));
+ test("-1.234567e+01", "{:.6Le}", F(-1.234567e1));
+ test("-1.234567e+02", "{:.6Le}", F(-1.234567e2));
+ test("-1.234567e+03", "{:.6Le}", F(-1.234567e3));
+ test("-1.234567e+20", "{:.6Le}", F(-1.234567e20));
+
+ std::locale::global(loc);
+ test("1#234567e-03", "{:.6Le}", F(1.234567e-3));
+ test("1#234567e-02", "{:.6Le}", F(1.234567e-2));
+ test("1#234567e-01", "{:.6Le}", F(1.234567e-1));
+ test("1#234567e+00", "{:.6Le}", F(1.234567e0));
+ test("1#234567e+01", "{:.6Le}", F(1.234567e1));
+ test("1#234567e+02", "{:.6Le}", F(1.234567e2));
+ test("1#234567e+03", "{:.6Le}", F(1.234567e3));
+ test("1#234567e+20", "{:.6Le}", F(1.234567e20));
+ test("-1#234567e-03", "{:.6Le}", F(-1.234567e-3));
+ test("-1#234567e-02", "{:.6Le}", F(-1.234567e-2));
+ test("-1#234567e-01", "{:.6Le}", F(-1.234567e-1));
+ test("-1#234567e+00", "{:.6Le}", F(-1.234567e0));
+ test("-1#234567e+01", "{:.6Le}", F(-1.234567e1));
+ test("-1#234567e+02", "{:.6Le}", F(-1.234567e2));
+ test("-1#234567e+03", "{:.6Le}", F(-1.234567e3));
+ test("-1#234567e+20", "{:.6Le}", F(-1.234567e20));
+
+ test("1.234567e-03", en_US, "{:.6Le}", F(1.234567e-3));
+ test("1.234567e-02", en_US, "{:.6Le}", F(1.234567e-2));
+ test("1.234567e-01", en_US, "{:.6Le}", F(1.234567e-1));
+ test("1.234567e+00", en_US, "{:.6Le}", F(1.234567e0));
+ test("1.234567e+01", en_US, "{:.6Le}", F(1.234567e1));
+ test("1.234567e+02", en_US, "{:.6Le}", F(1.234567e2));
+ test("1.234567e+03", en_US, "{:.6Le}", F(1.234567e3));
+ test("1.234567e+20", en_US, "{:.6Le}", F(1.234567e20));
+ test("-1.234567e-03", en_US, "{:.6Le}", F(-1.234567e-3));
+ test("-1.234567e-02", en_US, "{:.6Le}", F(-1.234567e-2));
+ test("-1.234567e-01", en_US, "{:.6Le}", F(-1.234567e-1));
+ test("-1.234567e+00", en_US, "{:.6Le}", F(-1.234567e0));
+ test("-1.234567e+01", en_US, "{:.6Le}", F(-1.234567e1));
+ test("-1.234567e+02", en_US, "{:.6Le}", F(-1.234567e2));
+ test("-1.234567e+03", en_US, "{:.6Le}", F(-1.234567e3));
+ test("-1.234567e+20", en_US, "{:.6Le}", F(-1.234567e20));
+
+ std::locale::global(en_US);
+ test("1#234567e-03", loc, "{:.6Le}", F(1.234567e-3));
+ test("1#234567e-02", loc, "{:.6Le}", F(1.234567e-2));
+ test("1#234567e-01", loc, "{:.6Le}", F(1.234567e-1));
+ test("1#234567e+00", loc, "{:.6Le}", F(1.234567e0));
+ test("1#234567e+01", loc, "{:.6Le}", F(1.234567e1));
+ test("1#234567e+02", loc, "{:.6Le}", F(1.234567e2));
+ test("1#234567e+03", loc, "{:.6Le}", F(1.234567e3));
+ test("1#234567e+20", loc, "{:.6Le}", F(1.234567e20));
+ test("-1#234567e-03", loc, "{:.6Le}", F(-1.234567e-3));
+ test("-1#234567e-02", loc, "{:.6Le}", F(-1.234567e-2));
+ test("-1#234567e-01", loc, "{:.6Le}", F(-1.234567e-1));
+ test("-1#234567e+00", loc, "{:.6Le}", F(-1.234567e0));
+ test("-1#234567e+01", loc, "{:.6Le}", F(-1.234567e1));
+ test("-1#234567e+02", loc, "{:.6Le}", F(-1.234567e2));
+ test("-1#234567e+03", loc, "{:.6Le}", F(-1.234567e3));
+ test("-1#234567e+20", loc, "{:.6Le}", F(-1.234567e20));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1.234567e+03$$$", "{:$<15.6Le}", F(1.234567e3));
+ test("$$$1.234567e+03", "{:$>15.6Le}", F(1.234567e3));
+ test("$1.234567e+03$$", "{:$^15.6Le}", F(1.234567e3));
+ test("0001.234567e+03", "{:015.6Le}", F(1.234567e3));
+ test("-1.234567e+03$$$", "{:$<16.6Le}", F(-1.234567e3));
+ test("$$$-1.234567e+03", "{:$>16.6Le}", F(-1.234567e3));
+ test("$-1.234567e+03$$", "{:$^16.6Le}", F(-1.234567e3));
+ test("-0001.234567e+03", "{:016.6Le}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1#234567e+03$$$", "{:$<15.6Le}", F(1.234567e3));
+ test("$$$1#234567e+03", "{:$>15.6Le}", F(1.234567e3));
+ test("$1#234567e+03$$", "{:$^15.6Le}", F(1.234567e3));
+ test("0001#234567e+03", "{:015.6Le}", F(1.234567e3));
+ test("-1#234567e+03$$$", "{:$<16.6Le}", F(-1.234567e3));
+ test("$$$-1#234567e+03", "{:$>16.6Le}", F(-1.234567e3));
+ test("$-1#234567e+03$$", "{:$^16.6Le}", F(-1.234567e3));
+ test("-0001#234567e+03", "{:016.6Le}", F(-1.234567e3));
+
+ test("1.234567e+03$$$", en_US, "{:$<15.6Le}", F(1.234567e3));
+ test("$$$1.234567e+03", en_US, "{:$>15.6Le}", F(1.234567e3));
+ test("$1.234567e+03$$", en_US, "{:$^15.6Le}", F(1.234567e3));
+ test("0001.234567e+03", en_US, "{:015.6Le}", F(1.234567e3));
+ test("-1.234567e+03$$$", en_US, "{:$<16.6Le}", F(-1.234567e3));
+ test("$$$-1.234567e+03", en_US, "{:$>16.6Le}", F(-1.234567e3));
+ test("$-1.234567e+03$$", en_US, "{:$^16.6Le}", F(-1.234567e3));
+ test("-0001.234567e+03", en_US, "{:016.6Le}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1#234567e+03$$$", loc, "{:$<15.6Le}", F(1.234567e3));
+ test("$$$1#234567e+03", loc, "{:$>15.6Le}", F(1.234567e3));
+ test("$1#234567e+03$$", loc, "{:$^15.6Le}", F(1.234567e3));
+ test("0001#234567e+03", loc, "{:015.6Le}", F(1.234567e3));
+ test("-1#234567e+03$$$", loc, "{:$<16.6Le}", F(-1.234567e3));
+ test("$$$-1#234567e+03", loc, "{:$>16.6Le}", F(-1.234567e3));
+ test("$-1#234567e+03$$", loc, "{:$^16.6Le}", F(-1.234567e3));
+ test("-0001#234567e+03", loc, "{:016.6Le}", F(-1.234567e3));
+}
+
+template <class F>
+static void test_floating_point_scientific_upper_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.234567E-03", "{:.6LE}", F(1.234567e-3));
+ test("1.234567E-02", "{:.6LE}", F(1.234567e-2));
+ test("1.234567E-01", "{:.6LE}", F(1.234567e-1));
+ test("1.234567E+00", "{:.6LE}", F(1.234567e0));
+ test("1.234567E+01", "{:.6LE}", F(1.234567e1));
+ test("1.234567E+02", "{:.6LE}", F(1.234567e2));
+ test("1.234567E+03", "{:.6LE}", F(1.234567e3));
+ test("1.234567E+20", "{:.6LE}", F(1.234567e20));
+ test("-1.234567E-03", "{:.6LE}", F(-1.234567e-3));
+ test("-1.234567E-02", "{:.6LE}", F(-1.234567e-2));
+ test("-1.234567E-01", "{:.6LE}", F(-1.234567e-1));
+ test("-1.234567E+00", "{:.6LE}", F(-1.234567e0));
+ test("-1.234567E+01", "{:.6LE}", F(-1.234567e1));
+ test("-1.234567E+02", "{:.6LE}", F(-1.234567e2));
+ test("-1.234567E+03", "{:.6LE}", F(-1.234567e3));
+ test("-1.234567E+20", "{:.6LE}", F(-1.234567e20));
+
+ std::locale::global(loc);
+ test("1#234567E-03", "{:.6LE}", F(1.234567e-3));
+ test("1#234567E-02", "{:.6LE}", F(1.234567e-2));
+ test("1#234567E-01", "{:.6LE}", F(1.234567e-1));
+ test("1#234567E+00", "{:.6LE}", F(1.234567e0));
+ test("1#234567E+01", "{:.6LE}", F(1.234567e1));
+ test("1#234567E+02", "{:.6LE}", F(1.234567e2));
+ test("1#234567E+03", "{:.6LE}", F(1.234567e3));
+ test("1#234567E+20", "{:.6LE}", F(1.234567e20));
+ test("-1#234567E-03", "{:.6LE}", F(-1.234567e-3));
+ test("-1#234567E-02", "{:.6LE}", F(-1.234567e-2));
+ test("-1#234567E-01", "{:.6LE}", F(-1.234567e-1));
+ test("-1#234567E+00", "{:.6LE}", F(-1.234567e0));
+ test("-1#234567E+01", "{:.6LE}", F(-1.234567e1));
+ test("-1#234567E+02", "{:.6LE}", F(-1.234567e2));
+ test("-1#234567E+03", "{:.6LE}", F(-1.234567e3));
+ test("-1#234567E+20", "{:.6LE}", F(-1.234567e20));
+
+ test("1.234567E-03", en_US, "{:.6LE}", F(1.234567e-3));
+ test("1.234567E-02", en_US, "{:.6LE}", F(1.234567e-2));
+ test("1.234567E-01", en_US, "{:.6LE}", F(1.234567e-1));
+ test("1.234567E+00", en_US, "{:.6LE}", F(1.234567e0));
+ test("1.234567E+01", en_US, "{:.6LE}", F(1.234567e1));
+ test("1.234567E+02", en_US, "{:.6LE}", F(1.234567e2));
+ test("1.234567E+03", en_US, "{:.6LE}", F(1.234567e3));
+ test("1.234567E+20", en_US, "{:.6LE}", F(1.234567e20));
+ test("-1.234567E-03", en_US, "{:.6LE}", F(-1.234567e-3));
+ test("-1.234567E-02", en_US, "{:.6LE}", F(-1.234567e-2));
+ test("-1.234567E-01", en_US, "{:.6LE}", F(-1.234567e-1));
+ test("-1.234567E+00", en_US, "{:.6LE}", F(-1.234567e0));
+ test("-1.234567E+01", en_US, "{:.6LE}", F(-1.234567e1));
+ test("-1.234567E+02", en_US, "{:.6LE}", F(-1.234567e2));
+ test("-1.234567E+03", en_US, "{:.6LE}", F(-1.234567e3));
+ test("-1.234567E+20", en_US, "{:.6LE}", F(-1.234567e20));
+
+ std::locale::global(en_US);
+ test("1#234567E-03", loc, "{:.6LE}", F(1.234567e-3));
+ test("1#234567E-02", loc, "{:.6LE}", F(1.234567e-2));
+ test("1#234567E-01", loc, "{:.6LE}", F(1.234567e-1));
+ test("1#234567E+00", loc, "{:.6LE}", F(1.234567e0));
+ test("1#234567E+01", loc, "{:.6LE}", F(1.234567e1));
+ test("1#234567E+02", loc, "{:.6LE}", F(1.234567e2));
+ test("1#234567E+03", loc, "{:.6LE}", F(1.234567e3));
+ test("1#234567E+20", loc, "{:.6LE}", F(1.234567e20));
+ test("-1#234567E-03", loc, "{:.6LE}", F(-1.234567e-3));
+ test("-1#234567E-02", loc, "{:.6LE}", F(-1.234567e-2));
+ test("-1#234567E-01", loc, "{:.6LE}", F(-1.234567e-1));
+ test("-1#234567E+00", loc, "{:.6LE}", F(-1.234567e0));
+ test("-1#234567E+01", loc, "{:.6LE}", F(-1.234567e1));
+ test("-1#234567E+02", loc, "{:.6LE}", F(-1.234567e2));
+ test("-1#234567E+03", loc, "{:.6LE}", F(-1.234567e3));
+ test("-1#234567E+20", loc, "{:.6LE}", F(-1.234567e20));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1.234567E+03$$$", "{:$<15.6LE}", F(1.234567e3));
+ test("$$$1.234567E+03", "{:$>15.6LE}", F(1.234567e3));
+ test("$1.234567E+03$$", "{:$^15.6LE}", F(1.234567e3));
+ test("0001.234567E+03", "{:015.6LE}", F(1.234567e3));
+ test("-1.234567E+03$$$", "{:$<16.6LE}", F(-1.234567e3));
+ test("$$$-1.234567E+03", "{:$>16.6LE}", F(-1.234567e3));
+ test("$-1.234567E+03$$", "{:$^16.6LE}", F(-1.234567e3));
+ test("-0001.234567E+03", "{:016.6LE}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1#234567E+03$$$", "{:$<15.6LE}", F(1.234567e3));
+ test("$$$1#234567E+03", "{:$>15.6LE}", F(1.234567e3));
+ test("$1#234567E+03$$", "{:$^15.6LE}", F(1.234567e3));
+ test("0001#234567E+03", "{:015.6LE}", F(1.234567e3));
+ test("-1#234567E+03$$$", "{:$<16.6LE}", F(-1.234567e3));
+ test("$$$-1#234567E+03", "{:$>16.6LE}", F(-1.234567e3));
+ test("$-1#234567E+03$$", "{:$^16.6LE}", F(-1.234567e3));
+ test("-0001#234567E+03", "{:016.6LE}", F(-1.234567e3));
+
+ test("1.234567E+03$$$", en_US, "{:$<15.6LE}", F(1.234567e3));
+ test("$$$1.234567E+03", en_US, "{:$>15.6LE}", F(1.234567e3));
+ test("$1.234567E+03$$", en_US, "{:$^15.6LE}", F(1.234567e3));
+ test("0001.234567E+03", en_US, "{:015.6LE}", F(1.234567e3));
+ test("-1.234567E+03$$$", en_US, "{:$<16.6LE}", F(-1.234567e3));
+ test("$$$-1.234567E+03", en_US, "{:$>16.6LE}", F(-1.234567e3));
+ test("$-1.234567E+03$$", en_US, "{:$^16.6LE}", F(-1.234567e3));
+ test("-0001.234567E+03", en_US, "{:016.6LE}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1#234567E+03$$$", loc, "{:$<15.6LE}", F(1.234567e3));
+ test("$$$1#234567E+03", loc, "{:$>15.6LE}", F(1.234567e3));
+ test("$1#234567E+03$$", loc, "{:$^15.6LE}", F(1.234567e3));
+ test("0001#234567E+03", loc, "{:015.6LE}", F(1.234567e3));
+ test("-1#234567E+03$$$", loc, "{:$<16.6LE}", F(-1.234567e3));
+ test("$$$-1#234567E+03", loc, "{:$>16.6LE}", F(-1.234567e3));
+ test("$-1#234567E+03$$", loc, "{:$^16.6LE}", F(-1.234567e3));
+ test("-0001#234567E+03", loc, "{:016.6LE}", F(-1.234567e3));
+}
+
+template <class F>
+static void test_floating_point_fixed_lower_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("0.000001", "{:.6Lf}", F(1.234567e-6));
+ test("0.000012", "{:.6Lf}", F(1.234567e-5));
+ test("0.000123", "{:.6Lf}", F(1.234567e-4));
+ test("0.001235", "{:.6Lf}", F(1.234567e-3));
+ test("0.012346", "{:.6Lf}", F(1.234567e-2));
+ test("0.123457", "{:.6Lf}", F(1.234567e-1));
+ test("1.234567", "{:.6Lf}", F(1.234567e0));
+ test("12.345670", "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("123.456700", "{:.6Lf}", F(1.234567e2));
+ test("1,234.567000", "{:.6Lf}", F(1.234567e3));
+ test("12,345.670000", "{:.6Lf}", F(1.234567e4));
+ test("123,456.700000", "{:.6Lf}", F(1.234567e5));
+ test("1,234,567.000000", "{:.6Lf}", F(1.234567e6));
+ test("12,345,670.000000", "{:.6Lf}", F(1.234567e7));
+ test("123,456,700,000,000,000,000.000000", "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0.000001", "{:.6Lf}", F(-1.234567e-6));
+ test("-0.000012", "{:.6Lf}", F(-1.234567e-5));
+ test("-0.000123", "{:.6Lf}", F(-1.234567e-4));
+ test("-0.001235", "{:.6Lf}", F(-1.234567e-3));
+ test("-0.012346", "{:.6Lf}", F(-1.234567e-2));
+ test("-0.123457", "{:.6Lf}", F(-1.234567e-1));
+ test("-1.234567", "{:.6Lf}", F(-1.234567e0));
+ test("-12.345670", "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-123.456700", "{:.6Lf}", F(-1.234567e2));
+ test("-1,234.567000", "{:.6Lf}", F(-1.234567e3));
+ test("-12,345.670000", "{:.6Lf}", F(-1.234567e4));
+ test("-123,456.700000", "{:.6Lf}", F(-1.234567e5));
+ test("-1,234,567.000000", "{:.6Lf}", F(-1.234567e6));
+ test("-12,345,670.000000", "{:.6Lf}", F(-1.234567e7));
+ test("-123,456,700,000,000,000,000.000000", "{:.6Lf}", F(-1.234567e20));
+ }
+
+ std::locale::global(loc);
+ test("0#000001", "{:.6Lf}", F(1.234567e-6));
+ test("0#000012", "{:.6Lf}", F(1.234567e-5));
+ test("0#000123", "{:.6Lf}", F(1.234567e-4));
+ test("0#001235", "{:.6Lf}", F(1.234567e-3));
+ test("0#012346", "{:.6Lf}", F(1.234567e-2));
+ test("0#123457", "{:.6Lf}", F(1.234567e-1));
+ test("1#234567", "{:.6Lf}", F(1.234567e0));
+ test("1_2#345670", "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("12_3#456700", "{:.6Lf}", F(1.234567e2));
+ test("1_23_4#567000", "{:.6Lf}", F(1.234567e3));
+ test("12_34_5#670000", "{:.6Lf}", F(1.234567e4));
+ test("123_45_6#700000", "{:.6Lf}", F(1.234567e5));
+ test("1_234_56_7#000000", "{:.6Lf}", F(1.234567e6));
+ test("12_345_67_0#000000", "{:.6Lf}", F(1.234567e7));
+ test("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0#000001", "{:.6Lf}", F(-1.234567e-6));
+ test("-0#000012", "{:.6Lf}", F(-1.234567e-5));
+ test("-0#000123", "{:.6Lf}", F(-1.234567e-4));
+ test("-0#001235", "{:.6Lf}", F(-1.234567e-3));
+ test("-0#012346", "{:.6Lf}", F(-1.234567e-2));
+ test("-0#123457", "{:.6Lf}", F(-1.234567e-1));
+ test("-1#234567", "{:.6Lf}", F(-1.234567e0));
+ test("-1_2#345670", "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-12_3#456700", "{:.6Lf}", F(-1.234567e2));
+ test("-1_23_4#567000", "{:.6Lf}", F(-1.234567e3));
+ test("-12_34_5#670000", "{:.6Lf}", F(-1.234567e4));
+ test("-123_45_6#700000", "{:.6Lf}", F(-1.234567e5));
+ test("-1_234_56_7#000000", "{:.6Lf}", F(-1.234567e6));
+ test("-12_345_67_0#000000", "{:.6Lf}", F(-1.234567e7));
+ test("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", "{:.6Lf}", F(-1.234567e20));
+ }
+
+ test("0.000001", en_US, "{:.6Lf}", F(1.234567e-6));
+ test("0.000012", en_US, "{:.6Lf}", F(1.234567e-5));
+ test("0.000123", en_US, "{:.6Lf}", F(1.234567e-4));
+ test("0.001235", en_US, "{:.6Lf}", F(1.234567e-3));
+ test("0.012346", en_US, "{:.6Lf}", F(1.234567e-2));
+ test("0.123457", en_US, "{:.6Lf}", F(1.234567e-1));
+ test("1.234567", en_US, "{:.6Lf}", F(1.234567e0));
+ test("12.345670", en_US, "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("123.456700", en_US, "{:.6Lf}", F(1.234567e2));
+ test("1,234.567000", en_US, "{:.6Lf}", F(1.234567e3));
+ test("12,345.670000", en_US, "{:.6Lf}", F(1.234567e4));
+ test("123,456.700000", en_US, "{:.6Lf}", F(1.234567e5));
+ test("1,234,567.000000", en_US, "{:.6Lf}", F(1.234567e6));
+ test("12,345,670.000000", en_US, "{:.6Lf}", F(1.234567e7));
+ test("123,456,700,000,000,000,000.000000", en_US, "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0.000001", en_US, "{:.6Lf}", F(-1.234567e-6));
+ test("-0.000012", en_US, "{:.6Lf}", F(-1.234567e-5));
+ test("-0.000123", en_US, "{:.6Lf}", F(-1.234567e-4));
+ test("-0.001235", en_US, "{:.6Lf}", F(-1.234567e-3));
+ test("-0.012346", en_US, "{:.6Lf}", F(-1.234567e-2));
+ test("-0.123457", en_US, "{:.6Lf}", F(-1.234567e-1));
+ test("-1.234567", en_US, "{:.6Lf}", F(-1.234567e0));
+ test("-12.345670", en_US, "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-123.456700", en_US, "{:.6Lf}", F(-1.234567e2));
+ test("-1,234.567000", en_US, "{:.6Lf}", F(-1.234567e3));
+ test("-12,345.670000", en_US, "{:.6Lf}", F(-1.234567e4));
+ test("-123,456.700000", en_US, "{:.6Lf}", F(-1.234567e5));
+ test("-1,234,567.000000", en_US, "{:.6Lf}", F(-1.234567e6));
+ test("-12,345,670.000000", en_US, "{:.6Lf}", F(-1.234567e7));
+ test("-123,456,700,000,000,000,000.000000", en_US, "{:.6Lf}", F(-1.234567e20));
+ }
+
+ std::locale::global(en_US);
+ test("0#000001", loc, "{:.6Lf}", F(1.234567e-6));
+ test("0#000012", loc, "{:.6Lf}", F(1.234567e-5));
+ test("0#000123", loc, "{:.6Lf}", F(1.234567e-4));
+ test("0#001235", loc, "{:.6Lf}", F(1.234567e-3));
+ test("0#012346", loc, "{:.6Lf}", F(1.234567e-2));
+ test("0#123457", loc, "{:.6Lf}", F(1.234567e-1));
+ test("1#234567", loc, "{:.6Lf}", F(1.234567e0));
+ test("1_2#345670", loc, "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("12_3#456700", loc, "{:.6Lf}", F(1.234567e2));
+ test("1_23_4#567000", loc, "{:.6Lf}", F(1.234567e3));
+ test("12_34_5#670000", loc, "{:.6Lf}", F(1.234567e4));
+ test("123_45_6#700000", loc, "{:.6Lf}", F(1.234567e5));
+ test("1_234_56_7#000000", loc, "{:.6Lf}", F(1.234567e6));
+ test("12_345_67_0#000000", loc, "{:.6Lf}", F(1.234567e7));
+ test("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", loc, "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0#000001", loc, "{:.6Lf}", F(-1.234567e-6));
+ test("-0#000012", loc, "{:.6Lf}", F(-1.234567e-5));
+ test("-0#000123", loc, "{:.6Lf}", F(-1.234567e-4));
+ test("-0#001235", loc, "{:.6Lf}", F(-1.234567e-3));
+ test("-0#012346", loc, "{:.6Lf}", F(-1.234567e-2));
+ test("-0#123457", loc, "{:.6Lf}", F(-1.234567e-1));
+ test("-1#234567", loc, "{:.6Lf}", F(-1.234567e0));
+ test("-1_2#345670", loc, "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-12_3#456700", loc, "{:.6Lf}", F(-1.234567e2));
+ test("-1_23_4#567000", loc, "{:.6Lf}", F(-1.234567e3));
+ test("-12_34_5#670000", loc, "{:.6Lf}", F(-1.234567e4));
+ test("-123_45_6#700000", loc, "{:.6Lf}", F(-1.234567e5));
+ test("-1_234_56_7#000000", loc, "{:.6Lf}", F(-1.234567e6));
+ test("-12_345_67_0#000000", loc, "{:.6Lf}", F(-1.234567e7));
+ test("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", loc, "{:.6Lf}", F(-1.234567e20));
+ }
+
+ // *** Fill, align, zero padding ***
+ if constexpr (sizeof(F) > sizeof(float)) {
+ std::locale::global(en_US);
+ test("1,234.567000$$$", "{:$<15.6Lf}", F(1.234567e3));
+ test("$$$1,234.567000", "{:$>15.6Lf}", F(1.234567e3));
+ test("$1,234.567000$$", "{:$^15.6Lf}", F(1.234567e3));
+ test("0001,234.567000", "{:015.6Lf}", F(1.234567e3));
+ test("-1,234.567000$$$", "{:$<16.6Lf}", F(-1.234567e3));
+ test("$$$-1,234.567000", "{:$>16.6Lf}", F(-1.234567e3));
+ test("$-1,234.567000$$", "{:$^16.6Lf}", F(-1.234567e3));
+ test("-0001,234.567000", "{:016.6Lf}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1_23_4#567000$$$", "{:$<16.6Lf}", F(1.234567e3));
+ test("$$$1_23_4#567000", "{:$>16.6Lf}", F(1.234567e3));
+ test("$1_23_4#567000$$", "{:$^16.6Lf}", F(1.234567e3));
+ test("0001_23_4#567000", "{:016.6Lf}", F(1.234567e3));
+ test("-1_23_4#567000$$$", "{:$<17.6Lf}", F(-1.234567e3));
+ test("$$$-1_23_4#567000", "{:$>17.6Lf}", F(-1.234567e3));
+ test("$-1_23_4#567000$$", "{:$^17.6Lf}", F(-1.234567e3));
+ test("-0001_23_4#567000", "{:017.6Lf}", F(-1.234567e3));
+
+ test("1,234.567000$$$", en_US, "{:$<15.6Lf}", F(1.234567e3));
+ test("$$$1,234.567000", en_US, "{:$>15.6Lf}", F(1.234567e3));
+ test("$1,234.567000$$", en_US, "{:$^15.6Lf}", F(1.234567e3));
+ test("0001,234.567000", en_US, "{:015.6Lf}", F(1.234567e3));
+ test("-1,234.567000$$$", en_US, "{:$<16.6Lf}", F(-1.234567e3));
+ test("$$$-1,234.567000", en_US, "{:$>16.6Lf}", F(-1.234567e3));
+ test("$-1,234.567000$$", en_US, "{:$^16.6Lf}", F(-1.234567e3));
+ test("-0001,234.567000", en_US, "{:016.6Lf}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1_23_4#567000$$$", loc, "{:$<16.6Lf}", F(1.234567e3));
+ test("$$$1_23_4#567000", loc, "{:$>16.6Lf}", F(1.234567e3));
+ test("$1_23_4#567000$$", loc, "{:$^16.6Lf}", F(1.234567e3));
+ test("0001_23_4#567000", loc, "{:016.6Lf}", F(1.234567e3));
+ test("-1_23_4#567000$$$", loc, "{:$<17.6Lf}", F(-1.234567e3));
+ test("$$$-1_23_4#567000", loc, "{:$>17.6Lf}", F(-1.234567e3));
+ test("$-1_23_4#567000$$", loc, "{:$^17.6Lf}", F(-1.234567e3));
+ test("-0001_23_4#567000", loc, "{:017.6Lf}", F(-1.234567e3));
+ }
+}
+
+template <class F>
+static void test_floating_point_fixed_upper_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("0.000001", "{:.6Lf}", F(1.234567e-6));
+ test("0.000012", "{:.6Lf}", F(1.234567e-5));
+ test("0.000123", "{:.6Lf}", F(1.234567e-4));
+ test("0.001235", "{:.6Lf}", F(1.234567e-3));
+ test("0.012346", "{:.6Lf}", F(1.234567e-2));
+ test("0.123457", "{:.6Lf}", F(1.234567e-1));
+ test("1.234567", "{:.6Lf}", F(1.234567e0));
+ test("12.345670", "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("123.456700", "{:.6Lf}", F(1.234567e2));
+ test("1,234.567000", "{:.6Lf}", F(1.234567e3));
+ test("12,345.670000", "{:.6Lf}", F(1.234567e4));
+ test("123,456.700000", "{:.6Lf}", F(1.234567e5));
+ test("1,234,567.000000", "{:.6Lf}", F(1.234567e6));
+ test("12,345,670.000000", "{:.6Lf}", F(1.234567e7));
+ test("123,456,700,000,000,000,000.000000", "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0.000001", "{:.6Lf}", F(-1.234567e-6));
+ test("-0.000012", "{:.6Lf}", F(-1.234567e-5));
+ test("-0.000123", "{:.6Lf}", F(-1.234567e-4));
+ test("-0.001235", "{:.6Lf}", F(-1.234567e-3));
+ test("-0.012346", "{:.6Lf}", F(-1.234567e-2));
+ test("-0.123457", "{:.6Lf}", F(-1.234567e-1));
+ test("-1.234567", "{:.6Lf}", F(-1.234567e0));
+ test("-12.345670", "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-123.456700", "{:.6Lf}", F(-1.234567e2));
+ test("-1,234.567000", "{:.6Lf}", F(-1.234567e3));
+ test("-12,345.670000", "{:.6Lf}", F(-1.234567e4));
+ test("-123,456.700000", "{:.6Lf}", F(-1.234567e5));
+ test("-1,234,567.000000", "{:.6Lf}", F(-1.234567e6));
+ test("-12,345,670.000000", "{:.6Lf}", F(-1.234567e7));
+ test("-123,456,700,000,000,000,000.000000", "{:.6Lf}", F(-1.234567e20));
+ }
+
+ std::locale::global(loc);
+ test("0#000001", "{:.6Lf}", F(1.234567e-6));
+ test("0#000012", "{:.6Lf}", F(1.234567e-5));
+ test("0#000123", "{:.6Lf}", F(1.234567e-4));
+ test("0#001235", "{:.6Lf}", F(1.234567e-3));
+ test("0#012346", "{:.6Lf}", F(1.234567e-2));
+ test("0#123457", "{:.6Lf}", F(1.234567e-1));
+ test("1#234567", "{:.6Lf}", F(1.234567e0));
+ test("1_2#345670", "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("12_3#456700", "{:.6Lf}", F(1.234567e2));
+ test("1_23_4#567000", "{:.6Lf}", F(1.234567e3));
+ test("12_34_5#670000", "{:.6Lf}", F(1.234567e4));
+ test("123_45_6#700000", "{:.6Lf}", F(1.234567e5));
+ test("1_234_56_7#000000", "{:.6Lf}", F(1.234567e6));
+ test("12_345_67_0#000000", "{:.6Lf}", F(1.234567e7));
+ test("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0#000001", "{:.6Lf}", F(-1.234567e-6));
+ test("-0#000012", "{:.6Lf}", F(-1.234567e-5));
+ test("-0#000123", "{:.6Lf}", F(-1.234567e-4));
+ test("-0#001235", "{:.6Lf}", F(-1.234567e-3));
+ test("-0#012346", "{:.6Lf}", F(-1.234567e-2));
+ test("-0#123457", "{:.6Lf}", F(-1.234567e-1));
+ test("-1#234567", "{:.6Lf}", F(-1.234567e0));
+ test("-1_2#345670", "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-12_3#456700", "{:.6Lf}", F(-1.234567e2));
+ test("-1_23_4#567000", "{:.6Lf}", F(-1.234567e3));
+ test("-12_34_5#670000", "{:.6Lf}", F(-1.234567e4));
+ test("-123_45_6#700000", "{:.6Lf}", F(-1.234567e5));
+ test("-1_234_56_7#000000", "{:.6Lf}", F(-1.234567e6));
+ test("-12_345_67_0#000000", "{:.6Lf}", F(-1.234567e7));
+ test("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", "{:.6Lf}", F(-1.234567e20));
+ }
+
+ test("0.000001", en_US, "{:.6Lf}", F(1.234567e-6));
+ test("0.000012", en_US, "{:.6Lf}", F(1.234567e-5));
+ test("0.000123", en_US, "{:.6Lf}", F(1.234567e-4));
+ test("0.001235", en_US, "{:.6Lf}", F(1.234567e-3));
+ test("0.012346", en_US, "{:.6Lf}", F(1.234567e-2));
+ test("0.123457", en_US, "{:.6Lf}", F(1.234567e-1));
+ test("1.234567", en_US, "{:.6Lf}", F(1.234567e0));
+ test("12.345670", en_US, "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("123.456700", en_US, "{:.6Lf}", F(1.234567e2));
+ test("1,234.567000", en_US, "{:.6Lf}", F(1.234567e3));
+ test("12,345.670000", en_US, "{:.6Lf}", F(1.234567e4));
+ test("123,456.700000", en_US, "{:.6Lf}", F(1.234567e5));
+ test("1,234,567.000000", en_US, "{:.6Lf}", F(1.234567e6));
+ test("12,345,670.000000", en_US, "{:.6Lf}", F(1.234567e7));
+ test("123,456,700,000,000,000,000.000000", en_US, "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0.000001", en_US, "{:.6Lf}", F(-1.234567e-6));
+ test("-0.000012", en_US, "{:.6Lf}", F(-1.234567e-5));
+ test("-0.000123", en_US, "{:.6Lf}", F(-1.234567e-4));
+ test("-0.001235", en_US, "{:.6Lf}", F(-1.234567e-3));
+ test("-0.012346", en_US, "{:.6Lf}", F(-1.234567e-2));
+ test("-0.123457", en_US, "{:.6Lf}", F(-1.234567e-1));
+ test("-1.234567", en_US, "{:.6Lf}", F(-1.234567e0));
+ test("-12.345670", en_US, "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-123.456700", en_US, "{:.6Lf}", F(-1.234567e2));
+ test("-1,234.567000", en_US, "{:.6Lf}", F(-1.234567e3));
+ test("-12,345.670000", en_US, "{:.6Lf}", F(-1.234567e4));
+ test("-123,456.700000", en_US, "{:.6Lf}", F(-1.234567e5));
+ test("-1,234,567.000000", en_US, "{:.6Lf}", F(-1.234567e6));
+ test("-12,345,670.000000", en_US, "{:.6Lf}", F(-1.234567e7));
+ test("-123,456,700,000,000,000,000.000000", en_US, "{:.6Lf}", F(-1.234567e20));
+ }
+
+ std::locale::global(en_US);
+ test("0#000001", loc, "{:.6Lf}", F(1.234567e-6));
+ test("0#000012", loc, "{:.6Lf}", F(1.234567e-5));
+ test("0#000123", loc, "{:.6Lf}", F(1.234567e-4));
+ test("0#001235", loc, "{:.6Lf}", F(1.234567e-3));
+ test("0#012346", loc, "{:.6Lf}", F(1.234567e-2));
+ test("0#123457", loc, "{:.6Lf}", F(1.234567e-1));
+ test("1#234567", loc, "{:.6Lf}", F(1.234567e0));
+ test("1_2#345670", loc, "{:.6Lf}", F(1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("12_3#456700", loc, "{:.6Lf}", F(1.234567e2));
+ test("1_23_4#567000", loc, "{:.6Lf}", F(1.234567e3));
+ test("12_34_5#670000", loc, "{:.6Lf}", F(1.234567e4));
+ test("123_45_6#700000", loc, "{:.6Lf}", F(1.234567e5));
+ test("1_234_56_7#000000", loc, "{:.6Lf}", F(1.234567e6));
+ test("12_345_67_0#000000", loc, "{:.6Lf}", F(1.234567e7));
+ test("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", loc, "{:.6Lf}", F(1.234567e20));
+ }
+ test("-0#000001", loc, "{:.6Lf}", F(-1.234567e-6));
+ test("-0#000012", loc, "{:.6Lf}", F(-1.234567e-5));
+ test("-0#000123", loc, "{:.6Lf}", F(-1.234567e-4));
+ test("-0#001235", loc, "{:.6Lf}", F(-1.234567e-3));
+ test("-0#012346", loc, "{:.6Lf}", F(-1.234567e-2));
+ test("-0#123457", loc, "{:.6Lf}", F(-1.234567e-1));
+ test("-1#234567", loc, "{:.6Lf}", F(-1.234567e0));
+ test("-1_2#345670", loc, "{:.6Lf}", F(-1.234567e1));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-12_3#456700", loc, "{:.6Lf}", F(-1.234567e2));
+ test("-1_23_4#567000", loc, "{:.6Lf}", F(-1.234567e3));
+ test("-12_34_5#670000", loc, "{:.6Lf}", F(-1.234567e4));
+ test("-123_45_6#700000", loc, "{:.6Lf}", F(-1.234567e5));
+ test("-1_234_56_7#000000", loc, "{:.6Lf}", F(-1.234567e6));
+ test("-12_345_67_0#000000", loc, "{:.6Lf}", F(-1.234567e7));
+ test("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000", loc, "{:.6Lf}", F(-1.234567e20));
+ }
+
+ // *** Fill, align, zero padding ***
+ if constexpr (sizeof(F) > sizeof(float)) {
+ std::locale::global(en_US);
+ test("1,234.567000$$$", "{:$<15.6Lf}", F(1.234567e3));
+ test("$$$1,234.567000", "{:$>15.6Lf}", F(1.234567e3));
+ test("$1,234.567000$$", "{:$^15.6Lf}", F(1.234567e3));
+ test("0001,234.567000", "{:015.6Lf}", F(1.234567e3));
+ test("-1,234.567000$$$", "{:$<16.6Lf}", F(-1.234567e3));
+ test("$$$-1,234.567000", "{:$>16.6Lf}", F(-1.234567e3));
+ test("$-1,234.567000$$", "{:$^16.6Lf}", F(-1.234567e3));
+ test("-0001,234.567000", "{:016.6Lf}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1_23_4#567000$$$", "{:$<16.6Lf}", F(1.234567e3));
+ test("$$$1_23_4#567000", "{:$>16.6Lf}", F(1.234567e3));
+ test("$1_23_4#567000$$", "{:$^16.6Lf}", F(1.234567e3));
+ test("0001_23_4#567000", "{:016.6Lf}", F(1.234567e3));
+ test("-1_23_4#567000$$$", "{:$<17.6Lf}", F(-1.234567e3));
+ test("$$$-1_23_4#567000", "{:$>17.6Lf}", F(-1.234567e3));
+ test("$-1_23_4#567000$$", "{:$^17.6Lf}", F(-1.234567e3));
+ test("-0001_23_4#567000", "{:017.6Lf}", F(-1.234567e3));
+
+ test("1,234.567000$$$", en_US, "{:$<15.6Lf}", F(1.234567e3));
+ test("$$$1,234.567000", en_US, "{:$>15.6Lf}", F(1.234567e3));
+ test("$1,234.567000$$", en_US, "{:$^15.6Lf}", F(1.234567e3));
+ test("0001,234.567000", en_US, "{:015.6Lf}", F(1.234567e3));
+ test("-1,234.567000$$$", en_US, "{:$<16.6Lf}", F(-1.234567e3));
+ test("$$$-1,234.567000", en_US, "{:$>16.6Lf}", F(-1.234567e3));
+ test("$-1,234.567000$$", en_US, "{:$^16.6Lf}", F(-1.234567e3));
+ test("-0001,234.567000", en_US, "{:016.6Lf}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1_23_4#567000$$$", loc, "{:$<16.6Lf}", F(1.234567e3));
+ test("$$$1_23_4#567000", loc, "{:$>16.6Lf}", F(1.234567e3));
+ test("$1_23_4#567000$$", loc, "{:$^16.6Lf}", F(1.234567e3));
+ test("0001_23_4#567000", loc, "{:016.6Lf}", F(1.234567e3));
+ test("-1_23_4#567000$$$", loc, "{:$<17.6Lf}", F(-1.234567e3));
+ test("$$$-1_23_4#567000", loc, "{:$>17.6Lf}", F(-1.234567e3));
+ test("$-1_23_4#567000$$", loc, "{:$^17.6Lf}", F(-1.234567e3));
+ test("-0001_23_4#567000", loc, "{:017.6Lf}", F(-1.234567e3));
+ }
+}
+
+template <class F>
+static void test_floating_point_general_lower_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.23457e-06", "{:.6Lg}", F(1.234567e-6));
+ test("1.23457e-05", "{:.6Lg}", F(1.234567e-5));
+ test("0.000123457", "{:.6Lg}", F(1.234567e-4));
+ test("0.00123457", "{:.6Lg}", F(1.234567e-3));
+ test("0.0123457", "{:.6Lg}", F(1.234567e-2));
+ test("0.123457", "{:.6Lg}", F(1.234567e-1));
+ test("1.23457", "{:.6Lg}", F(1.234567e0));
+ test("12.3457", "{:.6Lg}", F(1.234567e1));
+ test("123.457", "{:.6Lg}", F(1.234567e2));
+ test("1,234.57", "{:.6Lg}", F(1.234567e3));
+ test("12,345.7", "{:.6Lg}", F(1.234567e4));
+ test("123,457", "{:.6Lg}", F(1.234567e5));
+ test("1.23457e+06", "{:.6Lg}", F(1.234567e6));
+ test("1.23457e+07", "{:.6Lg}", F(1.234567e7));
+ test("-1.23457e-06", "{:.6Lg}", F(-1.234567e-6));
+ test("-1.23457e-05", "{:.6Lg}", F(-1.234567e-5));
+ test("-0.000123457", "{:.6Lg}", F(-1.234567e-4));
+ test("-0.00123457", "{:.6Lg}", F(-1.234567e-3));
+ test("-0.0123457", "{:.6Lg}", F(-1.234567e-2));
+ test("-0.123457", "{:.6Lg}", F(-1.234567e-1));
+ test("-1.23457", "{:.6Lg}", F(-1.234567e0));
+ test("-12.3457", "{:.6Lg}", F(-1.234567e1));
+ test("-123.457", "{:.6Lg}", F(-1.234567e2));
+ test("-1,234.57", "{:.6Lg}", F(-1.234567e3));
+ test("-12,345.7", "{:.6Lg}", F(-1.234567e4));
+ test("-123,457", "{:.6Lg}", F(-1.234567e5));
+ test("-1.23457e+06", "{:.6Lg}", F(-1.234567e6));
+ test("-1.23457e+07", "{:.6Lg}", F(-1.234567e7));
+
+ std::locale::global(loc);
+ test("1#23457e-06", "{:.6Lg}", F(1.234567e-6));
+ test("1#23457e-05", "{:.6Lg}", F(1.234567e-5));
+ test("0#000123457", "{:.6Lg}", F(1.234567e-4));
+ test("0#00123457", "{:.6Lg}", F(1.234567e-3));
+ test("0#0123457", "{:.6Lg}", F(1.234567e-2));
+ test("0#123457", "{:.6Lg}", F(1.234567e-1));
+ test("1#23457", "{:.6Lg}", F(1.234567e0));
+ test("1_2#3457", "{:.6Lg}", F(1.234567e1));
+ test("12_3#457", "{:.6Lg}", F(1.234567e2));
+ test("1_23_4#57", "{:.6Lg}", F(1.234567e3));
+ test("12_34_5#7", "{:.6Lg}", F(1.234567e4));
+ test("123_45_7", "{:.6Lg}", F(1.234567e5));
+ test("1#23457e+06", "{:.6Lg}", F(1.234567e6));
+ test("1#23457e+07", "{:.6Lg}", F(1.234567e7));
+ test("-1#23457e-06", "{:.6Lg}", F(-1.234567e-6));
+ test("-1#23457e-05", "{:.6Lg}", F(-1.234567e-5));
+ test("-0#000123457", "{:.6Lg}", F(-1.234567e-4));
+ test("-0#00123457", "{:.6Lg}", F(-1.234567e-3));
+ test("-0#0123457", "{:.6Lg}", F(-1.234567e-2));
+ test("-0#123457", "{:.6Lg}", F(-1.234567e-1));
+ test("-1#23457", "{:.6Lg}", F(-1.234567e0));
+ test("-1_2#3457", "{:.6Lg}", F(-1.234567e1));
+ test("-12_3#457", "{:.6Lg}", F(-1.234567e2));
+ test("-1_23_4#57", "{:.6Lg}", F(-1.234567e3));
+ test("-12_34_5#7", "{:.6Lg}", F(-1.234567e4));
+ test("-123_45_7", "{:.6Lg}", F(-1.234567e5));
+ test("-1#23457e+06", "{:.6Lg}", F(-1.234567e6));
+ test("-1#23457e+07", "{:.6Lg}", F(-1.234567e7));
+
+ test("1.23457e-06", en_US, "{:.6Lg}", F(1.234567e-6));
+ test("1.23457e-05", en_US, "{:.6Lg}", F(1.234567e-5));
+ test("0.000123457", en_US, "{:.6Lg}", F(1.234567e-4));
+ test("0.00123457", en_US, "{:.6Lg}", F(1.234567e-3));
+ test("0.0123457", en_US, "{:.6Lg}", F(1.234567e-2));
+ test("0.123457", en_US, "{:.6Lg}", F(1.234567e-1));
+ test("1.23457", en_US, "{:.6Lg}", F(1.234567e0));
+ test("12.3457", en_US, "{:.6Lg}", F(1.234567e1));
+ test("123.457", en_US, "{:.6Lg}", F(1.234567e2));
+ test("1,234.57", en_US, "{:.6Lg}", F(1.234567e3));
+ test("12,345.7", en_US, "{:.6Lg}", F(1.234567e4));
+ test("123,457", en_US, "{:.6Lg}", F(1.234567e5));
+ test("1.23457e+06", en_US, "{:.6Lg}", F(1.234567e6));
+ test("1.23457e+07", en_US, "{:.6Lg}", F(1.234567e7));
+ test("-1.23457e-06", en_US, "{:.6Lg}", F(-1.234567e-6));
+ test("-1.23457e-05", en_US, "{:.6Lg}", F(-1.234567e-5));
+ test("-0.000123457", en_US, "{:.6Lg}", F(-1.234567e-4));
+ test("-0.00123457", en_US, "{:.6Lg}", F(-1.234567e-3));
+ test("-0.0123457", en_US, "{:.6Lg}", F(-1.234567e-2));
+ test("-0.123457", en_US, "{:.6Lg}", F(-1.234567e-1));
+ test("-1.23457", en_US, "{:.6Lg}", F(-1.234567e0));
+ test("-12.3457", en_US, "{:.6Lg}", F(-1.234567e1));
+ test("-123.457", en_US, "{:.6Lg}", F(-1.234567e2));
+ test("-1,234.57", en_US, "{:.6Lg}", F(-1.234567e3));
+ test("-12,345.7", en_US, "{:.6Lg}", F(-1.234567e4));
+ test("-123,457", en_US, "{:.6Lg}", F(-1.234567e5));
+ test("-1.23457e+06", en_US, "{:.6Lg}", F(-1.234567e6));
+ test("-1.23457e+07", en_US, "{:.6Lg}", F(-1.234567e7));
+
+ std::locale::global(en_US);
+ test("1#23457e-06", loc, "{:.6Lg}", F(1.234567e-6));
+ test("1#23457e-05", loc, "{:.6Lg}", F(1.234567e-5));
+ test("0#000123457", loc, "{:.6Lg}", F(1.234567e-4));
+ test("0#00123457", loc, "{:.6Lg}", F(1.234567e-3));
+ test("0#0123457", loc, "{:.6Lg}", F(1.234567e-2));
+ test("0#123457", loc, "{:.6Lg}", F(1.234567e-1));
+ test("1#23457", loc, "{:.6Lg}", F(1.234567e0));
+ test("1_2#3457", loc, "{:.6Lg}", F(1.234567e1));
+ test("12_3#457", loc, "{:.6Lg}", F(1.234567e2));
+ test("1_23_4#57", loc, "{:.6Lg}", F(1.234567e3));
+ test("12_34_5#7", loc, "{:.6Lg}", F(1.234567e4));
+ test("123_45_7", loc, "{:.6Lg}", F(1.234567e5));
+ test("1#23457e+06", loc, "{:.6Lg}", F(1.234567e6));
+ test("1#23457e+07", loc, "{:.6Lg}", F(1.234567e7));
+ test("-1#23457e-06", loc, "{:.6Lg}", F(-1.234567e-6));
+ test("-1#23457e-05", loc, "{:.6Lg}", F(-1.234567e-5));
+ test("-0#000123457", loc, "{:.6Lg}", F(-1.234567e-4));
+ test("-0#00123457", loc, "{:.6Lg}", F(-1.234567e-3));
+ test("-0#0123457", loc, "{:.6Lg}", F(-1.234567e-2));
+ test("-0#123457", loc, "{:.6Lg}", F(-1.234567e-1));
+ test("-1#23457", loc, "{:.6Lg}", F(-1.234567e0));
+ test("-1_2#3457", loc, "{:.6Lg}", F(-1.234567e1));
+ test("-12_3#457", loc, "{:.6Lg}", F(-1.234567e2));
+ test("-1_23_4#57", loc, "{:.6Lg}", F(-1.234567e3));
+ test("-12_34_5#7", loc, "{:.6Lg}", F(-1.234567e4));
+ test("-123_45_7", loc, "{:.6Lg}", F(-1.234567e5));
+ test("-1#23457e+06", loc, "{:.6Lg}", F(-1.234567e6));
+ test("-1#23457e+07", loc, "{:.6Lg}", F(-1.234567e7));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1,234.57$$$", "{:$<11.6Lg}", F(1.234567e3));
+ test("$$$1,234.57", "{:$>11.6Lg}", F(1.234567e3));
+ test("$1,234.57$$", "{:$^11.6Lg}", F(1.234567e3));
+ test("0001,234.57", "{:011.6Lg}", F(1.234567e3));
+ test("-1,234.57$$$", "{:$<12.6Lg}", F(-1.234567e3));
+ test("$$$-1,234.57", "{:$>12.6Lg}", F(-1.234567e3));
+ test("$-1,234.57$$", "{:$^12.6Lg}", F(-1.234567e3));
+ test("-0001,234.57", "{:012.6Lg}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1_23_4#57$$$", "{:$<12.6Lg}", F(1.234567e3));
+ test("$$$1_23_4#57", "{:$>12.6Lg}", F(1.234567e3));
+ test("$1_23_4#57$$", "{:$^12.6Lg}", F(1.234567e3));
+ test("0001_23_4#57", "{:012.6Lg}", F(1.234567e3));
+ test("-1_23_4#57$$$", "{:$<13.6Lg}", F(-1.234567e3));
+ test("$$$-1_23_4#57", "{:$>13.6Lg}", F(-1.234567e3));
+ test("$-1_23_4#57$$", "{:$^13.6Lg}", F(-1.234567e3));
+ test("-0001_23_4#57", "{:013.6Lg}", F(-1.234567e3));
+
+ test("1,234.57$$$", en_US, "{:$<11.6Lg}", F(1.234567e3));
+ test("$$$1,234.57", en_US, "{:$>11.6Lg}", F(1.234567e3));
+ test("$1,234.57$$", en_US, "{:$^11.6Lg}", F(1.234567e3));
+ test("0001,234.57", en_US, "{:011.6Lg}", F(1.234567e3));
+ test("-1,234.57$$$", en_US, "{:$<12.6Lg}", F(-1.234567e3));
+ test("$$$-1,234.57", en_US, "{:$>12.6Lg}", F(-1.234567e3));
+ test("$-1,234.57$$", en_US, "{:$^12.6Lg}", F(-1.234567e3));
+ test("-0001,234.57", en_US, "{:012.6Lg}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1_23_4#57$$$", loc, "{:$<12.6Lg}", F(1.234567e3));
+ test("$$$1_23_4#57", loc, "{:$>12.6Lg}", F(1.234567e3));
+ test("$1_23_4#57$$", loc, "{:$^12.6Lg}", F(1.234567e3));
+ test("0001_23_4#57", loc, "{:012.6Lg}", F(1.234567e3));
+ test("-1_23_4#57$$$", loc, "{:$<13.6Lg}", F(-1.234567e3));
+ test("$$$-1_23_4#57", loc, "{:$>13.6Lg}", F(-1.234567e3));
+ test("$-1_23_4#57$$", loc, "{:$^13.6Lg}", F(-1.234567e3));
+ test("-0001_23_4#57", loc, "{:013.6Lg}", F(-1.234567e3));
+}
+
+template <class F>
+static void test_floating_point_general_upper_case() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.23457E-06", "{:.6LG}", F(1.234567e-6));
+ test("1.23457E-05", "{:.6LG}", F(1.234567e-5));
+ test("0.000123457", "{:.6LG}", F(1.234567e-4));
+ test("0.00123457", "{:.6LG}", F(1.234567e-3));
+ test("0.0123457", "{:.6LG}", F(1.234567e-2));
+ test("0.123457", "{:.6LG}", F(1.234567e-1));
+ test("1.23457", "{:.6LG}", F(1.234567e0));
+ test("12.3457", "{:.6LG}", F(1.234567e1));
+ test("123.457", "{:.6LG}", F(1.234567e2));
+ test("1,234.57", "{:.6LG}", F(1.234567e3));
+ test("12,345.7", "{:.6LG}", F(1.234567e4));
+ test("123,457", "{:.6LG}", F(1.234567e5));
+ test("1.23457E+06", "{:.6LG}", F(1.234567e6));
+ test("1.23457E+07", "{:.6LG}", F(1.234567e7));
+ test("-1.23457E-06", "{:.6LG}", F(-1.234567e-6));
+ test("-1.23457E-05", "{:.6LG}", F(-1.234567e-5));
+ test("-0.000123457", "{:.6LG}", F(-1.234567e-4));
+ test("-0.00123457", "{:.6LG}", F(-1.234567e-3));
+ test("-0.0123457", "{:.6LG}", F(-1.234567e-2));
+ test("-0.123457", "{:.6LG}", F(-1.234567e-1));
+ test("-1.23457", "{:.6LG}", F(-1.234567e0));
+ test("-12.3457", "{:.6LG}", F(-1.234567e1));
+ test("-123.457", "{:.6LG}", F(-1.234567e2));
+ test("-1,234.57", "{:.6LG}", F(-1.234567e3));
+ test("-12,345.7", "{:.6LG}", F(-1.234567e4));
+ test("-123,457", "{:.6LG}", F(-1.234567e5));
+ test("-1.23457E+06", "{:.6LG}", F(-1.234567e6));
+ test("-1.23457E+07", "{:.6LG}", F(-1.234567e7));
+
+ std::locale::global(loc);
+ test("1#23457E-06", "{:.6LG}", F(1.234567e-6));
+ test("1#23457E-05", "{:.6LG}", F(1.234567e-5));
+ test("0#000123457", "{:.6LG}", F(1.234567e-4));
+ test("0#00123457", "{:.6LG}", F(1.234567e-3));
+ test("0#0123457", "{:.6LG}", F(1.234567e-2));
+ test("0#123457", "{:.6LG}", F(1.234567e-1));
+ test("1#23457", "{:.6LG}", F(1.234567e0));
+ test("1_2#3457", "{:.6LG}", F(1.234567e1));
+ test("12_3#457", "{:.6LG}", F(1.234567e2));
+ test("1_23_4#57", "{:.6LG}", F(1.234567e3));
+ test("12_34_5#7", "{:.6LG}", F(1.234567e4));
+ test("123_45_7", "{:.6LG}", F(1.234567e5));
+ test("1#23457E+06", "{:.6LG}", F(1.234567e6));
+ test("1#23457E+07", "{:.6LG}", F(1.234567e7));
+ test("-1#23457E-06", "{:.6LG}", F(-1.234567e-6));
+ test("-1#23457E-05", "{:.6LG}", F(-1.234567e-5));
+ test("-0#000123457", "{:.6LG}", F(-1.234567e-4));
+ test("-0#00123457", "{:.6LG}", F(-1.234567e-3));
+ test("-0#0123457", "{:.6LG}", F(-1.234567e-2));
+ test("-0#123457", "{:.6LG}", F(-1.234567e-1));
+ test("-1#23457", "{:.6LG}", F(-1.234567e0));
+ test("-1_2#3457", "{:.6LG}", F(-1.234567e1));
+ test("-12_3#457", "{:.6LG}", F(-1.234567e2));
+ test("-1_23_4#57", "{:.6LG}", F(-1.234567e3));
+ test("-12_34_5#7", "{:.6LG}", F(-1.234567e4));
+ test("-123_45_7", "{:.6LG}", F(-1.234567e5));
+ test("-1#23457E+06", "{:.6LG}", F(-1.234567e6));
+ test("-1#23457E+07", "{:.6LG}", F(-1.234567e7));
+
+ test("1.23457E-06", en_US, "{:.6LG}", F(1.234567e-6));
+ test("1.23457E-05", en_US, "{:.6LG}", F(1.234567e-5));
+ test("0.000123457", en_US, "{:.6LG}", F(1.234567e-4));
+ test("0.00123457", en_US, "{:.6LG}", F(1.234567e-3));
+ test("0.0123457", en_US, "{:.6LG}", F(1.234567e-2));
+ test("0.123457", en_US, "{:.6LG}", F(1.234567e-1));
+ test("1.23457", en_US, "{:.6LG}", F(1.234567e0));
+ test("12.3457", en_US, "{:.6LG}", F(1.234567e1));
+ test("123.457", en_US, "{:.6LG}", F(1.234567e2));
+ test("1,234.57", en_US, "{:.6LG}", F(1.234567e3));
+ test("12,345.7", en_US, "{:.6LG}", F(1.234567e4));
+ test("123,457", en_US, "{:.6LG}", F(1.234567e5));
+ test("1.23457E+06", en_US, "{:.6LG}", F(1.234567e6));
+ test("1.23457E+07", en_US, "{:.6LG}", F(1.234567e7));
+ test("-1.23457E-06", en_US, "{:.6LG}", F(-1.234567e-6));
+ test("-1.23457E-05", en_US, "{:.6LG}", F(-1.234567e-5));
+ test("-0.000123457", en_US, "{:.6LG}", F(-1.234567e-4));
+ test("-0.00123457", en_US, "{:.6LG}", F(-1.234567e-3));
+ test("-0.0123457", en_US, "{:.6LG}", F(-1.234567e-2));
+ test("-0.123457", en_US, "{:.6LG}", F(-1.234567e-1));
+ test("-1.23457", en_US, "{:.6LG}", F(-1.234567e0));
+ test("-12.3457", en_US, "{:.6LG}", F(-1.234567e1));
+ test("-123.457", en_US, "{:.6LG}", F(-1.234567e2));
+ test("-1,234.57", en_US, "{:.6LG}", F(-1.234567e3));
+ test("-12,345.7", en_US, "{:.6LG}", F(-1.234567e4));
+ test("-123,457", en_US, "{:.6LG}", F(-1.234567e5));
+ test("-1.23457E+06", en_US, "{:.6LG}", F(-1.234567e6));
+ test("-1.23457E+07", en_US, "{:.6LG}", F(-1.234567e7));
+
+ std::locale::global(en_US);
+ test("1#23457E-06", loc, "{:.6LG}", F(1.234567e-6));
+ test("1#23457E-05", loc, "{:.6LG}", F(1.234567e-5));
+ test("0#000123457", loc, "{:.6LG}", F(1.234567e-4));
+ test("0#00123457", loc, "{:.6LG}", F(1.234567e-3));
+ test("0#0123457", loc, "{:.6LG}", F(1.234567e-2));
+ test("0#123457", loc, "{:.6LG}", F(1.234567e-1));
+ test("1#23457", loc, "{:.6LG}", F(1.234567e0));
+ test("1_2#3457", loc, "{:.6LG}", F(1.234567e1));
+ test("12_3#457", loc, "{:.6LG}", F(1.234567e2));
+ test("1_23_4#57", loc, "{:.6LG}", F(1.234567e3));
+ test("12_34_5#7", loc, "{:.6LG}", F(1.234567e4));
+ test("123_45_7", loc, "{:.6LG}", F(1.234567e5));
+ test("1#23457E+06", loc, "{:.6LG}", F(1.234567e6));
+ test("1#23457E+07", loc, "{:.6LG}", F(1.234567e7));
+ test("-1#23457E-06", loc, "{:.6LG}", F(-1.234567e-6));
+ test("-1#23457E-05", loc, "{:.6LG}", F(-1.234567e-5));
+ test("-0#000123457", loc, "{:.6LG}", F(-1.234567e-4));
+ test("-0#00123457", loc, "{:.6LG}", F(-1.234567e-3));
+ test("-0#0123457", loc, "{:.6LG}", F(-1.234567e-2));
+ test("-0#123457", loc, "{:.6LG}", F(-1.234567e-1));
+ test("-1#23457", loc, "{:.6LG}", F(-1.234567e0));
+ test("-1_2#3457", loc, "{:.6LG}", F(-1.234567e1));
+ test("-12_3#457", loc, "{:.6LG}", F(-1.234567e2));
+ test("-1_23_4#57", loc, "{:.6LG}", F(-1.234567e3));
+ test("-12_34_5#7", loc, "{:.6LG}", F(-1.234567e4));
+ test("-123_45_7", loc, "{:.6LG}", F(-1.234567e5));
+ test("-1#23457E+06", loc, "{:.6LG}", F(-1.234567e6));
+ test("-1#23457E+07", loc, "{:.6LG}", F(-1.234567e7));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1,234.57$$$", "{:$<11.6LG}", F(1.234567e3));
+ test("$$$1,234.57", "{:$>11.6LG}", F(1.234567e3));
+ test("$1,234.57$$", "{:$^11.6LG}", F(1.234567e3));
+ test("0001,234.57", "{:011.6LG}", F(1.234567e3));
+ test("-1,234.57$$$", "{:$<12.6LG}", F(-1.234567e3));
+ test("$$$-1,234.57", "{:$>12.6LG}", F(-1.234567e3));
+ test("$-1,234.57$$", "{:$^12.6LG}", F(-1.234567e3));
+ test("-0001,234.57", "{:012.6LG}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1_23_4#57$$$", "{:$<12.6LG}", F(1.234567e3));
+ test("$$$1_23_4#57", "{:$>12.6LG}", F(1.234567e3));
+ test("$1_23_4#57$$", "{:$^12.6LG}", F(1.234567e3));
+ test("0001_23_4#57", "{:012.6LG}", F(1.234567e3));
+ test("-1_23_4#57$$$", "{:$<13.6LG}", F(-1.234567e3));
+ test("$$$-1_23_4#57", "{:$>13.6LG}", F(-1.234567e3));
+ test("$-1_23_4#57$$", "{:$^13.6LG}", F(-1.234567e3));
+ test("-0001_23_4#57", "{:013.6LG}", F(-1.234567e3));
+
+ test("1,234.57$$$", en_US, "{:$<11.6LG}", F(1.234567e3));
+ test("$$$1,234.57", en_US, "{:$>11.6LG}", F(1.234567e3));
+ test("$1,234.57$$", en_US, "{:$^11.6LG}", F(1.234567e3));
+ test("0001,234.57", en_US, "{:011.6LG}", F(1.234567e3));
+ test("-1,234.57$$$", en_US, "{:$<12.6LG}", F(-1.234567e3));
+ test("$$$-1,234.57", en_US, "{:$>12.6LG}", F(-1.234567e3));
+ test("$-1,234.57$$", en_US, "{:$^12.6LG}", F(-1.234567e3));
+ test("-0001,234.57", en_US, "{:012.6LG}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1_23_4#57$$$", loc, "{:$<12.6LG}", F(1.234567e3));
+ test("$$$1_23_4#57", loc, "{:$>12.6LG}", F(1.234567e3));
+ test("$1_23_4#57$$", loc, "{:$^12.6LG}", F(1.234567e3));
+ test("0001_23_4#57", loc, "{:012.6LG}", F(1.234567e3));
+ test("-1_23_4#57$$$", loc, "{:$<13.6LG}", F(-1.234567e3));
+ test("$$$-1_23_4#57", loc, "{:$>13.6LG}", F(-1.234567e3));
+ test("$-1_23_4#57$$", loc, "{:$^13.6LG}", F(-1.234567e3));
+ test("-0001_23_4#57", loc, "{:013.6LG}", F(-1.234567e3));
+}
+
+template <class F>
+static void test_floating_point_default() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.234567e-06", "{:L}", F(1.234567e-6));
+ test("1.234567e-05", "{:L}", F(1.234567e-5));
+ test("0.0001234567", "{:L}", F(1.234567e-4));
+ test("0.001234567", "{:L}", F(1.234567e-3));
+ test("0.01234567", "{:L}", F(1.234567e-2));
+ test("0.1234567", "{:L}", F(1.234567e-1));
+ test("1.234567", "{:L}", F(1.234567e0));
+ test("12.34567", "{:L}", F(1.234567e1));
+ test("123.4567", "{:L}", F(1.234567e2));
+ test("1,234.567", "{:L}", F(1.234567e3));
+ test("12,345.67", "{:L}", F(1.234567e4));
+ test("123,456.7", "{:L}", F(1.234567e5));
+ test("1,234,567", "{:L}", F(1.234567e6));
+ test("12,345,670", "{:L}", F(1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("123,456,700", "{:L}", F(1.234567e8));
+ test("1,234,567,000", "{:L}", F(1.234567e9));
+ test("12,345,670,000", "{:L}", F(1.234567e10));
+ test("123,456,700,000", "{:L}", F(1.234567e11));
+ test("1.234567e+12", "{:L}", F(1.234567e12));
+ test("1.234567e+13", "{:L}", F(1.234567e13));
+ }
+ test("-1.234567e-06", "{:L}", F(-1.234567e-6));
+ test("-1.234567e-05", "{:L}", F(-1.234567e-5));
+ test("-0.0001234567", "{:L}", F(-1.234567e-4));
+ test("-0.001234567", "{:L}", F(-1.234567e-3));
+ test("-0.01234567", "{:L}", F(-1.234567e-2));
+ test("-0.1234567", "{:L}", F(-1.234567e-1));
+ test("-1.234567", "{:L}", F(-1.234567e0));
+ test("-12.34567", "{:L}", F(-1.234567e1));
+ test("-123.4567", "{:L}", F(-1.234567e2));
+ test("-1,234.567", "{:L}", F(-1.234567e3));
+ test("-12,345.67", "{:L}", F(-1.234567e4));
+ test("-123,456.7", "{:L}", F(-1.234567e5));
+ test("-1,234,567", "{:L}", F(-1.234567e6));
+ test("-12,345,670", "{:L}", F(-1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-123,456,700", "{:L}", F(-1.234567e8));
+ test("-1,234,567,000", "{:L}", F(-1.234567e9));
+ test("-12,345,670,000", "{:L}", F(-1.234567e10));
+ test("-123,456,700,000", "{:L}", F(-1.234567e11));
+ test("-1.234567e+12", "{:L}", F(-1.234567e12));
+ test("-1.234567e+13", "{:L}", F(-1.234567e13));
+ }
+
+ std::locale::global(loc);
+ test("1#234567e-06", "{:L}", F(1.234567e-6));
+ test("1#234567e-05", "{:L}", F(1.234567e-5));
+ test("0#0001234567", "{:L}", F(1.234567e-4));
+ test("0#001234567", "{:L}", F(1.234567e-3));
+ test("0#01234567", "{:L}", F(1.234567e-2));
+ test("0#1234567", "{:L}", F(1.234567e-1));
+ test("1#234567", "{:L}", F(1.234567e0));
+ test("1_2#34567", "{:L}", F(1.234567e1));
+ test("12_3#4567", "{:L}", F(1.234567e2));
+ test("1_23_4#567", "{:L}", F(1.234567e3));
+ test("12_34_5#67", "{:L}", F(1.234567e4));
+ test("123_45_6#7", "{:L}", F(1.234567e5));
+ test("1_234_56_7", "{:L}", F(1.234567e6));
+ test("12_345_67_0", "{:L}", F(1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("1_23_456_70_0", "{:L}", F(1.234567e8));
+ test("1_2_34_567_00_0", "{:L}", F(1.234567e9));
+ test("1_2_3_45_670_00_0", "{:L}", F(1.234567e10));
+ test("1_2_3_4_56_700_00_0", "{:L}", F(1.234567e11));
+ test("1#234567e+12", "{:L}", F(1.234567e12));
+ test("1#234567e+13", "{:L}", F(1.234567e13));
+ }
+ test("-1#234567e-06", "{:L}", F(-1.234567e-6));
+ test("-1#234567e-05", "{:L}", F(-1.234567e-5));
+ test("-0#0001234567", "{:L}", F(-1.234567e-4));
+ test("-0#001234567", "{:L}", F(-1.234567e-3));
+ test("-0#01234567", "{:L}", F(-1.234567e-2));
+ test("-0#1234567", "{:L}", F(-1.234567e-1));
+ test("-1#234567", "{:L}", F(-1.234567e0));
+ test("-1_2#34567", "{:L}", F(-1.234567e1));
+ test("-12_3#4567", "{:L}", F(-1.234567e2));
+ test("-1_23_4#567", "{:L}", F(-1.234567e3));
+ test("-12_34_5#67", "{:L}", F(-1.234567e4));
+ test("-123_45_6#7", "{:L}", F(-1.234567e5));
+ test("-1_234_56_7", "{:L}", F(-1.234567e6));
+ test("-12_345_67_0", "{:L}", F(-1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-1_23_456_70_0", "{:L}", F(-1.234567e8));
+ test("-1_2_34_567_00_0", "{:L}", F(-1.234567e9));
+ test("-1_2_3_45_670_00_0", "{:L}", F(-1.234567e10));
+ test("-1_2_3_4_56_700_00_0", "{:L}", F(-1.234567e11));
+ test("-1#234567e+12", "{:L}", F(-1.234567e12));
+ test("-1#234567e+13", "{:L}", F(-1.234567e13));
+ }
+
+ test("1.234567e-06", en_US, "{:L}", F(1.234567e-6));
+ test("1.234567e-05", en_US, "{:L}", F(1.234567e-5));
+ test("0.0001234567", en_US, "{:L}", F(1.234567e-4));
+ test("0.001234567", en_US, "{:L}", F(1.234567e-3));
+ test("0.01234567", en_US, "{:L}", F(1.234567e-2));
+ test("0.1234567", en_US, "{:L}", F(1.234567e-1));
+ test("1.234567", en_US, "{:L}", F(1.234567e0));
+ test("12.34567", en_US, "{:L}", F(1.234567e1));
+ test("123.4567", en_US, "{:L}", F(1.234567e2));
+ test("1,234.567", en_US, "{:L}", F(1.234567e3));
+ test("12,345.67", en_US, "{:L}", F(1.234567e4));
+ test("123,456.7", en_US, "{:L}", F(1.234567e5));
+ test("1,234,567", en_US, "{:L}", F(1.234567e6));
+ test("12,345,670", en_US, "{:L}", F(1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("123,456,700", en_US, "{:L}", F(1.234567e8));
+ test("1,234,567,000", en_US, "{:L}", F(1.234567e9));
+ test("12,345,670,000", en_US, "{:L}", F(1.234567e10));
+ test("123,456,700,000", en_US, "{:L}", F(1.234567e11));
+ test("1.234567e+12", en_US, "{:L}", F(1.234567e12));
+ test("1.234567e+13", en_US, "{:L}", F(1.234567e13));
+ }
+ test("-1.234567e-06", en_US, "{:L}", F(-1.234567e-6));
+ test("-1.234567e-05", en_US, "{:L}", F(-1.234567e-5));
+ test("-0.0001234567", en_US, "{:L}", F(-1.234567e-4));
+ test("-0.001234567", en_US, "{:L}", F(-1.234567e-3));
+ test("-0.01234567", en_US, "{:L}", F(-1.234567e-2));
+ test("-0.1234567", en_US, "{:L}", F(-1.234567e-1));
+ test("-1.234567", en_US, "{:L}", F(-1.234567e0));
+ test("-12.34567", en_US, "{:L}", F(-1.234567e1));
+ test("-123.4567", en_US, "{:L}", F(-1.234567e2));
+ test("-1,234.567", en_US, "{:L}", F(-1.234567e3));
+ test("-12,345.67", en_US, "{:L}", F(-1.234567e4));
+ test("-123,456.7", en_US, "{:L}", F(-1.234567e5));
+ test("-1,234,567", en_US, "{:L}", F(-1.234567e6));
+ test("-12,345,670", en_US, "{:L}", F(-1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-123,456,700", en_US, "{:L}", F(-1.234567e8));
+ test("-1,234,567,000", en_US, "{:L}", F(-1.234567e9));
+ test("-12,345,670,000", en_US, "{:L}", F(-1.234567e10));
+ test("-123,456,700,000", en_US, "{:L}", F(-1.234567e11));
+ test("-1.234567e+12", en_US, "{:L}", F(-1.234567e12));
+ test("-1.234567e+13", en_US, "{:L}", F(-1.234567e13));
+ }
+
+ std::locale::global(en_US);
+ test("1#234567e-06", loc, "{:L}", F(1.234567e-6));
+ test("1#234567e-05", loc, "{:L}", F(1.234567e-5));
+ test("0#0001234567", loc, "{:L}", F(1.234567e-4));
+ test("0#001234567", loc, "{:L}", F(1.234567e-3));
+ test("0#01234567", loc, "{:L}", F(1.234567e-2));
+ test("0#1234567", loc, "{:L}", F(1.234567e-1));
+ test("1#234567", loc, "{:L}", F(1.234567e0));
+ test("1_2#34567", loc, "{:L}", F(1.234567e1));
+ test("12_3#4567", loc, "{:L}", F(1.234567e2));
+ test("1_23_4#567", loc, "{:L}", F(1.234567e3));
+ test("12_34_5#67", loc, "{:L}", F(1.234567e4));
+ test("123_45_6#7", loc, "{:L}", F(1.234567e5));
+ test("1_234_56_7", loc, "{:L}", F(1.234567e6));
+ test("12_345_67_0", loc, "{:L}", F(1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("1_23_456_70_0", loc, "{:L}", F(1.234567e8));
+ test("1_2_34_567_00_0", loc, "{:L}", F(1.234567e9));
+ test("1_2_3_45_670_00_0", loc, "{:L}", F(1.234567e10));
+ test("1_2_3_4_56_700_00_0", loc, "{:L}", F(1.234567e11));
+ test("1#234567e+12", loc, "{:L}", F(1.234567e12));
+ test("1#234567e+13", loc, "{:L}", F(1.234567e13));
+ }
+ test("-1#234567e-06", loc, "{:L}", F(-1.234567e-6));
+ test("-1#234567e-05", loc, "{:L}", F(-1.234567e-5));
+ test("-0#0001234567", loc, "{:L}", F(-1.234567e-4));
+ test("-0#001234567", loc, "{:L}", F(-1.234567e-3));
+ test("-0#01234567", loc, "{:L}", F(-1.234567e-2));
+ test("-0#1234567", loc, "{:L}", F(-1.234567e-1));
+ test("-1#234567", loc, "{:L}", F(-1.234567e0));
+ test("-1_2#34567", loc, "{:L}", F(-1.234567e1));
+ test("-12_3#4567", loc, "{:L}", F(-1.234567e2));
+ test("-1_23_4#567", loc, "{:L}", F(-1.234567e3));
+ test("-12_34_5#67", loc, "{:L}", F(-1.234567e4));
+ test("-123_45_6#7", loc, "{:L}", F(-1.234567e5));
+ test("-1_234_56_7", loc, "{:L}", F(-1.234567e6));
+ test("-12_345_67_0", loc, "{:L}", F(-1.234567e7));
+ if constexpr (sizeof(F) > sizeof(float)) {
+ test("-1_23_456_70_0", loc, "{:L}", F(-1.234567e8));
+ test("-1_2_34_567_00_0", loc, "{:L}", F(-1.234567e9));
+ test("-1_2_3_45_670_00_0", loc, "{:L}", F(-1.234567e10));
+ test("-1_2_3_4_56_700_00_0", loc, "{:L}", F(-1.234567e11));
+ test("-1#234567e+12", loc, "{:L}", F(-1.234567e12));
+ test("-1#234567e+13", loc, "{:L}", F(-1.234567e13));
+ }
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1,234.567$$$", "{:$<12L}", F(1.234567e3));
+ test("$$$1,234.567", "{:$>12L}", F(1.234567e3));
+ test("$1,234.567$$", "{:$^12L}", F(1.234567e3));
+ test("0001,234.567", "{:012L}", F(1.234567e3));
+ test("-1,234.567$$$", "{:$<13L}", F(-1.234567e3));
+ test("$$$-1,234.567", "{:$>13L}", F(-1.234567e3));
+ test("$-1,234.567$$", "{:$^13L}", F(-1.234567e3));
+ test("-0001,234.567", "{:013L}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1_23_4#567$$$", "{:$<13L}", F(1.234567e3));
+ test("$$$1_23_4#567", "{:$>13L}", F(1.234567e3));
+ test("$1_23_4#567$$", "{:$^13L}", F(1.234567e3));
+ test("0001_23_4#567", "{:013L}", F(1.234567e3));
+ test("-1_23_4#567$$$", "{:$<14L}", F(-1.234567e3));
+ test("$$$-1_23_4#567", "{:$>14L}", F(-1.234567e3));
+ test("$-1_23_4#567$$", "{:$^14L}", F(-1.234567e3));
+ test("-0001_23_4#567", "{:014L}", F(-1.234567e3));
+
+ test("1,234.567$$$", en_US, "{:$<12L}", F(1.234567e3));
+ test("$$$1,234.567", en_US, "{:$>12L}", F(1.234567e3));
+ test("$1,234.567$$", en_US, "{:$^12L}", F(1.234567e3));
+ test("0001,234.567", en_US, "{:012L}", F(1.234567e3));
+ test("-1,234.567$$$", en_US, "{:$<13L}", F(-1.234567e3));
+ test("$$$-1,234.567", en_US, "{:$>13L}", F(-1.234567e3));
+ test("$-1,234.567$$", en_US, "{:$^13L}", F(-1.234567e3));
+ test("-0001,234.567", en_US, "{:013L}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1_23_4#567$$$", loc, "{:$<13L}", F(1.234567e3));
+ test("$$$1_23_4#567", loc, "{:$>13L}", F(1.234567e3));
+ test("$1_23_4#567$$", loc, "{:$^13L}", F(1.234567e3));
+ test("0001_23_4#567", loc, "{:013L}", F(1.234567e3));
+ test("-1_23_4#567$$$", loc, "{:$<14L}", F(-1.234567e3));
+ test("$$$-1_23_4#567", loc, "{:$>14L}", F(-1.234567e3));
+ test("$-1_23_4#567$$", loc, "{:$^14L}", F(-1.234567e3));
+ test("-0001_23_4#567", loc, "{:014L}", F(-1.234567e3));
+}
+
+template <class F>
+static void test_floating_point_default_precision() {
+ std::locale loc = std::locale(std::locale(), new numpunct<char>());
+ std::locale en_US = std::locale(LOCALE_en_US_UTF_8);
+
+ // *** Basic ***
+ std::locale::global(en_US);
+ test("1.23457e-06", "{:.6L}", F(1.234567e-6));
+ test("1.23457e-05", "{:.6L}", F(1.234567e-5));
+ test("0.000123457", "{:.6L}", F(1.234567e-4));
+ test("0.00123457", "{:.6L}", F(1.234567e-3));
+ test("0.0123457", "{:.6L}", F(1.234567e-2));
+ test("0.123457", "{:.6L}", F(1.234567e-1));
+ test("1.23457", "{:.6L}", F(1.234567e0));
+ test("12.3457", "{:.6L}", F(1.234567e1));
+ test("123.457", "{:.6L}", F(1.234567e2));
+ test("1,234.57", "{:.6L}", F(1.234567e3));
+ test("12,345.7", "{:.6L}", F(1.234567e4));
+ test("123,457", "{:.6L}", F(1.234567e5));
+ test("1.23457e+06", "{:.6L}", F(1.234567e6));
+ test("1.23457e+07", "{:.6L}", F(1.234567e7));
+ test("-1.23457e-06", "{:.6L}", F(-1.234567e-6));
+ test("-1.23457e-05", "{:.6L}", F(-1.234567e-5));
+ test("-0.000123457", "{:.6L}", F(-1.234567e-4));
+ test("-0.00123457", "{:.6L}", F(-1.234567e-3));
+ test("-0.0123457", "{:.6L}", F(-1.234567e-2));
+ test("-0.123457", "{:.6L}", F(-1.234567e-1));
+ test("-1.23457", "{:.6L}", F(-1.234567e0));
+ test("-12.3457", "{:.6L}", F(-1.234567e1));
+ test("-123.457", "{:.6L}", F(-1.234567e2));
+ test("-1,234.57", "{:.6L}", F(-1.234567e3));
+ test("-12,345.7", "{:.6L}", F(-1.234567e4));
+ test("-123,457", "{:.6L}", F(-1.234567e5));
+ test("-1.23457e+06", "{:.6L}", F(-1.234567e6));
+ test("-1.23457e+07", "{:.6L}", F(-1.234567e7));
+
+ std::locale::global(loc);
+ test("1#23457e-06", "{:.6L}", F(1.234567e-6));
+ test("1#23457e-05", "{:.6L}", F(1.234567e-5));
+ test("0#000123457", "{:.6L}", F(1.234567e-4));
+ test("0#00123457", "{:.6L}", F(1.234567e-3));
+ test("0#0123457", "{:.6L}", F(1.234567e-2));
+ test("0#123457", "{:.6L}", F(1.234567e-1));
+ test("1#23457", "{:.6L}", F(1.234567e0));
+ test("1_2#3457", "{:.6L}", F(1.234567e1));
+ test("12_3#457", "{:.6L}", F(1.234567e2));
+ test("1_23_4#57", "{:.6L}", F(1.234567e3));
+ test("12_34_5#7", "{:.6L}", F(1.234567e4));
+ test("123_45_7", "{:.6L}", F(1.234567e5));
+ test("1#23457e+06", "{:.6L}", F(1.234567e6));
+ test("1#23457e+07", "{:.6L}", F(1.234567e7));
+ test("-1#23457e-06", "{:.6L}", F(-1.234567e-6));
+ test("-1#23457e-05", "{:.6L}", F(-1.234567e-5));
+ test("-0#000123457", "{:.6L}", F(-1.234567e-4));
+ test("-0#00123457", "{:.6L}", F(-1.234567e-3));
+ test("-0#0123457", "{:.6L}", F(-1.234567e-2));
+ test("-0#123457", "{:.6L}", F(-1.234567e-1));
+ test("-1#23457", "{:.6L}", F(-1.234567e0));
+ test("-1_2#3457", "{:.6L}", F(-1.234567e1));
+ test("-12_3#457", "{:.6L}", F(-1.234567e2));
+ test("-1_23_4#57", "{:.6L}", F(-1.234567e3));
+ test("-12_34_5#7", "{:.6L}", F(-1.234567e4));
+ test("-123_45_7", "{:.6L}", F(-1.234567e5));
+ test("-1#23457e+06", "{:.6L}", F(-1.234567e6));
+ test("-1#23457e+07", "{:.6L}", F(-1.234567e7));
+
+ test("1.23457e-06", en_US, "{:.6L}", F(1.234567e-6));
+ test("1.23457e-05", en_US, "{:.6L}", F(1.234567e-5));
+ test("0.000123457", en_US, "{:.6L}", F(1.234567e-4));
+ test("0.00123457", en_US, "{:.6L}", F(1.234567e-3));
+ test("0.0123457", en_US, "{:.6L}", F(1.234567e-2));
+ test("0.123457", en_US, "{:.6L}", F(1.234567e-1));
+ test("1.23457", en_US, "{:.6L}", F(1.234567e0));
+ test("12.3457", en_US, "{:.6L}", F(1.234567e1));
+ test("123.457", en_US, "{:.6L}", F(1.234567e2));
+ test("1,234.57", en_US, "{:.6L}", F(1.234567e3));
+ test("12,345.7", en_US, "{:.6L}", F(1.234567e4));
+ test("123,457", en_US, "{:.6L}", F(1.234567e5));
+ test("1.23457e+06", en_US, "{:.6L}", F(1.234567e6));
+ test("1.23457e+07", en_US, "{:.6L}", F(1.234567e7));
+ test("-1.23457e-06", en_US, "{:.6L}", F(-1.234567e-6));
+ test("-1.23457e-05", en_US, "{:.6L}", F(-1.234567e-5));
+ test("-0.000123457", en_US, "{:.6L}", F(-1.234567e-4));
+ test("-0.00123457", en_US, "{:.6L}", F(-1.234567e-3));
+ test("-0.0123457", en_US, "{:.6L}", F(-1.234567e-2));
+ test("-0.123457", en_US, "{:.6L}", F(-1.234567e-1));
+ test("-1.23457", en_US, "{:.6L}", F(-1.234567e0));
+ test("-12.3457", en_US, "{:.6L}", F(-1.234567e1));
+ test("-123.457", en_US, "{:.6L}", F(-1.234567e2));
+ test("-1,234.57", en_US, "{:.6L}", F(-1.234567e3));
+ test("-12,345.7", en_US, "{:.6L}", F(-1.234567e4));
+ test("-123,457", en_US, "{:.6L}", F(-1.234567e5));
+ test("-1.23457e+06", en_US, "{:.6L}", F(-1.234567e6));
+ test("-1.23457e+07", en_US, "{:.6L}", F(-1.234567e7));
+
+ std::locale::global(en_US);
+ test("1#23457e-06", loc, "{:.6L}", F(1.234567e-6));
+ test("1#23457e-05", loc, "{:.6L}", F(1.234567e-5));
+ test("0#000123457", loc, "{:.6L}", F(1.234567e-4));
+ test("0#00123457", loc, "{:.6L}", F(1.234567e-3));
+ test("0#0123457", loc, "{:.6L}", F(1.234567e-2));
+ test("0#123457", loc, "{:.6L}", F(1.234567e-1));
+ test("1#23457", loc, "{:.6L}", F(1.234567e0));
+ test("1_2#3457", loc, "{:.6L}", F(1.234567e1));
+ test("12_3#457", loc, "{:.6L}", F(1.234567e2));
+ test("1_23_4#57", loc, "{:.6L}", F(1.234567e3));
+ test("12_34_5#7", loc, "{:.6L}", F(1.234567e4));
+ test("123_45_7", loc, "{:.6L}", F(1.234567e5));
+ test("1#23457e+06", loc, "{:.6L}", F(1.234567e6));
+ test("1#23457e+07", loc, "{:.6L}", F(1.234567e7));
+ test("-1#23457e-06", loc, "{:.6L}", F(-1.234567e-6));
+ test("-1#23457e-05", loc, "{:.6L}", F(-1.234567e-5));
+ test("-0#000123457", loc, "{:.6L}", F(-1.234567e-4));
+ test("-0#00123457", loc, "{:.6L}", F(-1.234567e-3));
+ test("-0#0123457", loc, "{:.6L}", F(-1.234567e-2));
+ test("-0#123457", loc, "{:.6L}", F(-1.234567e-1));
+ test("-1#23457", loc, "{:.6L}", F(-1.234567e0));
+ test("-1_2#3457", loc, "{:.6L}", F(-1.234567e1));
+ test("-12_3#457", loc, "{:.6L}", F(-1.234567e2));
+ test("-1_23_4#57", loc, "{:.6L}", F(-1.234567e3));
+ test("-12_34_5#7", loc, "{:.6L}", F(-1.234567e4));
+ test("-123_45_7", loc, "{:.6L}", F(-1.234567e5));
+ test("-1#23457e+06", loc, "{:.6L}", F(-1.234567e6));
+ test("-1#23457e+07", loc, "{:.6L}", F(-1.234567e7));
+
+ // *** Fill, align, zero padding ***
+ std::locale::global(en_US);
+ test("1,234.57$$$", "{:$<11.6L}", F(1.234567e3));
+ test("$$$1,234.57", "{:$>11.6L}", F(1.234567e3));
+ test("$1,234.57$$", "{:$^11.6L}", F(1.234567e3));
+ test("0001,234.57", "{:011.6L}", F(1.234567e3));
+ test("-1,234.57$$$", "{:$<12.6L}", F(-1.234567e3));
+ test("$$$-1,234.57", "{:$>12.6L}", F(-1.234567e3));
+ test("$-1,234.57$$", "{:$^12.6L}", F(-1.234567e3));
+ test("-0001,234.57", "{:012.6L}", F(-1.234567e3));
+
+ std::locale::global(loc);
+ test("1_23_4#57$$$", "{:$<12.6L}", F(1.234567e3));
+ test("$$$1_23_4#57", "{:$>12.6L}", F(1.234567e3));
+ test("$1_23_4#57$$", "{:$^12.6L}", F(1.234567e3));
+ test("0001_23_4#57", "{:012.6L}", F(1.234567e3));
+ test("-1_23_4#57$$$", "{:$<13.6L}", F(-1.234567e3));
+ test("$$$-1_23_4#57", "{:$>13.6L}", F(-1.234567e3));
+ test("$-1_23_4#57$$", "{:$^13.6L}", F(-1.234567e3));
+ test("-0001_23_4#57", "{:013.6L}", F(-1.234567e3));
+
+ test("1,234.57$$$", en_US, "{:$<11.6L}", F(1.234567e3));
+ test("$$$1,234.57", en_US, "{:$>11.6L}", F(1.234567e3));
+ test("$1,234.57$$", en_US, "{:$^11.6L}", F(1.234567e3));
+ test("0001,234.57", en_US, "{:011.6L}", F(1.234567e3));
+ test("-1,234.57$$$", en_US, "{:$<12.6L}", F(-1.234567e3));
+ test("$$$-1,234.57", en_US, "{:$>12.6L}", F(-1.234567e3));
+ test("$-1,234.57$$", en_US, "{:$^12.6L}", F(-1.234567e3));
+ test("-0001,234.57", en_US, "{:012.6L}", F(-1.234567e3));
+
+ std::locale::global(en_US);
+ test("1_23_4#57$$$", loc, "{:$<12.6L}", F(1.234567e3));
+ test("$$$1_23_4#57", loc, "{:$>12.6L}", F(1.234567e3));
+ test("$1_23_4#57$$", loc, "{:$^12.6L}", F(1.234567e3));
+ test("0001_23_4#57", loc, "{:012.6L}", F(1.234567e3));
+ test("-1_23_4#57$$$", loc, "{:$<13.6L}", F(-1.234567e3));
+ test("$$$-1_23_4#57", loc, "{:$>13.6L}", F(-1.234567e3));
+ test("$-1_23_4#57$$", loc, "{:$^13.6L}", F(-1.234567e3));
+ test("-0001_23_4#57", loc, "{:013.6L}", F(-1.234567e3));
+}
+
+template <class F>
+static void test_floating_point() {
+ test_floating_point_hex_lower_case<F>();
+ test_floating_point_hex_upper_case<F>();
+ test_floating_point_hex_lower_case_precision<F>();
+ test_floating_point_hex_upper_case_precision<F>();
+
+ test_floating_point_scientific_lower_case<F>();
+ test_floating_point_scientific_upper_case<F>();
+
+ test_floating_point_fixed_lower_case<F>();
+ test_floating_point_fixed_upper_case<F>();
+
+ test_floating_point_general_lower_case<F>();
+ test_floating_point_general_upper_case<F>();
+
+ test_floating_point_default<F>();
+ test_floating_point_default_precision<F>();
+}
+
+int main(int, char**) {
+ test_bool();
+ test_integer();
+ test_floating_point<float>();
+ test_floating_point<double>();
+ test_floating_point<long double>();
+
+ return 0;
+}
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print.pass.cpp
new file mode 100644
index 00000000000000..0831ef71076629
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h
new file mode 100644
index 00000000000000..d28256cabc7986
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h
@@ -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_PRINT_FUN_PRINT_TESTS_H
+#define TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_PRINT_FUN_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_PRINT_FUN_PRINT_TESTS_H
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp
new file mode 100644
index 00000000000000..deb262d2fb627e
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/println.pass.cpp
@@ -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;
+}
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp
new file mode 100644
index 00000000000000..671df8c065b401
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp
@@ -0,0 +1,198 @@
+//===----------------------------------------------------------------------===//
+// 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>(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::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;
+}
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
new file mode 100644
index 00000000000000..fb6d6894884099
--- /dev/null
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -0,0 +1,197 @@
+//===----------------------------------------------------------------------===//
+// 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>(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);
+
+ [[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;
+}
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp
index 720322081e1ef2..2a42ca080612de 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ostream.version.compile.pass.cpp
@@ -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
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp
index 5284848ead8418..f4ccea4e86304c 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/print.version.compile.pass.cpp
@@ -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
diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
index c0d3d554dcf056..650a14b019ed87 100644
--- a/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
+++ b/libcxx/test/std/language.support/support.limits/support.limits.general/version.version.compile.pass.cpp
@@ -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
diff --git a/libcxx/utils/generate_feature_test_macro_components.py b/libcxx/utils/generate_feature_test_macro_components.py
index 6a30324397883a..ec7d8ff9f707e6 100755
--- a/libcxx/utils/generate_feature_test_macro_components.py
+++ b/libcxx/utils/generate_feature_test_macro_components.py
@@ -873,7 +873,6 @@ def add_version_header(tc):
"name": "__cpp_lib_print",
"values": {"c++23": 202207},
"headers": ["ostream", "print"],
- "unimplemented": True,
},
{
"name": "__cpp_lib_quoted_string_io",
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 5e854917e6ef45..d3c5dedf4ea286 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -570,6 +570,7 @@ def check_gdb(cfg):
cfg.available_features,
),
),
+
# Tests that require time zone database support in the built library
Feature(
name="availability-tzdb-missing",
@@ -579,4 +580,14 @@ def check_gdb(cfg):
cfg.available_features,
),
),
+
+ # Tests that require __libcpp_print support 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,
+ ),
+ ),
]
>From f2aa35db131bb658b8beb9b3507aae891c55e68b Mon Sep 17 00:00:00 2001
From: Mark de Wever <koraq at xs4all.nl>
Date: Sat, 16 Dec 2023 13:37:41 +0100
Subject: [PATCH 2/2] Addresses review comments.
---
libcxx/include/fstream | 4 +--
libcxx/include/ostream | 15 +++++++++--
libcxx/include/print | 10 +++----
libcxx/src/ostream.cpp | 14 +++++-----
libcxx/src/std_stream.h | 4 +--
.../vprint_unicode.pass.cpp | 26 +++++++++----------
.../ostream.formatted.print/print_tests.h | 6 ++---
.../vprint_nonunicode.pass.cpp | 21 +++++++++++----
.../vprint_unicode.pass.cpp | 21 +++++++++++----
libcxx/utils/libcxx/test/features.py | 2 +-
10 files changed, 78 insertions(+), 45 deletions(-)
diff --git a/libcxx/include/fstream b/libcxx/include/fstream
index 812225d549eab6..c5a589698e2265 100644
--- a/libcxx/include/fstream
+++ b/libcxx/include/fstream
@@ -256,8 +256,6 @@ public:
inline static const char*
__make_mdstring(ios_base::openmode __mode) _NOEXCEPT;
- _LIBCPP_NODISCARD _LIBCPP_HIDE_FROM_ABI FILE* __file() { return __file_; }
-
protected:
// 27.9.1.5 Overridden virtual functions:
int_type underflow() override;
@@ -291,6 +289,8 @@ private:
bool __read_mode();
void __write_mode();
+
+ _LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
};
template <class _CharT, class _Traits>
diff --git a/libcxx/include/ostream b/libcxx/include/ostream
index 5c5c30de006857..4f51d088a05bb7 100644
--- a/libcxx/include/ostream
+++ b/libcxx/include/ostream
@@ -1214,9 +1214,20 @@ extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostream<wchar_t>;
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 = vformat(__os.getloc(), __fmt, __args);
+ string __o = std::vformat(__os.getloc(), __fmt, __args);
if (__write_nl)
__o += '\n';
@@ -1289,7 +1300,7 @@ __vprint_unicode(ostream& __os, string_view __fmt, format_args __args, bool __wr
# endif // _LIBCPP_HAS_NO_EXCEPTIONS
ostream::sentry __s(__os);
if (__s) {
-# ifndef _WIN32
+# 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);
diff --git a/libcxx/include/print b/libcxx/include/print
index 2174557794e4df..e076b6e4864f8c 100644
--- a/libcxx/include/print
+++ b/libcxx/include/print
@@ -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
@@ -202,7 +202,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_terminal(FILE* __stream) {
// 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(_WIN32)
+# elif defined(__LIBCPP_WIN32API)
return std::__is_windows_terminal(__stream);
# elif __has_include(<unistd.h>)
return isatty(fileno(__stream));
@@ -275,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 "
@@ -313,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));
diff --git a/libcxx/src/ostream.cpp b/libcxx/src/ostream.cpp
index b91cb57d607caa..bba8e6550710f8 100644
--- a/libcxx/src/ostream.cpp
+++ b/libcxx/src/ostream.cpp
@@ -19,21 +19,21 @@ _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 why build with RTTI
- // disabled with a dylib with RTTI enabled.
+ // the dylib with RTTI disabled. It does not affect users who build with RTTI
+ // disabled but use a dylib where the RTTI is enabled.
//
- // Not returning a FILE* 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.
+ // 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();
+ return __buffer->__file_;
# endif
if (auto* __buffer = dynamic_cast<__stdoutbuf<char>*>(__rdbuf))
- return __buffer->__file();
+ return __buffer->__file_;
#endif // _LIBCPP_HAS_NO_RTTI
return nullptr;
diff --git a/libcxx/src/std_stream.h b/libcxx/src/std_stream.h
index 21388e19a9656a..0f6ff4460a53e2 100644
--- a/libcxx/src/std_stream.h
+++ b/libcxx/src/std_stream.h
@@ -286,8 +286,6 @@ class _LIBCPP_HIDDEN __stdoutbuf
__stdoutbuf(FILE* __fp, state_type* __st);
- [[nodiscard]] FILE* __file() { return __file_; }
-
protected:
virtual int_type overflow (int_type __c = traits_type::eof());
virtual streamsize xsputn(const char_type* __s, streamsize __n);
@@ -308,6 +306,8 @@ class _LIBCPP_HIDDEN __stdoutbuf
__stdoutbuf(const __stdoutbuf&);
__stdoutbuf& operator=(const __stdoutbuf&);
+
+ _LIBCPP_EXPORTED_FROM_ABI friend FILE* __get_ostream_file(ostream&);
};
template <class _CharT>
diff --git a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index 6243b250dec393..7b590f1e80c4b5 100644
--- a/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -20,10 +20,9 @@
// void __vprint_unicode(ostream& os, string_view fmt,
// format_args args, bool write_nl);
-// In the library when the 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.
+// 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>
@@ -39,23 +38,21 @@ bool is_terminal(FILE*);
#include "test_macros.h"
-#include <print> // TODO REMOVE
-
scoped_test_env env;
std::string filename = env.create_file("output.txt");
int is_terminal_calls = 0;
-bool should_call_is_terminal = false;
bool is_terminal_result = false;
bool is_terminal(FILE*) {
++is_terminal_calls;
- assert(should_call_is_terminal);
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;
- should_call_is_terminal = false;
is_terminal_result = false;
{
std::stringstream stream;
@@ -68,9 +65,10 @@ static void test_is_terminal_not_a_file_stream() {
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;
- should_call_is_terminal = true;
is_terminal_result = false;
{
std::fstream stream(filename);
@@ -88,11 +86,11 @@ static void test_is_terminal_file_stream() {
}
}
+// 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;
- should_call_is_terminal = true;
is_terminal_result = false;
my_filebuf buf;
@@ -104,9 +102,10 @@ static void test_is_terminal_rdbuf_derived_from_filebuf() {
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;
- should_call_is_terminal = true;
is_terminal_result = false;
{
std::print(std::cout, "test");
@@ -122,6 +121,8 @@ static void test_is_terminal_std_cout_cerr_clog() {
}
}
+// 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() {
@@ -137,7 +138,6 @@ static void test_is_terminal_is_flushed() {
}
};
- should_call_is_terminal = true;
is_terminal_result = false;
sync_counter buf;
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h
index d28256cabc7986..f5a6a639cbd307 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/print_tests.h
@@ -5,8 +5,8 @@
//
//===----------------------------------------------------------------------===//
-#ifndef TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_PRINT_FUN_PRINT_TESTS_H
-#define TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_PRINT_FUN_PRINT_TESTS_H
+#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) {
@@ -80,4 +80,4 @@ void print_tests(TestFunction check, ExceptionTest check_exception) {
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_PRINT_FUN_PRINT_TESTS_H
+#endif // TEST_STD_INPUT_OUTPUT_IOSTREAM_FORMAT_OUTPUT_STREAMS_OSTREAM_FORMATTED_OSTREAM_FORMATTED_PRINT_PRINT_TESTS_H
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp
index 671df8c065b401..350e20387b01c3 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp
@@ -46,12 +46,23 @@ auto test_file = []<class... Args>(std::string_view expected, test_format_string
"\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.
+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
diff --git a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
index fb6d6894884099..9b14c429bdb45f 100644
--- a/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
+++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp
@@ -45,12 +45,23 @@ auto test_file = []<class... Args>(std::string_view expected, test_format_string
"\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.
+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
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index d3c5dedf4ea286..7ec06389f7d9f6 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -581,7 +581,7 @@ def check_gdb(cfg):
),
),
- # Tests that require __libcpp_print support in the built library
+ # 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(
More information about the libcxx-commits
mailing list