diff --git a/libcxx/docs/FeatureTestMacroTable.rst b/libcxx/docs/FeatureTestMacroTable.rst --- a/libcxx/docs/FeatureTestMacroTable.rst +++ b/libcxx/docs/FeatureTestMacroTable.rst @@ -344,7 +344,7 @@ --------------------------------------------------- ----------------- ``__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 --- a/libcxx/docs/ImplementationDefinedBehavior.rst +++ b/libcxx/docs/ImplementationDefinedBehavior.rst @@ -28,6 +28,21 @@ 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 `_ A terminal capable of displaying Unicode +-------------------------------------------------------------------------------------------------------------------------- + +* 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`` derived from ``std::filebuf``. + +* The way to determine whether this ``FILE*`` is the same as specified + for `void vprint_unicode(FILE* stream, string_view fmt, format_args args); + `_. + Listed in the index of implementation-defined behavior ====================================================== diff --git a/libcxx/docs/ReleaseNotes/18.rst b/libcxx/docs/ReleaseNotes/18.rst --- a/libcxx/docs/ReleaseNotes/18.rst +++ b/libcxx/docs/ReleaseNotes/18.rst @@ -41,6 +41,8 @@ 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 ```` functions - P2697R1 - Interfacing ``bitset`` with ``string_view`` diff --git a/libcxx/docs/Status/Cxx23Papers.csv b/libcxx/docs/Status/Cxx23Papers.csv --- a/libcxx/docs/Status/Cxx23Papers.csv +++ b/libcxx/docs/Status/Cxx23Papers.csv @@ -59,7 +59,7 @@ "`P1467R9 `__","LWG","Extended ``floating-point`` types and standard names","July 2022","","" "`P1642R11 `__","LWG","Freestanding ``[utilities]``, ``[ranges]``, and ``[iterators]``","July 2022","","" "`P1899R3 `__","LWG","``stride_view``","July 2022","","","|ranges|" -"`P2093R14 `__","LWG","Formatted output","July 2022","","|In Progress|" +"`P2093R14 `__","LWG","Formatted output","July 2022","","|Complete|","18.0" "`P2165R4 `__","LWG","Compatibility between ``tuple``, ``pair`` and ``tuple-like`` objects","July 2022","","" "`P2278R4 `__","LWG","``cbegin`` should always return a constant iterator","July 2022","","","|ranges|" "`P2286R8 `__","LWG","Formatting Ranges","July 2022","|Complete|","16.0","|format| |ranges|" @@ -99,7 +99,7 @@ "`P2167R3 `__","LWG", "Improved Proposed Wording for LWG 2114", "November 2022","","","" "`P2396R1 `__","LWG", "Concurrency TS 2 fixes ", "November 2022","","","|concurrency TS|" "`P2505R5 `__","LWG", "Monadic Functions for ``std::expected``", "November 2022","|Complete|","17.0","" -"`P2539R4 `__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|In Progress|","","|format|" +"`P2539R4 `__","LWG", "Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?", "November 2022","|Complete|","18.0","|format|" "`P2602R2 `__","LWG", "Poison Pills are Too Toxic", "November 2022","","","|ranges|" "`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 --- a/libcxx/docs/Status/FormatIssues.csv +++ b/libcxx/docs/Status/FormatIssues.csv @@ -5,11 +5,11 @@ `P1868 `_,"width: clarifying units of width and precision in std::format (Implements the unicode support.)","C++20",Mark de Wever,|Complete|,14.0 `P2216 `_,"std::format improvements","C++20",Mark de Wever,|Complete|,15.0 `P2418 `__,"Add support for ``std::generator``-like types to ``std::format``","C++20",Mark de Wever,|Complete|,15.0 -"`P2093R14 `__","Formatted output","C++23",Mark de Wever,|In Progress| +"`P2093R14 `__","Formatted output","C++23",Mark de Wever,|Complete|,"18.0" "`P2286R8 `__","Formatting Ranges","C++23","Mark de Wever","|Complete|",16.0 "`P2508R1 `__","Exposing ``std::basic-format-string``","C++23","Mark de Wever","|Complete|",15.0 "`P2585R0 `__","Improving default container formatting","C++23","Mark de Wever","|Complete|",17.0 -"`P2539R4 `__","Should the output of ``std::print`` to a terminal be synchronized with the underlying stream?","C++23","Mark de Wever","|In Progress|" +"`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 `__","Escaping improvements in ``std::format``","C++23","Mark de Wever","" "`P2675R1 `__","``format``'s width estimation is too approximate and not forward compatible","C++23","Mark de Wever","|Complete|",17.0 "`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 --- a/libcxx/docs/Status/FormatPaper.csv +++ b/libcxx/docs/Status/FormatPaper.csv @@ -49,4 +49,4 @@ "`P2093R14 `__","Formatted output" `[print.fun] `__,"Output to ``stdout``",,Mark de Wever,|Complete|, 17.0 `[print.fun] `__,"Output to ``FILE*``",,Mark de Wever,|Complete|, 17.0 -`[ostream.formatted.print] `__,"Output to ``ostream``",,Mark de Wever +`[ostream.formatted.print] `__,"Output to ``ostream``",,Mark de Wever,|Complete|, 18.0 diff --git a/libcxx/include/__availability b/libcxx/include/__availability --- a/libcxx/include/__availability +++ b/libcxx/include/__availability @@ -139,6 +139,12 @@ // # define _LIBCPP_AVAILABILITY_HAS_NO_TZDB # define _LIBCPP_AVAILABILITY_TZDB + // This controls the availability of C++23 , 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_NO_PRINT +# 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. @@ -241,6 +247,9 @@ # define _LIBCPP_AVAILABILITY_HAS_NO_TZDB # define _LIBCPP_AVAILABILITY_TZDB __attribute__((unavailable)) +# define _LIBCPP_AVAILABILITY_HAS_NO_PRINT +# define _LIBCPP_AVAILABILITY_PRINT __attribute__((unavailable)) + # 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) || \ (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ < 150000) || \ diff --git a/libcxx/include/fstream b/libcxx/include/fstream --- a/libcxx/include/fstream +++ b/libcxx/include/fstream @@ -256,6 +256,8 @@ 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 --- a/libcxx/include/ostream +++ b/libcxx/include/ostream @@ -159,13 +159,24 @@ template basic_ostream& operator<<(basic_ostream&, const char32_t*) = delete; // since C++20 +// [ostream.formatted.print], print functions +template // since C++23 + void print(ostream& os, format_string fmt, Args&&... args); +template // since C++23 + void println(ostream& os, format_string 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 @@ #include <__type_traits/void_t.h> #include <__utility/declval.h> #include +#include #include #include #include +#include #include +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -1195,6 +1209,140 @@ extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS basic_ostream; #endif +#if _LIBCPP_STD_VER >= 23 + +template // 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 _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 // 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 // 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 // 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 +_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 +_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 --- a/libcxx/include/print +++ b/libcxx/include/print @@ -198,7 +198,11 @@ # 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() return isatty(fileno(__stream)); diff --git a/libcxx/include/version b/libcxx/include/version --- a/libcxx/include/version +++ b/libcxx/include/version @@ -455,7 +455,7 @@ # 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- 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 --- a/libcxx/modules/std/ostream.inc +++ b/libcxx/modules/std/ostream.inc @@ -27,13 +27,14 @@ # 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 --- a/libcxx/src/CMakeLists.txt +++ b/libcxx/src/CMakeLists.txt @@ -89,6 +89,7 @@ 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 --- /dev/null +++ b/libcxx/src/ostream.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#endif +#include + +#include "std_stream.h" + +_LIBCPP_BEGIN_NAMESPACE_STD + +_LIBCPP_AVAILABILITY_PRINT _LIBCPP_EXPORTED_FROM_ABI FILE* __get_ostream_file(ostream& __os) { + auto* __rdbuf = __os.rdbuf(); +#ifndef _LIBCPP_HAS_NO_FILESYSTEM + if (auto* __buffer = dynamic_cast(__rdbuf)) + return __buffer->__file(); +#endif + + if (auto* __buffer = dynamic_cast<__stdoutbuf*>(__rdbuf)) + return __buffer->__file(); + + return nullptr; +} + +_LIBCPP_END_NAMESPACE_STD diff --git a/libcxx/src/std_stream.h b/libcxx/src/std_stream.h --- a/libcxx/src/std_stream.h +++ b/libcxx/src/std_stream.h @@ -286,7 +286,9 @@ __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 --- /dev/null +++ b/libcxx/test/libcxx/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp @@ -0,0 +1,192 @@ +//===----------------------------------------------------------------------===// +// 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 +// + +// 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 +bool is_terminal(FILE*); +#define _LIBCPP_TESTING_PRINT_IS_TERMINAL ::is_terminal + +#include "filesystem_test_helper.h" +#include +#include +#include +#include +#include + +#include "test_macros.h" + +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::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 +} + +#ifdef _WIN32 +static void test_transcoding() { + // TODO PRINT Investigate on Windows why it fails. +# if 0 + is_terminal_calls = 0; + should_call_is_terminal = true; + is_terminal_result = true; + + { + std::ofstream stream(filename); + // 2 code units UTF-8 0xCC 0x81, should be transcoded to 1 code unit UTF-16 0x0301 + std::print(stream, "\u0301"); + assert(is_terminal_calls == 1); + } + + + FILE* file = std::fopen(filename.c_str(), "r"); + assert(std::fgetc(file) == 0x03); + assert(std::fgetc(file) == 0x01); + assert(std::fgetc(file) == EOF); + std::fclose(file); +# endif +} +#endif + +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(); + +#ifdef _WIN32 + test_transcoding(); +#endif + + return 0; +} diff --git a/libcxx/test/libcxx/transitive_includes/cxx03.csv b/libcxx/test/libcxx/transitive_includes/cxx03.csv --- a/libcxx/test/libcxx/transitive_includes/cxx03.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx03.csv @@ -619,26 +619,29 @@ 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 --- a/libcxx/test/libcxx/transitive_includes/cxx11.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx11.csv @@ -624,26 +624,29 @@ 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 --- a/libcxx/test/libcxx/transitive_includes/cxx14.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx14.csv @@ -626,26 +626,29 @@ 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 --- a/libcxx/test/libcxx/transitive_includes/cxx17.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx17.csv @@ -626,26 +626,29 @@ 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 --- a/libcxx/test/libcxx/transitive_includes/cxx20.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx20.csv @@ -631,26 +631,28 @@ 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 --- a/libcxx/test/libcxx/transitive_includes/cxx23.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv @@ -425,19 +425,23 @@ 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 --- a/libcxx/test/libcxx/transitive_includes/cxx26.csv +++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv @@ -425,19 +425,23 @@ 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 --- /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,2197 @@ +//===----------------------------------------------------------------------===// +// 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 + +// REQUIRES: locale.en_US.UTF-8 + +// + +// This test checks the locale-specific form for these print functions: +// template +// void print(ostream& os, format_string fmt, Args&&... args); +// template +// void println(ostream& os, format_string 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 +#include + +#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 +struct numpunct; + +template <> +struct numpunct : std::numpunct { + 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 +static void +test(std::stringstream& stream, std::string expected, test_format_string fmt, Args&&... args) { + // *** print *** + { + std::print(stream, fmt, std::forward(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)...); + std::string out = stream.str(); + TEST_REQUIRE(out == expected, + TEST_WRITE_CONCATENATED( + "\nFormat string ", fmt.get(), "\nExpected output ", expected, "\nActual output ", out, '\n')); + } +} + +template +static void test(std::string expected, test_format_string fmt, Args&&... args) { + std::stringstream stream; + test(stream, std::move(expected), fmt, std::forward(args)...); +} + +template +static void test(std::string expected, std::locale loc, test_format_string fmt, Args&&... args) { + std::stringstream stream; + stream.imbue(loc); + test(stream, std::move(expected), fmt, std::forward(args)...); +} + +#ifndef TEST_HAS_NO_UNICODE +struct numpunct_unicode : std::numpunct { + 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()); + + 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()); + 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 +static void test_floating_point_hex_lower_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_hex_upper_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_hex_lower_case_precision() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_hex_upper_case_precision() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_scientific_lower_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_scientific_upper_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_fixed_lower_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_fixed_upper_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_general_lower_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_general_upper_case() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_default() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point_default_precision() { + std::locale loc = std::locale(std::locale(), new numpunct()); + 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 +static void test_floating_point() { + test_floating_point_hex_lower_case(); + test_floating_point_hex_upper_case(); + test_floating_point_hex_lower_case_precision(); + test_floating_point_hex_upper_case_precision(); + + test_floating_point_scientific_lower_case(); + test_floating_point_scientific_upper_case(); + + test_floating_point_fixed_lower_case(); + test_floating_point_fixed_upper_case(); + + test_floating_point_general_lower_case(); + test_floating_point_general_upper_case(); + + test_floating_point_default(); + test_floating_point_default_precision(); +} + +int main(int, char**) { + test_bool(); + test_integer(); + test_floating_point(); + test_floating_point(); + test_floating_point(); + + 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 --- /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 + +// + +// template +// void print(ostream& os, format_string 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 +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "print_tests.h" +#include "test_format_string.h" +#include "test_macros.h" + +auto test_file = [](std::string_view expected, test_format_string fmt, Args&&... args) { + std::stringstream sstr; + std::print(sstr, fmt, std::forward(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 = [](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 { + 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 { + protected: + int virtual overflow(int) { return std::char_traits::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 = [&](std::string_view expected, test_format_string fmt, Args&&... args) { + sstr.str(""); + std::print(sstr, fmt, std::forward(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 --- /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 +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 --- /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 + +// + +// template +// void println(ostream& os, format_string 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 +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "print_tests.h" +#include "test_format_string.h" +#include "test_macros.h" + +auto test_file = [](std::string_view e, test_format_string fmt, Args&&... args) { + std::string expected = std::string{e} + '\n'; + + std::stringstream sstr; + std::println(sstr, fmt, std::forward(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 = [](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 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_nonunicode.pass.cpp @@ -0,0 +1,195 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// 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 +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "print_tests.h" +#include "test_format_string.h" +#include "test_macros.h" + +auto test_file = [](std::string_view expected, test_format_string 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 = [](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 { + 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(); + TEST_THROWS_TYPE(std::ios_base::failure, + std::vprint_nonunicode(os, "throws exception at run-time {0:{0}}", std::make_format_args(-10))); + + 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(-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::vprint_nonunicode(sstr, "no output {0:{0}}", std::make_format_args(-10))); + 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(-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::vprint_nonunicode(sstr, "no output {0:{0}}", std::make_format_args(-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 { + protected: + int virtual overflow(int) { return std::char_traits::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_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(-10))); + + 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 = [&](std::string_view expected, test_format_string 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 --- /dev/null +++ b/libcxx/test/std/input.output/iostream.format/output.streams/ostream.formatted/ostream.formatted.print/vprint_unicode.pass.cpp @@ -0,0 +1,194 @@ +//===----------------------------------------------------------------------===// +// 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 + +// + +// 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 +#include +#include + +#include "assert_macros.h" +#include "concat_macros.h" +#include "print_tests.h" +#include "test_format_string.h" +#include "test_macros.h" + +auto test_file = [](std::string_view expected, test_format_string 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 = [](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 { + 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_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(-10))); + + 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(-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::vprint_unicode(sstr, "no output {0:{0}}", std::make_format_args(-10))); + 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(-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::vprint_unicode(sstr, "no output {0:{0}}", std::make_format_args(-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 { + protected: + int virtual overflow(int) { return std::char_traits::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. + TEST_THROWS_TYPE( + std::format_error, std::vprint_unicode(os, "throws exception at run-time {0:{0}}", std::make_format_args(-10))); + + 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 = [&](std::string_view expected, test_format_string 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 --- 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 --- 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 --- 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 @@ -5261,17 +5261,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 @@ -6980,17 +6974,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 --- a/libcxx/utils/generate_feature_test_macro_components.py +++ b/libcxx/utils/generate_feature_test_macro_components.py @@ -874,7 +874,6 @@ "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 --- a/libcxx/utils/libcxx/test/features.py +++ b/libcxx/utils/libcxx/test/features.py @@ -534,6 +534,7 @@ cfg.available_features, ), ), + # Tests that require time zone database support in the built library Feature( name="availability-tzdb-missing", @@ -543,6 +544,16 @@ 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, + ), + ), # Tests that require 64-bit architecture Feature( name="32-bit-pointer",