diff --git a/libcxx/benchmarks/formatter_float.bench.cpp b/libcxx/benchmarks/formatter_float.bench.cpp new file mode 100644 --- /dev/null +++ b/libcxx/benchmarks/formatter_float.bench.cpp @@ -0,0 +1,241 @@ +//===----------------------------------------------------------------------===// +// 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 + +#include +#include +#include +#include + +#include "CartesianBenchmarks.h" +#include "benchmark/benchmark.h" + +// *** Localization *** +enum class LocalizationE { False, True }; +struct AllLocalizations : EnumValuesAsTuple { + static constexpr const char* Names[] = {"LocFalse", "LocTrue"}; +}; + +template +struct Localization {}; + +template <> +struct Localization { + static constexpr const char* fmt = ""; +}; + +template <> +struct Localization { + static constexpr const char* fmt = "L"; +}; + +// *** Types *** +enum class TypeE { Float, Double, LongDouble }; +// TODO FMT Set to 3 after to_chars has long double suport. +struct AllTypes : EnumValuesAsTuple { + static constexpr const char* Names[] = {"Float", "Double", "LongDouble"}; +}; + +template +struct Type {}; + +template <> +struct Type { + using type = float; +}; + +template <> +struct Type { + using type = double; +}; + +template <> +struct Type { + using type = long double; +}; + +// *** Values *** +enum class ValueE { Inf, Random }; +struct AllValues : EnumValuesAsTuple { + static constexpr const char* Names[] = {"Inf", "Random"}; +}; + +template +struct Value {}; + +template <> +struct Value { + template + static std::array make_data() { + std::array result; + std::fill(result.begin(), result.end(), -std::numeric_limits::infinity()); + return result; + } +}; + +template <> +struct Value { + template + static std::array make_data() { + std::random_device seed; + std::mt19937 generator(seed()); + std::uniform_int_distribution> distribution; + + std::array result; + std::generate(result.begin(), result.end(), [&] { + while (true) { + auto result = std::bit_cast(distribution(generator)); + if (std::isfinite(result)) + return result; + } + }); + return result; + } +}; + +// *** Display Type *** +enum class DisplayTypeE { + Default, + Hex, + Scientific, + Fixed, + General, +}; +struct AllDisplayTypes : EnumValuesAsTuple { + static constexpr const char* Names[] = {"DisplayDefault", "DisplayHex", "DisplayScientific", "DisplayFixed", + "DisplayGeneral"}; +}; + +template +struct DisplayType {}; + +template <> +struct DisplayType { + static constexpr const char* fmt = ""; +}; + +template <> +struct DisplayType { + static constexpr const char* fmt = "a"; +}; + +template <> +struct DisplayType { + static constexpr const char* fmt = "e"; +}; + +template <> +struct DisplayType { + static constexpr const char* fmt = "f"; +}; + +template <> +struct DisplayType { + static constexpr const char* fmt = "g"; +}; + +// *** Alignment *** +enum class AlignmentE { None, Left, Center, Right, ZeroPadding }; +struct AllAlignments : EnumValuesAsTuple { + static constexpr const char* Names[] = {"AlignNone", "AlignmentLeft", "AlignmentCenter", "AlignmentRight", + "ZeroPadding"}; +}; + +template +struct Alignment {}; + +template <> +struct Alignment { + static constexpr const char* fmt = ""; +}; + +template <> +struct Alignment { + // Width > PrecisionE::Huge + static constexpr const char* fmt = "0<17500"; +}; + +template <> +struct Alignment { + // Width > PrecisionE::Huge + static constexpr const char* fmt = "0^17500"; +}; + +template <> +struct Alignment { + // Width > PrecisionE::Huge + static constexpr const char* fmt = "0>17500"; +}; + +template <> +struct Alignment { + // Width > PrecisionE::Huge + static constexpr const char* fmt = "017500"; +}; + +enum class PrecisionE { None, Zero, Small, Huge }; +struct AllPrecisions : EnumValuesAsTuple { + static constexpr const char* Names[] = {"PrecNone", "PrecZero", "PrecSmall", "PrecHuge"}; +}; + +template +struct Precision {}; + +template <> +struct Precision { + static constexpr const char* fmt = ""; +}; + +template <> +struct Precision { + static constexpr const char* fmt = ".0"; +}; + +template <> +struct Precision { + static constexpr const char* fmt = ".10"; +}; + +template <> +struct Precision { + // The maximum precision for a minimal sub normal long double is ±0x1p-16494. + // This value is always larger than that value forcing the trailing zero path + // to be executed. + static constexpr const char* fmt = ".17000"; +}; + +template +struct FloatingPoint { + using F = typename Type::type; + + void run(benchmark::State& state) const { + std::array data{Value::template make_data()}; + std::array output; + std::string fmt{std::string("{:") + Alignment::fmt + Precision::fmt + + Localization::fmt + DisplayType::fmt + "}"}; + + while (state.KeepRunningBatch(1000)) + for (F value : data) + benchmark::DoNotOptimize(std::format_to(output.begin(), fmt, value)); + } + + std::string name() const { + return "FloatingPoint" + L::name() + DT::name() + T::name() + V::name() + A::name() + P::name(); + } +}; + +int main(int argc, char** argv) { + benchmark::Initialize(&argc, argv); + if (benchmark::ReportUnrecognizedArguments(argc, argv)) + return 1; + + makeCartesianProductBenchmark(); + + benchmark::RunSpecifiedBenchmarks(); +} diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -203,10 +203,10 @@ "`3237 `__","LWG 3038 and 3190 have inconsistent PRs","Prague","|Complete|","14.0" "`3238 `__","Insufficiently-defined behavior of ``std::function``\ deduction guides","Prague","","" "`3242 `__","``std::format``\ : missing rules for ``arg-id``\ in ``width``\ and ``precision``\ ","Prague","|Complete|","Clang 14","|format|" -"`3243 `__","``std::format``\ and negative zeroes","Prague","","","|format|" +"`3243 `__","``std::format``\ and negative zeroes","Prague","|Complete|","14.0","|format|" "`3247 `__","``ranges::iter_move``\ should perform ADL-only lookup of ``iter_move``\ ","Prague","","","|ranges|" "`3248 `__","``std::format``\ ``#b``\ , ``#B``\ , ``#o``\ , ``#x``\ , and ``#X``\ presentation types misformat negative numbers","Prague","|Complete|","14.0","|format|" -"`3250 `__","``std::format``\ : ``#``\ (alternate form) for NaN and inf","Prague","","","|format|" +"`3250 `__","``std::format``\ : ``#``\ (alternate form) for NaN and inf","Prague","|Complete|","14.0","|format|" "`3251 `__","Are ``std::format``\ alignment specifiers applied to string arguments?","Prague","","","|format|" "`3252 `__","Parse locale's aware modifiers for commands are not consistent with POSIX spec","Prague","","","|chrono|" "`3254 `__","Strike ``stop_token``\ 's ``operator!=``\ ","Prague","","" diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -129,7 +129,7 @@ "`P1644R0 `__","LWG","Add wait/notify to atomic","Cologne","","" "`P1650R0 `__","LWG","Output std::chrono::days with 'd' suffix","Cologne","","" "`P1651R0 `__","LWG","bind_front should not unwrap reference_wrapper","Cologne","|Complete|","13.0" -"`P1652R1 `__","LWG","Printf corner cases in std::format","Cologne","|In Progress|","" +"`P1652R1 `__","LWG","Printf corner cases in std::format","Cologne","|Complete|","14.0" "`P1661R1 `__","LWG","Remove dedicated precalculated hash lookup interface","Cologne","|Nothing To Do|","" "`P1754R1 `__","LWG","Rename concepts to standard_case for C++20, while we still can","Cologne","|In Progress|","" "","","","","","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -178,6 +178,7 @@ __format/formatter.h __format/formatter_bool.h __format/formatter_char.h + __format/formatter_floating_point.h __format/formatter_integer.h __format/formatter_integral.h __format/formatter_string.h diff --git a/libcxx/include/__format/formatter.h b/libcxx/include/__format/formatter.h --- a/libcxx/include/__format/formatter.h +++ b/libcxx/include/__format/formatter.h @@ -190,6 +190,34 @@ return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill); } +/** + * @overload + * + * Writes additional zero's for the precision before the exponent. + * This is used when the precision requested in the format string is larger + * than the maximum precision of the floating-point type. These precision + * digits are always 0. + * + * @param __exponent The location of the exponent character. + * @param __num_trailing_zeros The number of 0's to write before the exponent + * character. + */ +template +_LIBCPP_HIDE_FROM_ABI auto __write(output_iterator auto __out_it, const _CharT* __first, + const _CharT* __last, size_t __size, size_t __width, _Fill __fill, + __format_spec::_Flags::_Alignment __alignment, const _CharT* __exponent, + size_t __num_trailing_zeros) -> decltype(__out_it) { + _LIBCPP_ASSERT(__first <= __last, "Not a valid range"); + _LIBCPP_ASSERT(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used"); + + __padding_size_result __padding = __padding_size(__size + __num_trailing_zeros, __width, __alignment); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill); + __out_it = _VSTD::copy(__first, __exponent, _VSTD::move(__out_it)); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __num_trailing_zeros, _CharT('0')); + __out_it = _VSTD::copy(__exponent, __last, _VSTD::move(__out_it)); + return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill); +} + /** * @overload * diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__format/formatter_floating_point.h @@ -0,0 +1,717 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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 _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H +#define _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H + +#include <__algorithm/copy.h> +#include <__algorithm/copy_n.h> +#include <__algorithm/fill_n.h> +#include <__algorithm/find.h> +#include <__algorithm/min.h> +#include <__algorithm/rotate.h> +#include <__algorithm/transform.h> +#include <__concepts/arithmetic.h> +#include <__config> +#include <__debug> +#include <__format/format_error.h> +#include <__format/format_fwd.h> +#include <__format/format_string.h> +#include <__format/formatter.h> +#include <__format/formatter_integral.h> +#include <__format/parser_std_format_spec.h> +#include <__utility/move.h> +#include +#include + +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if _LIBCPP_STD_VER > 17 + +// TODO FMT Remove this once we require compilers with proper C++20 support. +// If the compiler has no concepts support, the format header will be disabled. +// Without concepts support enable_if needs to be used and that too much effort +// to support compilers with partial C++20 support. +# if !defined(_LIBCPP_HAS_NO_CONCEPTS) + +namespace __format_spec { + +template +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) { + to_chars_result __r = _VSTD::to_chars(__first, __last, __value); + _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +template +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) { + to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt); + _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +template +_LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) { + to_chars_result __r = _VSTD::to_chars(__first, __last, __value, __fmt, __precision); + _LIBCPP_ASSERT(__r.ec == errc(0), "Internal buffer too small"); + return __r.ptr; +} + +// https://en.cppreference.com/w/cpp/language/types#cite_note-1 +// float min subnormal: +/-0x1p-149 max: +/- 3.402,823,4 10^38 +// double min subnormal: +/-0x1p-1074 max +/- 1.797,693,134,862,315,7 10^308 +// long double (x86) min subnormal: +/-0x1p-16446 max: +/- 1.189,731,495,357,231,765,021 10^4932 +// +// The maximum number of digits required for the integral part is based on the +// maximum's value power of 10. Every power of 10 requires one additional +// decimal digit. +// The maximum number of digits required for the fractional part is based on +// the minimal subnormal hexadecimal output's power of 10. Every division of a +// fraction's binary 1 by 2, requires one additional decimal digit. +// +// The maximum size of a formatted value depends on the selected output format. +// Ignoring the fact the format string can request a precision larger than the +// values maximum required, these values are: +// +// sign 1 code unit +// __max_integral +// radix point 1 code unit +// __max_fractional +// exponent character 1 code unit +// sign 1 code unit +// __max_fractional_value +// ----------------------------------- +// total 4 code units extra required. +// +// TODO FMT Optimize the storage to avoid storing digits that are known to be zero. +// https://www.exploringbinary.com/maximum-number-of-decimal-digits-in-binary-floating-point-numbers/ + +// TODO FMT Add long double specialization when to_chars has proper long double support. +template +struct __traits; + +template +static constexpr size_t __float_buffer_size(int __precision) { + using _Traits = __traits<_Fp>; + return 4 + _Traits::__max_integral + __precision + _Traits::__max_fractional_value; +} + +template <> +struct __traits { + static constexpr int __max_integral = 38; + static constexpr int __max_fractional = 149; + static constexpr int __max_fractional_value = 3; + static constexpr size_t __stack_buffer_size = 256; + + static constexpr int __hex_precision_digits = 3; +}; + +template <> +struct __traits { + static constexpr int __max_integral = 308; + static constexpr int __max_fractional = 1074; + static constexpr int __max_fractional_value = 4; + static constexpr size_t __stack_buffer_size = 1024; + + static constexpr int __hex_precision_digits = 4; +}; + +/// Helper class to store the conversion buffer. +/// +/// Depending on the maxium size required for a value, the buffer is allocated +/// on the stack or the heap. +template +class _LIBCPP_TEMPLATE_VIS __float_buffer { + using _Traits = __traits<_Fp>; + +public: + // TODO FMT Improve this constructor to do a better estimate. + // When using a scientific formatting with a precision of 6 a stack buffer + // will always suffice. At the moment that isn't important since floats and + // doubles use a stack buffer, unless the precision used in the format string + // is large. + // When supporting long doubles the __max_integral part becomes 4932 which + // may be too much for some platforms. For these cases a better estimate is + // required. + explicit _LIBCPP_HIDE_FROM_ABI __float_buffer(int __precision) + : __precision_(__precision != -1 ? __precision : _Traits::__max_fractional) { + + // When the precision is larger than _Traits::__max_fractional the digits in + // the range (_Traits::__max_fractional, precision] will contain the value + // zero. There's no need to request to_chars to write these zeros: + // - When the value is large a temporary heap buffer needs to be allocated. + // - When to_chars writes the values they need to be "copied" to the output: + // - char: std::fill on the output iterator is faster than std::copy. + // - wchar_t: same argument as char, but additional std::copy won't work. + // The input is always a char buffer, so every char in the buffer needs + // to be converted from a char to a wchar_t. + if (__precision_ > _Traits::__max_fractional) { + __num_trailing_zeros_ = __precision_ - _Traits::__max_fractional; + __precision_ = _Traits::__max_fractional; + } + + __size_ = __format_spec::__float_buffer_size<_Fp>(__precision_); + if (__size_ > _Traits::__stack_buffer_size) + // The allocated buffer's contents don't need initialization. + __begin_ = allocator{}.allocate(__size_); + else + __begin_ = __buffer_; + } + + _LIBCPP_HIDE_FROM_ABI ~__float_buffer() { + if (__size_ > _Traits::__stack_buffer_size) + allocator{}.deallocate(__begin_, __size_); + } + _LIBCPP_HIDE_FROM_ABI __float_buffer(const __float_buffer&) = delete; + _LIBCPP_HIDE_FROM_ABI __float_buffer& operator=(const __float_buffer&) = delete; + + _LIBCPP_HIDE_FROM_ABI char* begin() const { return __begin_; } + _LIBCPP_HIDE_FROM_ABI char* end() const { return __begin_ + __size_; } + + _LIBCPP_HIDE_FROM_ABI int __precision() const { return __precision_; } + _LIBCPP_HIDE_FROM_ABI int __num_trailing_zeros() const { return __num_trailing_zeros_; } + _LIBCPP_HIDE_FROM_ABI void __remove_trailing_zeros() { __num_trailing_zeros_ = 0; } + +private: + int __precision_; + int __num_trailing_zeros_{0}; + size_t __size_; + char* __begin_; + char __buffer_[_Traits::__stack_buffer_size]; +}; + +struct __float_result { + /// Points at the beginning of the integral part in the buffer. + /// + /// When there's no sign character this points at the start of the buffer. + char* __integral; + + /// Points at the radix point, when not present it's the same as \ref __last. + char* __radix_point; + + /// Points at the exponent character, when not present it's the same as \ref __last. + char* __exponent; + + /// Points beyond the last written element in the buffer. + char* __last; +}; + +/// Finds the position of the exponent character 'e' at the end of the buffer. +/// +/// Assuming there is an exponent the input will terminate with +/// eSdd and eSdddd (S = sign, d = digit) +/// +/// \returns a pointer to the exponent or __last when not found. +constexpr inline _LIBCPP_HIDE_FROM_ABI char* __find_exponent(char* __first, char* __last) { + ptrdiff_t __size = __last - __first; + if (__size > 4) { + __first = __last - _VSTD::min(__size, ptrdiff_t(6)); + for (; __first != __last - 3; ++__first) { + if (*__first == 'e') + return __first; + } + } + return __last; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value, + char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value); + + __result.__exponent = __format_spec::__find_exponent(__result.__integral, __result.__last); + + // Constrains: + // - There's at least one decimal digit before the radix point. + // - The radix point, when present, is placed before the exponent. + __result.__radix_point = _VSTD::find(__result.__integral + 1, __result.__exponent, '.'); + + // When the radix point isn't found its position is the exponent instead of + // __result.__last. + if (__result.__radix_point == __result.__exponent) + __result.__radix_point = __result.__last; + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result; + __result.__integral = __integral; + if (__precision == -1) + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex); + else + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::hex, __precision); + + // H = one or more hex-digits + // S = sign + // D = one or more decimal-digits + // When the fractional part is zero and no precision the output is 0p+0 + // else the output is 0.HpSD + // So testing the second position can differentiate between these two cases. + char* __first = __integral + 1; + if (*__first == '.') { + __result.__radix_point = __first; + // One digit is the minimum + // 0.hpSd + // ^-- last + // ^---- integral = end of search + // ^-------- start of search + // 0123456 + // + // Four digits is the maximum + // 0.hpSdddd + // ^-- last + // ^---- integral = end of search + // ^-------- start of search + // 0123456789 + static_assert(__traits<_Fp>::__hex_precision_digits <= 4, "Guard against possible underflow."); + + char* __last = __result.__last - 2; + __first = __last - __traits<_Fp>::__hex_precision_digits; + __result.__exponent = _VSTD::find(__first, __last, 'p'); + } else { + __result.__radix_point = __result.__last; + __result.__exponent = __first; + } + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'p'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_upper_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result = + __format_spec::__format_buffer_hexadecimal_lower_case(__buffer, __value, __precision, __integral); + _VSTD::transform(__result.__integral, __result.__exponent, __result.__integral, __hex_to_upper); + *__result.__exponent = 'P'; + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = + __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision); + + char* __first = __integral + 1; + _LIBCPP_ASSERT(__first != __result.__last, "No exponent present"); + if (*__first == '.') { + __result.__radix_point = __first; + __result.__exponent = __format_spec::__find_exponent(__first + 1, __result.__last); + } else { + __result.__radix_point = __result.__last; + __result.__exponent = __first; + } + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_upper_case(const __float_buffer<_Fp>& __buffer, + _Tp __value, int __precision, + char* __integral) { + __float_result __result = + __format_spec::__format_buffer_scientific_lower_case(__buffer, __value, __precision, __integral); + *__result.__exponent = 'E'; + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value, + int __precision, char* __integral) { + __float_result __result; + __result.__integral = __integral; + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::fixed, __precision); + + // When there's no precision there's no radix point. + // Else the radix point is placed at __precision + 1 from the end. + // By converting __precision to a bool the subtraction can be done + // unconditionally. + __result.__radix_point = __result.__last - (__precision + bool(__precision)); + __result.__exponent = __result.__last; + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last), + "Post-condition failure."); + // clang-format on + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value, + int __precision, char* __integral) { + + __buffer.__remove_trailing_zeros(); + + __float_result __result; + __result.__integral = __integral; + __result.__last = __format_spec::__to_buffer(__integral, __buffer.end(), __value, chars_format::general, __precision); + + char* __first = __integral + 1; + if (__first == __result.__last) { + __result.__radix_point = __result.__last; + __result.__exponent = __result.__last; + } else { + __result.__exponent = __format_spec::__find_exponent(__first, __result.__last); + if (__result.__exponent != __result.__last) + // In scientific mode if there's a radix point it will always be after + // the first digit. (This is the position __first points at). + __result.__radix_point = *__first == '.' ? __first : __result.__last; + else { + // In fixed mode the algorithm truncates trailing spaces and possibly the + // radix point. There's no good guess for the position of the radix point + // therefore scan the output after the first digit. + __result.__radix_point = _VSTD::find(__first, __result.__last, '.'); + } + } + + // clang-format off + _LIBCPP_ASSERT((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); + // clang-format on + + return __result; +} + +template +_LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_upper_case(__float_buffer<_Fp>& __buffer, _Tp __value, + int __precision, char* __integral) { + __float_result __result = + __format_spec::__format_buffer_general_lower_case(__buffer, __value, __precision, __integral); + if (__result.__exponent != __result.__last) + *__result.__exponent = 'E'; + return __result; +} + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION +template +_LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(_OutIt __out_it, const __float_buffer<_Fp>& __buffer, + const __float_result& __result, _VSTD::locale __loc, + size_t __width, _Flags::_Alignment __alignment, + _CharT __fill) { + const auto& __np = use_facet>(__loc); + string __grouping = __np.grouping(); + char* __first = __result.__integral; + // When no radix point or exponent are present __last will be __result.__last. + char* __last = _VSTD::min(__result.__radix_point, __result.__exponent); + + ptrdiff_t __digits = __last - __first; + if (!__grouping.empty()) { + if (__digits <= __grouping[0]) + __grouping.clear(); + else + __grouping = __determine_grouping(__digits, __grouping); + } + + size_t __size = __result.__last - __buffer.begin() + // Formatted string + __buffer.__num_trailing_zeros() + // Not yet rendered zeros + __grouping.size() - // Grouping contains one + !__grouping.empty(); // additional character + + __formatter::__padding_size_result __padding = {0, 0}; + bool __zero_padding = __alignment == _Flags::_Alignment::__default; + if (__size < __width) { + if (__zero_padding) { + __alignment = _Flags::_Alignment::__right; + __fill = _CharT('0'); + } + + __padding = __formatter::__padding_size(__size, __width, __alignment); + } + + // sign and (zero padding or alignment) + if (__zero_padding && __first != __buffer.begin()) + *__out_it++ = *__buffer.begin(); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __padding.__before, __fill); + if (!__zero_padding && __first != __buffer.begin()) + *__out_it++ = *__buffer.begin(); + + // integral part + if (__grouping.empty()) { + __out_it = _VSTD::copy_n(__first, __digits, _VSTD::move(__out_it)); + } else { + auto __r = __grouping.rbegin(); + auto __e = __grouping.rend() - 1; + _CharT __sep = __np.thousands_sep(); + // The output is divided in small groups of numbers to write: + // - A group before the first separator. + // - A separator and a group, repeated for the number of separators. + // - A group after the last separator. + // This loop achieves that process by testing the termination condition + // midway in the loop. + while (true) { + __out_it = _VSTD::copy_n(__first, *__r, _VSTD::move(__out_it)); + __first += *__r; + + if (__r == __e) + break; + + ++__r; + *__out_it++ = __sep; + } + } + + // fractional part + if (__result.__radix_point != __result.__last) { + *__out_it++ = __np.decimal_point(); + __out_it = _VSTD::copy(__result.__radix_point + 1, __result.__exponent, _VSTD::move(__out_it)); + __out_it = _VSTD::fill_n(_VSTD::move(__out_it), __buffer.__num_trailing_zeros(), _CharT('0')); + } + + // exponent + if (__result.__exponent != __result.__last) + __out_it = _VSTD::copy(__result.__exponent, __result.__last, _VSTD::move(__out_it)); + + // alignment + return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after, __fill); +} + +# endif // _LIBCPP_HAS_NO_LOCALIZATION + +template <__formatter::__char_type _CharT> +class _LIBCPP_TEMPLATE_VIS __formatter_floating_point : public __parser_floating_point<_CharT> { +public: + template + _LIBCPP_HIDE_FROM_ABI auto format(_Tp __value, auto& __ctx) -> decltype(__ctx.out()) { + if (this->__width_needs_substitution()) + this->__substitute_width_arg_id(__ctx.arg(this->__width)); + + bool __negative = _VSTD::signbit(__value); + + if (!_VSTD::isfinite(__value)) [[unlikely]] + return __format_non_finite(__ctx.out(), __negative, _VSTD::isnan(__value)); + + bool __has_precision = this->__has_precision_field(); + if (this->__precision_needs_substitution()) + this->__substitute_precision_arg_id(__ctx.arg(this->__precision)); + + // Depending on the std-format-spec string the sign and the value + // might not be outputted together: + // - zero-padding may insert additional '0' characters. + // Therefore the value is processed as a non negative value. + // The function @ref __insert_sign will insert a '-' when the value was + // negative. + + if (__negative) + __value = _VSTD::copysign(__value, +1.0); + + // TODO FMT _Fp should just be _Tp when to_chars has proper long double support. + using _Fp = conditional_t, double, _Tp>; + // Force the type of the precision to avoid -1 to become an unsigned value. + __float_buffer<_Fp> __buffer(__has_precision ? int(this->__precision) : -1); + __float_result __result = __format_buffer(__buffer, __value, __negative, __has_precision); + + if (this->__alternate_form && __result.__radix_point == __result.__last) { + *__result.__last++ = '.'; + + // When there is an exponent the point needs to be moved before the + // exponent. When there's no exponent the rotate does nothing. Since + // rotate tests whether the operation is a nop, call it unconditionally. + _VSTD::rotate(__result.__exponent, __result.__last - 1, __result.__last); + __result.__radix_point = __result.__exponent; + + // The radix point is always placed before the exponent. + // - No exponent needs to point to the new last. + // - An exponent needs to move one position to the right. + // So it's safe to increment the value unconditionally. + ++__result.__exponent; + } + +# ifndef _LIBCPP_HAS_NO_LOCALIZATION + if (this->__locale_specific_form) + return __format_spec::__format_locale_specific_form(__ctx.out(), __buffer, __result, __ctx.locale(), + this->__width, this->__alignment, this->__fill); +# endif + + ptrdiff_t __size = __result.__last - __buffer.begin(); + int __num_trailing_zeros = __buffer.__num_trailing_zeros(); + if (__size + __num_trailing_zeros >= this->__width) { + if (__num_trailing_zeros && __result.__exponent != __result.__last) + // Insert trailing zeros before exponent character. + return _VSTD::copy(__result.__exponent, __result.__last, + _VSTD::fill_n(_VSTD::copy(__buffer.begin(), __result.__exponent, __ctx.out()), + __num_trailing_zeros, _CharT('0'))); + + return _VSTD::fill_n(_VSTD::copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros, + _CharT('0')); + } + + auto __out_it = __ctx.out(); + char* __first = __buffer.begin(); + if (this->__alignment == _Flags::_Alignment::__default) { + // When there is a sign output it before the padding. Note the __size + // doesn't need any adjustment, regardless whether the sign is written + // here or in __formatter::__write. + if (__first != __result.__integral) + *__out_it++ = *__first++; + // After the sign is written, zero padding is the same a right alignment + // with '0'. + this->__alignment = _Flags::_Alignment::__right; + this->__fill = _CharT('0'); + } + + if (__num_trailing_zeros) + return __formatter::__write(_VSTD::move(__out_it), __first, __result.__last, __size, this->__width, this->__fill, + this->__alignment, __result.__exponent, __num_trailing_zeros); + + return __formatter::__write(_VSTD::move(__out_it), __first, __result.__last, __size, this->__width, this->__fill, + this->__alignment); + } + +private: + template + _LIBCPP_HIDE_FROM_ABI _OutIt __format_non_finite(_OutIt __out_it, bool __negative, bool __isnan) { + char __buffer[4]; + char* __last = __insert_sign(__buffer, __negative, this->__sign); + + // to_char can return inf, infinity, nan, and nan(n-char-sequence). + // The format library requires inf and nan. + // All in one expression to avoid dangling references. + __last = _VSTD::copy_n(&("infnanINFNAN"[6 * (this->__type == _Flags::_Type::__float_hexadecimal_upper_case || + this->__type == _Flags::_Type::__scientific_upper_case || + this->__type == _Flags::_Type::__fixed_upper_case || + this->__type == _Flags::_Type::__general_upper_case) + + 3 * __isnan]), + 3, __last); + + // [format.string.std]/13 + // A zero (0) character preceding the width field pads the field with + // leading zeros (following any indication of sign or base) to the field + // width, except when applied to an infinity or NaN. + if (this->__alignment == _Flags::_Alignment::__default) + this->__alignment = _Flags::_Alignment::__right; + + ptrdiff_t __size = __last - __buffer; + if (__size >= this->__width) + return _VSTD::copy_n(__buffer, __size, _VSTD::move(__out_it)); + + return __formatter::__write(_VSTD::move(__out_it), __buffer, __last, __size, this->__width, this->__fill, + this->__alignment); + } + + /// Fills the buffer with the data based on the requested formatting. + /// + /// This function, when needed, turns the characters to upper case and + /// determines the "interesting" locations which are returned to the caller. + /// + /// This means the caller never has to convert the contents of the buffer to + /// upper case or search for radix points and the location of the exponent. + /// This gives a bit of overhead. The original code didn't do that, but due + /// to the number of possible additional work needed to turn this number to + /// the proper output the code was littered with tests for upper cases and + /// searches for radix points and exponents. + /// - When a precision larger than the type's precision is selected + /// additional zero characters need to be written before the exponent. + /// - alternate form needs to add a radix point when not present. + /// - localization needs to do grouping in the integral part. + template + // TODO FMT _Fp should just be _Tp when to_chars has proper long double support. + _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(__float_buffer<_Fp>& __buffer, _Tp __value, bool __negative, + bool __has_precision) { + char* __first = __insert_sign(__buffer.begin(), __negative, this->__sign); + switch (this->__type) { + case _Flags::_Type::__default: + return __format_spec::__format_buffer_default(__buffer, __value, __first); + + case _Flags::_Type::__float_hexadecimal_lower_case: + return __format_spec::__format_buffer_hexadecimal_lower_case( + __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); + + case _Flags::_Type::__float_hexadecimal_upper_case: + return __format_spec::__format_buffer_hexadecimal_upper_case( + __buffer, __value, __has_precision ? __buffer.__precision() : -1, __first); + + case _Flags::_Type::__scientific_lower_case: + return __format_spec::__format_buffer_scientific_lower_case(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__scientific_upper_case: + return __format_spec::__format_buffer_scientific_upper_case(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__fixed_lower_case: + case _Flags::_Type::__fixed_upper_case: + return __format_spec::__format_buffer_fixed(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__general_lower_case: + return __format_spec::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first); + + case _Flags::_Type::__general_upper_case: + return __format_spec::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first); + + default: + _LIBCPP_ASSERT(false, "The parser should have validated the type"); + _LIBCPP_UNREACHABLE(); + } + } +}; + +} //namespace __format_spec + +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter + : public __format_spec::__formatter_floating_point<_CharT> {}; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter + : public __format_spec::__formatter_floating_point<_CharT> {}; +template <__formatter::__char_type _CharT> +struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter + : public __format_spec::__formatter_floating_point<_CharT> {}; + +# endif // !defined(_LIBCPP_HAS_NO_CONCEPTS) + +#endif //_LIBCPP_STD_VER > 17 + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___FORMAT_FORMATTER_FLOATING_POINT_H diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h --- a/libcxx/include/__format/formatter_integral.h +++ b/libcxx/include/__format/formatter_integral.h @@ -82,7 +82,7 @@ namespace __format_spec { /** Wrapper around @ref to_chars, returning the output pointer. */ -template +template _LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, int __base) { // TODO FMT Evaluate code overhead due to not calling the internal function diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h --- a/libcxx/include/__format/parser_std_format_spec.h +++ b/libcxx/include/__format/parser_std_format_spec.h @@ -475,6 +475,21 @@ return ++__begin; } +/** + * Process the parsed alignment and zero-padding state of arithmetic types. + * + * [format.string.std]/13 + * If the 0 character and an align option both appear, the 0 character is + * ignored. + * + * For the formatter a @ref __default alignment means zero-padding. + */ +_LIBCPP_HIDE_FROM_ABI constexpr void __process_arithmetic_alignment(_Flags& __flags) { + __flags.__zero_padding &= __flags.__alignment == _Flags::_Alignment::__default; + if (!__flags.__zero_padding && __flags.__alignment == _Flags::_Alignment::__default) + __flags.__alignment = _Flags::_Alignment::__right; +} + /** * The parser for the std-format-spec. * @@ -648,23 +663,9 @@ return __begin; } - /** - * Handles the post-parsing updates for the integer types. - * - * Updates the zero-padding and alignment for integer types. - * - * [format.string.std]/13 - * If the 0 character and an align option both appear, the 0 character is - * ignored. - * - * For the formatter a @ref __default alignment means zero-padding. Update - * the alignment based on parsed format string. - */ + /** Handles the post-parsing updates for the integer types. */ _LIBCPP_HIDE_FROM_ABI constexpr void __handle_integer() noexcept { - this->__zero_padding &= this->__alignment == _Flags::_Alignment::__default; - if (!this->__zero_padding && - this->__alignment == _Flags::_Alignment::__default) - this->__alignment = _Flags::_Alignment::__right; + __process_arithmetic_alignment(static_cast<_Flags&>(*this)); } /** @@ -701,7 +702,130 @@ } }; -// TODO FMT Add a parser for floating-point values. +/** + * The parser for the std-format-spec. + * + * This implements the parser for the floating-point types. + * + * See @ref __parser_string. + */ +template +class _LIBCPP_TEMPLATE_VIS __parser_floating_point + : public __parser_width, // provides __width(|as_arg) + public __parser_precision, // provides __precision(|as_arg) + public __parser_fill_align<_CharT>, // provides __fill and uses __flags + public _Flags // provides __flags +{ +public: + using char_type = _CharT; + + /** + * The low-level std-format-spec parse function. + * + * @pre __begin points at the beginning of the std-format-spec. This means + * directly after the ':'. + * @pre The std-format-spec parses the entire input, or the first unmatched + * character is a '}'. + * + * @returns The iterator pointing at the last parsed character. + */ + _LIBCPP_HIDE_FROM_ABI constexpr auto parse(auto& __parse_ctx) + -> decltype(__parse_ctx.begin()) { + auto __it = __parse(__parse_ctx); + __process_arithmetic_alignment(static_cast<_Flags&>(*this)); + __process_display_type(); + return __it; + } +protected: + /** + * The low-level std-format-spec parse function. + * + * @pre __begin points at the beginning of the std-format-spec. This means + * directly after the ':'. + * @pre The std-format-spec parses the entire input, or the first unmatched + * character is a '}'. + * + * @returns The iterator pointing at the last parsed character. + */ + _LIBCPP_HIDE_FROM_ABI constexpr auto __parse(auto& __parse_ctx) + -> decltype(__parse_ctx.begin()) { + auto __begin = __parse_ctx.begin(); + auto __end = __parse_ctx.end(); + if (__begin == __end) + return __begin; + + __begin = __parser_fill_align<_CharT>::__parse(__begin, __end, + static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_sign(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_alternate_form(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_zero_padding(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parser_width::__parse(__begin, __end, __parse_ctx); + if (__begin == __end) + return __begin; + + __begin = __parser_precision::__parse(__begin, __end, __parse_ctx); + if (__begin == __end) + return __begin; + + __begin = + __parse_locale_specific_form(__begin, static_cast<_Flags&>(*this)); + if (__begin == __end) + return __begin; + + __begin = __parse_type(__begin, static_cast<_Flags&>(*this)); + + if (__begin != __end && *__begin != _CharT('}')) + __throw_format_error( + "The format-spec should consume the input or end with a '}'"); + + return __begin; + } + + /** Processes the parsed std-format-spec based on the parsed display type. */ + _LIBCPP_HIDE_FROM_ABI constexpr void __process_display_type() { + switch (this->__type) { + case _Flags::_Type::__default: + // When no precision specified then it keeps default since that + // formatting differs from the other types. + if (this->__has_precision_field()) + this->__type = _Flags::_Type::__general_lower_case; + break; + case _Flags::_Type::__float_hexadecimal_lower_case: + case _Flags::_Type::__float_hexadecimal_upper_case: + // Precision specific behavior will be handled later. + break; + case _Flags::_Type::__scientific_lower_case: + case _Flags::_Type::__scientific_upper_case: + case _Flags::_Type::__fixed_lower_case: + case _Flags::_Type::__fixed_upper_case: + case _Flags::_Type::__general_lower_case: + case _Flags::_Type::__general_upper_case: + if (!this->__has_precision_field()) { + // Set the default precision for the call to to_chars. + this->__precision = 6; + this->__precision_as_arg = false; + } + break; + + default: + __throw_format_error("The format-spec type has a type not supported for " + "a floating-point argument"); + } + } +}; + // TODO FMT Add a parser for pointer values. /** Helper struct returned from @ref __get_string_alignment. */ diff --git a/libcxx/include/format b/libcxx/include/format --- a/libcxx/include/format +++ b/libcxx/include/format @@ -277,6 +277,7 @@ #include <__format/formatter.h> #include <__format/formatter_bool.h> #include <__format/formatter_char.h> +#include <__format/formatter_floating_point.h> #include <__format/formatter_integer.h> #include <__format/formatter_string.h> #include <__format/parser_std_format_spec.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -488,25 +488,26 @@ export * module __format { - module format_arg { private header "__format/format_arg.h" } - module format_args { private header "__format/format_args.h" } + module format_arg { private header "__format/format_arg.h" } + module format_args { private header "__format/format_args.h" } module format_context { private header "__format/format_context.h" export optional export locale } - module format_error { private header "__format/format_error.h" } - module format_fwd { private header "__format/format_fwd.h" } - module format_parse_context { private header "__format/format_parse_context.h" } - module format_string { private header "__format/format_string.h" } - module format_to_n_result { private header "__format/format_to_n_result.h" } - module formatter { private header "__format/formatter.h" } - module formatter_bool { private header "__format/formatter_bool.h" } - module formatter_char { private header "__format/formatter_char.h" } - module formatter_integer { private header "__format/formatter_integer.h" } - module formatter_integral { private header "__format/formatter_integral.h" } - module formatter_string { private header "__format/formatter_string.h" } - module parser_std_format_spec { private header "__format/parser_std_format_spec.h" } + module format_error { private header "__format/format_error.h" } + module format_fwd { private header "__format/format_fwd.h" } + module format_parse_context { private header "__format/format_parse_context.h" } + module format_string { private header "__format/format_string.h" } + module format_to_n_result { private header "__format/format_to_n_result.h" } + module formatter { private header "__format/formatter.h" } + module formatter_bool { private header "__format/formatter_bool.h" } + module formatter_char { private header "__format/formatter_char.h" } + module formatter_floating_point { private header "__format/formatter_floating_point.h" } + module formatter_integer { private header "__format/formatter_integer.h" } + module formatter_integral { private header "__format/formatter_integral.h" } + module formatter_string { private header "__format/formatter_string.h" } + module parser_std_format_spec { private header "__format/parser_std_format_spec.h" } } } module forward_list { diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/format/formatter_floating_point.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__format/formatter_floating_point.h'}} +#include <__format/formatter_floating_point.h> diff --git a/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/format/format.string/format.string.std/std_format_spec_floating_point.pass.cpp @@ -0,0 +1,353 @@ +//===----------------------------------------------------------------------===// +// 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 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: libcpp-has-no-incomplete-format + +// + +// Tests the parsing of the format string as specified in [format.string.std]. +// It validates whether the std-format-spec is valid for a floating-point type. + +#include +#include +#ifndef _LIBCPP_HAS_NO_LOCALIZATION +# include +#endif + +#include "concepts_precision.h" +#include "test_macros.h" +#include "make_string.h" +#include "test_exception.h" + +#define CSTR(S) MAKE_CSTRING(CharT, S) + +using namespace std::__format_spec; + +template +using Parser = __parser_floating_point; + +template +struct Expected { + CharT fill = CharT(' '); + _Flags::_Alignment alignment = _Flags::_Alignment::__right; + _Flags::_Sign sign = _Flags::_Sign::__default; + bool alternate_form = false; + bool zero_padding = false; + uint32_t width = 0; + bool width_as_arg = false; + uint32_t precision = std::__format::__number_max; + bool precision_as_arg = true; + bool locale_specific_form = false; + _Flags::_Type type = _Flags::_Type::__default; +}; + +template +constexpr void test(Expected expected, size_t size, std::basic_string_view fmt) { + // Initialize parser with sufficient arguments to avoid the parsing to fail + // due to insufficient arguments. + std::basic_format_parse_context parse_ctx(fmt, std::__format::__number_max); + auto begin = parse_ctx.begin(); + auto end = parse_ctx.end(); + Parser parser; + auto it = parser.parse(parse_ctx); + + assert(begin == parse_ctx.begin()); + assert(end == parse_ctx.end()); + + assert(begin + size == it); + assert(parser.__fill == expected.fill); + assert(parser.__alignment == expected.alignment); + assert(parser.__sign == expected.sign); + assert(parser.__alternate_form == expected.alternate_form); + assert(parser.__zero_padding == expected.zero_padding); + assert(parser.__width == expected.width); + assert(parser.__width_as_arg == expected.width_as_arg); + assert(parser.__precision == expected.precision); + assert(parser.__precision_as_arg == expected.precision_as_arg); + assert(parser.__locale_specific_form == expected.locale_specific_form); + assert(parser.__type == expected.type); +} + +template +constexpr void test(Expected expected, size_t size, const CharT* f) { + // The format-spec is valid if completely consumed or terminates at a '}'. + // The valid inputs all end with a '}'. The test is executed twice: + // - first with the terminating '}', + // - second consuming the entire input. + std::basic_string_view fmt{f}; + assert(fmt.back() == CharT('}') && "Pre-condition failure"); + + test(expected, size, fmt); + fmt.remove_suffix(1); + test(expected, size, fmt); +} + +template +constexpr void test() { + Parser parser; + + assert(parser.__fill == CharT(' ')); + assert(parser.__alignment == _Flags::_Alignment::__default); + assert(parser.__sign == _Flags::_Sign::__default); + assert(parser.__alternate_form == false); + assert(parser.__zero_padding == false); + assert(parser.__width == 0); + assert(parser.__width_as_arg == false); + assert(parser.__precision == std::__format::__number_max); + assert(parser.__precision_as_arg == true); + assert(parser.__locale_specific_form == false); + assert(parser.__type == _Flags::_Type::__default); + + // Depending on whether or not a precision is specified the results differ. + // Table 65: Meaning of type options for floating-point types [tab:format.type.float] + + test({}, 0, CSTR("}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 2, CSTR(".0}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 4, CSTR(".{1}}")); + + test({.type = _Flags::_Type::__float_hexadecimal_lower_case}, 1, CSTR("a}")); + test({.type = _Flags::_Type::__float_hexadecimal_upper_case}, 1, CSTR("A}")); + + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_lower_case}, 1, CSTR("e}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__scientific_lower_case}, 3, CSTR(".0e}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__scientific_lower_case}, 5, CSTR(".{1}e}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_upper_case}, 1, CSTR("E}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__scientific_upper_case}, 3, CSTR(".0E}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__scientific_upper_case}, 5, CSTR(".{1}E}")); + + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_lower_case}, 1, CSTR("f}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__fixed_lower_case}, 3, CSTR(".0f}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__fixed_lower_case}, 5, CSTR(".{1}f}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_upper_case}, 1, CSTR("F}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__fixed_upper_case}, 3, CSTR(".0F}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__fixed_upper_case}, 5, CSTR(".{1}F}")); + + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 1, CSTR("g}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 3, CSTR(".0g}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 5, CSTR(".{1}g}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_upper_case}, 1, CSTR("G}")); + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_upper_case}, 3, CSTR(".0G}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_upper_case}, 5, CSTR(".{1}G}")); + + // *** Align-fill *** + test({.alignment = _Flags::_Alignment::__left}, 1, CSTR("<}")); + test({.alignment = _Flags::_Alignment::__center}, 1, "^}"); + test({.alignment = _Flags::_Alignment::__right}, 1, ">}"); + + test({.fill = CharT('L'), .alignment = _Flags::_Alignment::__left}, 2, CSTR("L<}")); + test({.fill = CharT('#'), .alignment = _Flags::_Alignment::__center}, 2, CSTR("#^}")); + test({.fill = CharT('0'), .alignment = _Flags::_Alignment::__right}, 2, CSTR("0>}")); + + test_exception>("The format-spec fill field contains an invalid character", CSTR("{<")); + test_exception>("The format-spec fill field contains an invalid character", CSTR("}<")); + + // *** Sign *** + test({.sign = _Flags::_Sign::__minus}, 1, CSTR("-}")); + test({.sign = _Flags::_Sign::__plus}, 1, CSTR("+}")); + test({.sign = _Flags::_Sign::__space}, 1, CSTR(" }")); + + // *** Alternate form *** + test({.alternate_form = true}, 1, CSTR("#}")); + + // *** Zero padding *** + // TODO FMT What to do with zero-padding without a width? + // [format.string.std]/13 + // A zero (0) character preceding the width field pads the field with + // leading zeros (following any indication of sign or base) to the field + // width, except when applied to an infinity or NaN. + // Obviously it makes no sense, but should it be allowed or is it a format + // error? + test({.alignment = _Flags::_Alignment::__default, .zero_padding = true}, 1, CSTR("0}")); + test({.alignment = _Flags::_Alignment::__left, .zero_padding = false}, 2, CSTR("<0}")); + test({.alignment = _Flags::_Alignment::__center, .zero_padding = false}, 2, CSTR("^0}")); + test({.alignment = _Flags::_Alignment::__right, .zero_padding = false}, 2, CSTR(">0}")); + + // *** Width *** + test({.width = 0, .width_as_arg = false}, 0, CSTR("}")); + test({.width = 1, .width_as_arg = false}, 1, CSTR("1}")); + test({.width = 10, .width_as_arg = false}, 2, CSTR("10}")); + test({.width = 1000, .width_as_arg = false}, 4, CSTR("1000}")); + test({.width = 1000000, .width_as_arg = false}, 7, CSTR("1000000}")); + + test({.width = 0, .width_as_arg = true}, 2, CSTR("{}}")); + test({.width = 0, .width_as_arg = true}, 3, CSTR("{0}}")); + test({.width = 1, .width_as_arg = true}, 3, CSTR("{1}}")); + + test_exception>("A format-spec width field shouldn't have a leading zero", CSTR("00")); + + static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test."); + test({.width = 2'147'483'647, .width_as_arg = false}, 10, CSTR("2147483647}")); + test_exception>("The numeric value of the format-spec is too large", CSTR("2147483648")); + test_exception>("The numeric value of the format-spec is too large", CSTR("5000000000")); + test_exception>("The numeric value of the format-spec is too large", CSTR("10000000000")); + + test_exception>("End of input while parsing format-spec arg-id", CSTR("{")); + test_exception>("Invalid arg-id", CSTR("{0")); + test_exception>("The arg-id of the format-spec starts with an invalid character", CSTR("{a")); + test_exception>("Invalid arg-id", CSTR("{1")); + test_exception>("Invalid arg-id", CSTR("{9")); + test_exception>("Invalid arg-id", CSTR("{9:")); + test_exception>("Invalid arg-id", CSTR("{9a")); + static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test."); + // Note the static_assert tests whether the arg-id is valid. + // Therefore the following should be true arg-id < __format::__number_max. + test({.width = 2'147'483'646, .width_as_arg = true}, 12, CSTR("{2147483646}}")); + test_exception>("The numeric value of the format-spec is too large", CSTR("{2147483648}")); + test_exception>("The numeric value of the format-spec is too large", CSTR("{5000000000}")); + test_exception>("The numeric value of the format-spec is too large", CSTR("{10000000000}")); + + // *** Precision *** + test({.precision = 0, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 2, CSTR(".0}")); + test({.precision = 1, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 2, CSTR(".1}")); + test({.precision = 10, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 3, CSTR(".10}")); + test({.precision = 1000, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 5, CSTR(".1000}")); + test({.precision = 1000000, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 8, + CSTR(".1000000}")); + + test({.precision = 0, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 3, CSTR(".{}}")); + test({.precision = 0, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 4, CSTR(".{0}}")); + test({.precision = 1, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 4, CSTR(".{1}}")); + + test_exception>("The format-spec precision field doesn't contain a value or arg-id", CSTR(".a")); + test_exception>("The format-spec precision field doesn't contain a value or arg-id", CSTR(".:")); + + static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test."); + test({.precision = 2'147'483'647, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 11, + CSTR(".2147483647}")); + test_exception>("The numeric value of the format-spec is too large", CSTR(".2147483648")); + test_exception>("The numeric value of the format-spec is too large", CSTR(".5000000000")); + test_exception>("The numeric value of the format-spec is too large", CSTR(".10000000000")); + + test_exception>("End of input while parsing format-spec arg-id", CSTR(".{")); + test_exception>("Invalid arg-id", CSTR(".{0")); + test_exception>("The arg-id of the format-spec starts with an invalid character", CSTR(".{a")); + test_exception>("Invalid arg-id", CSTR(".{1")); + test_exception>("Invalid arg-id", CSTR(".{9")); + test_exception>("Invalid arg-id", CSTR(".{9:")); + test_exception>("Invalid arg-id", CSTR(".{9a")); + + static_assert(std::__format::__number_max == 2'147'483'647, "Update the assert and the test."); + // Note the static_assert tests whether the arg-id is valid. + // Therefore the following should be true arg-id < __format::__number_max. + test({.precision = 2'147'483'646, .precision_as_arg = true, .type = _Flags::_Type::__general_lower_case}, 13, + CSTR(".{2147483646}}")); + test_exception>("The numeric value of the format-spec is too large", CSTR(".{2147483648}")); + test_exception>("The numeric value of the format-spec is too large", CSTR(".{5000000000}")); + test_exception>("The numeric value of the format-spec is too large", CSTR(".{10000000000}")); + + // *** Width & Precision *** + test({.width = 1, + .width_as_arg = false, + .precision = 0, + .precision_as_arg = false, + .type = _Flags::_Type::__general_lower_case}, + 3, CSTR("1.0}")); + test({.width = 0, + .width_as_arg = true, + .precision = 1, + .precision_as_arg = true, + .type = _Flags::_Type::__general_lower_case}, + 5, CSTR("{}.{}}")); + test({.width = 10, + .width_as_arg = true, + .precision = 9, + .precision_as_arg = true, + .type = _Flags::_Type::__general_lower_case}, + 8, CSTR("{10}.{9}}")); + + // *** Locale-specific form *** + test({.locale_specific_form = true}, 1, CSTR("L}")); + + // *** Type *** + { + const char* unsuported_type = "The format-spec type has a type not supported for a floating-point argument"; + const char* not_a_type = "The format-spec should consume the input or end with a '}'"; + + test({.type = _Flags::_Type::__float_hexadecimal_upper_case}, 1, CSTR("A}")); + test_exception>(unsuported_type, CSTR("B}")); + test_exception>(not_a_type, CSTR("C}")); + test_exception>(not_a_type, CSTR("D}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_upper_case}, 1, CSTR("E}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_upper_case}, 1, CSTR("F}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_upper_case}, 1, CSTR("G}")); + test_exception>(not_a_type, CSTR("H}")); + test_exception>(not_a_type, CSTR("I}")); + test_exception>(not_a_type, CSTR("J}")); + test_exception>(not_a_type, CSTR("K}")); + test({.locale_specific_form = true}, 1, CSTR("L}")); + test_exception>(not_a_type, CSTR("M}")); + test_exception>(not_a_type, CSTR("N}")); + test_exception>(not_a_type, CSTR("O}")); + test_exception>(not_a_type, CSTR("P}")); + test_exception>(not_a_type, CSTR("Q}")); + test_exception>(not_a_type, CSTR("R}")); + test_exception>(not_a_type, CSTR("S}")); + test_exception>(not_a_type, CSTR("T}")); + test_exception>(not_a_type, CSTR("U}")); + test_exception>(not_a_type, CSTR("V}")); + test_exception>(not_a_type, CSTR("W}")); + test_exception>(unsuported_type, CSTR("X}")); + test_exception>(not_a_type, CSTR("Y}")); + test_exception>(not_a_type, CSTR("Z}")); + + test({.type = _Flags::_Type::__float_hexadecimal_lower_case}, 1, CSTR("a}")); + test_exception>(unsuported_type, CSTR("b}")); + test_exception>(unsuported_type, CSTR("c}")); + test_exception>(unsuported_type, CSTR("d}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__scientific_lower_case}, 1, CSTR("e}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__fixed_lower_case}, 1, CSTR("f}")); + test({.precision = 6, .precision_as_arg = false, .type = _Flags::_Type::__general_lower_case}, 1, CSTR("g}")); + test_exception>(not_a_type, CSTR("h}")); + test_exception>(not_a_type, CSTR("i}")); + test_exception>(not_a_type, CSTR("j}")); + test_exception>(not_a_type, CSTR("k}")); + test_exception>(not_a_type, CSTR("l}")); + test_exception>(not_a_type, CSTR("m}")); + test_exception>(not_a_type, CSTR("n}")); + test_exception>(unsuported_type, CSTR("o}")); + test_exception>(unsuported_type, CSTR("p}")); + test_exception>(not_a_type, CSTR("q}")); + test_exception>(not_a_type, CSTR("r}")); + test_exception>(unsuported_type, CSTR("s}")); + test_exception>(not_a_type, CSTR("t}")); + test_exception>(not_a_type, CSTR("u}")); + test_exception>(not_a_type, CSTR("v}")); + test_exception>(not_a_type, CSTR("w}")); + test_exception>(unsuported_type, CSTR("x}")); + test_exception>(not_a_type, CSTR("y}")); + test_exception>(not_a_type, CSTR("z}")); + } + // **** General *** + test_exception>("The format-spec should consume the input or end with a '}'", CSTR("ss")); +} + +constexpr bool test() { + test(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test(); +#endif + + return true; +} + +int main(int, char**) { +#if !defined(_WIN32) && !defined(_AIX) + // Make sure the parsers match the expectations. The layout of the + // subobjects is chosen to minimize the size required. + static_assert(sizeof(Parser) == 3 * sizeof(uint32_t)); +# ifndef TEST_HAS_NO_WIDE_CHARACTERS + static_assert(sizeof(Parser) == (sizeof(wchar_t) <= 2 ? 3 * sizeof(uint32_t) : 4 * sizeof(uint32_t))); +# endif +#endif + + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp --- a/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp +++ b/libcxx/test/std/utilities/format/format.formatter/format.context/format.formatter.spec/formatter.floating_point.pass.cpp @@ -8,7 +8,6 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17 // UNSUPPORTED: libcpp-no-concepts // UNSUPPORTED: libcpp-has-no-incomplete-format -// UNSUPPORTED: LIBCXX-DEBUG-FIXME // @@ -25,11 +24,14 @@ // - double // - long double -// TODO FMT Enable after floating-point support has been enabled -#if 0 #include + +#include #include +#include +#include #include +#include #include #include "test_macros.h" @@ -37,9 +39,8 @@ #define STR(S) MAKE_STRING(CharT, S) -template -void test(StringViewT fmt, ArithmeticT arg) { - using CharT = typename StringViewT::value_type; +template +void test(std::basic_string_view fmt, ArithmeticT arg, std::basic_string expected) { auto parse_ctx = std::basic_format_parse_context(fmt); std::formatter formatter; static_assert(std::semiregular); @@ -51,15 +52,19 @@ auto out = std::back_inserter(result); using FormatCtxT = std::basic_format_context; - auto format_ctx = std::__format_context_create( - out, std::make_format_args(arg)); + auto format_ctx = std::__format_context_create(out, std::make_format_args(arg)); formatter.format(arg, format_ctx); - std::string expected = std::to_string(arg); - assert(result == std::basic_string(expected.begin(), expected.end())); + + if (expected.empty()) { + std::array buffer; + expected.append(buffer.begin(), std::to_chars(buffer.begin(), buffer.end(), arg).ptr); + } + + assert(result == expected); } template -void test_termination_condition(StringT f, ArithmeticT arg) { +void test_termination_condition(StringT f, ArithmeticT arg, StringT expected = {}) { // The format-spec is valid if completely consumed or terminates at a '}'. // The valid inputs all end with a '}'. The test is executed twice: // - first with the terminating '}', @@ -68,40 +73,398 @@ std::basic_string_view fmt{f}; assert(fmt.back() == CharT('}') && "Pre-condition failure"); - test(fmt, arg); + test(fmt, arg, expected); fmt.remove_suffix(1); - test(fmt, arg); + test(fmt, arg, expected); +} + +template +void test_hex_lower_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr; + test_termination_condition(STR(".20000a}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000a}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000a}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000a}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000a}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr; + test_termination_condition(STR(".20000La}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000La}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000La}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000La}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000La}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_hex_upper_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000A}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000A}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000A}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000A}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000A}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::hex, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000LA}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000LA}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000LA}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000LA}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000LA}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_scientific_lower_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr; + test_termination_condition(STR(".20000e}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000e}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000e}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000e}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000e}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr; + test_termination_condition(STR(".20000Le}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000Le}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000Le}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000Le}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000Le}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_scientific_upper_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000E}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000E}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000E}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000E}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000E}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::scientific, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000LE}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000LE}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000LE}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000LE}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000LE}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_fixed_lower_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr; + test_termination_condition(STR(".20000f}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000f}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000f}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000f}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000f}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr; + test_termination_condition(STR(".20000Lf}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000Lf}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000Lf}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000Lf}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000Lf}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_fixed_upper_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000F}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000F}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000F}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000F}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000F}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::fixed, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000LF}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000LF}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000LF}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000LF}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000LF}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_general_lower_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr; + test_termination_condition(STR(".20000g}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000g}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000g}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000g}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000g}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr; + test_termination_condition(STR(".20000Lg}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000Lg}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000Lg}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000Lg}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000Lg}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_general_upper_case_precision(ArithmeticT value) { + std::array buffer; + char* end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000G}"), value, std::basic_string{buffer.begin(), end}); + + size_t size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000G}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000G}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000G}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000G}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#ifndef _LIBCPP_HAS_NO_LOCALIZATION + end = std::to_chars(buffer.begin(), buffer.end(), value, std::chars_format::general, 20'000).ptr; + std::transform(buffer.begin(), end, buffer.begin(), [](char c) { return std::toupper(c); }); + test_termination_condition(STR(".20000LG}"), value, std::basic_string{buffer.begin(), end}); + + size = buffer.end() - end; + std::fill_n(end, size, '#'); + test_termination_condition(STR("#<25000.20000LG}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - (size / 2), buffer.end()); + test_termination_condition(STR("#^25000.20000LG}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::rotate(buffer.begin(), buffer.end() - ((size + 1) / 2), buffer.end()); + test_termination_condition(STR("#>25000.20000LG}"), value, std::basic_string{buffer.begin(), buffer.end()}); + std::fill_n(buffer.begin(), size, '0'); + if (std::signbit(value)) { + buffer[0] = '-'; + buffer[size] = '0'; + } + test_termination_condition(STR("025000.20000LG}"), value, std::basic_string{buffer.begin(), buffer.end()}); +#endif +} + +template +void test_value(ArithmeticT value) { + test_hex_lower_case_precision(value); + test_hex_upper_case_precision(value); + + test_scientific_lower_case_precision(value); + test_scientific_upper_case_precision(value); + + test_fixed_lower_case_precision(value); + test_fixed_upper_case_precision(value); + + test_general_lower_case_precision(value); + test_general_upper_case_precision(value); +} + +template +void test_special_values() { + using A = ArithmeticT; + + test_value(-std::numeric_limits::max()); + test_value(A(-1.0)); + test_value(-std::numeric_limits::min()); + test_value(-std::numeric_limits::denorm_min()); + test_value(A(-0.0)); + + test_value(A(0.0)); + test_value(std::numeric_limits::denorm_min()); + test_value(A(1.0)); + test_value(std::numeric_limits::min()); + test_value(std::numeric_limits::max()); } template void test_float_type() { using A = ArithmeticT; + test_termination_condition(STR("}"), A(-std::numeric_limits::max())); test_termination_condition(STR("}"), A(-std::numeric_limits::min())); test_termination_condition(STR("}"), A(-0.0)); + test_termination_condition(STR("}"), A(0.0)); test_termination_condition(STR("}"), A(std::numeric_limits::min())); test_termination_condition(STR("}"), A(std::numeric_limits::max())); if (sizeof(A) > sizeof(float)) { - test_termination_condition(STR("}"), - A(-std::numeric_limits::max())); - test_termination_condition(STR("}"), - A(-std::numeric_limits::min())); + test_termination_condition(STR("}"), A(-std::numeric_limits::max())); + test_termination_condition(STR("}"), A(-std::numeric_limits::min())); test_termination_condition(STR("}"), A(std::numeric_limits::min())); test_termination_condition(STR("}"), A(std::numeric_limits::max())); } if (sizeof(A) > sizeof(double)) { - test_termination_condition(STR("}"), - A(-std::numeric_limits::max())); - test_termination_condition(STR("}"), - A(-std::numeric_limits::min())); - test_termination_condition(STR("}"), - A(std::numeric_limits::min())); - test_termination_condition(STR("}"), - A(std::numeric_limits::max())); + test_termination_condition(STR("}"), A(-std::numeric_limits::max())); + test_termination_condition(STR("}"), A(-std::numeric_limits::min())); + test_termination_condition(STR("}"), A(std::numeric_limits::min())); + test_termination_condition(STR("}"), A(std::numeric_limits::max())); } - // TODO FMT Also test with special floating point values: +/-Inf NaN. + // The results of inf and nan may differ from the result of to_chars. + test_termination_condition(STR("}"), A(-std::numeric_limits::infinity()), STR("-inf")); + test_termination_condition(STR("}"), A(std::numeric_limits::infinity()), STR("inf")); + + A nan = std::numeric_limits::quiet_NaN(); + test_termination_condition(STR("}"), std::copysign(nan, -1.0), STR("-nan")); + test_termination_condition(STR("}"), nan, STR("nan")); + + // TODO FMT Enable long double testing + if constexpr (!std::same_as) + test_special_values(); } template @@ -119,6 +482,3 @@ return 0; } -#else -int main(int, char**) { return 0; } -#endif diff --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h --- a/libcxx/test/std/utilities/format/format.functions/format_tests.h +++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h @@ -13,6 +13,8 @@ #include "make_string.h" #include "test_macros.h" +#include + // In this file the following template types are used: // TestFunction must be callable as check(expected-result, string-to-format, args-to-format...) // ExceptionTest must be callable as check_exception(expected-exception, string-to-format, args-to-format...) @@ -992,6 +994,1496 @@ fmt, '*'); } +template +void format_test_floating_point_hex_lower_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // Test whether the hexadecimal letters are the proper case. + // The precision is too large for float, so two tests are used. + check(STR("answer is '1.abcp+0'"), STR("answer is '{:a}'"), F(0x1.abcp+0)); + check(STR("answer is '1.defp+0'"), STR("answer is '{:a}'"), F(0x1.defp+0)); + + // *** align-fill & width *** + check(STR("answer is ' 1p-2'"), STR("answer is '{:7a}'"), F(0.25)); + check(STR("answer is ' 1p-2'"), STR("answer is '{:>7a}'"), F(0.25)); + check(STR("answer is '1p-2 '"), STR("answer is '{:<7a}'"), F(0.25)); + check(STR("answer is ' 1p-2 '"), STR("answer is '{:^7a}'"), F(0.25)); + + check(STR("answer is '---1p-3'"), STR("answer is '{:->7a}'"), F(125e-3)); + check(STR("answer is '1p-3---'"), STR("answer is '{:-<7a}'"), F(125e-3)); + check(STR("answer is '-1p-3--'"), STR("answer is '{:-^7a}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6a}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6a}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6a}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6a}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6a}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6a}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7a}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7a}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7a}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 1p-2'"), STR("answer is '{:>07a}'"), F(0.25)); + check(STR("answer is '1p-2 '"), STR("answer is '{:<07a}'"), F(0.25)); + check(STR("answer is ' 1p-2 '"), STR("answer is '{:^07a}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0p+0'"), STR("answer is '{:a}'"), F(0)); + check(STR("answer is '0p+0'"), STR("answer is '{:-a}'"), F(0)); + check(STR("answer is '+0p+0'"), STR("answer is '{:+a}'"), F(0)); + check(STR("answer is ' 0p+0'"), STR("answer is '{: a}'"), F(0)); + + check(STR("answer is '-0p+0'"), STR("answer is '{:a}'"), F(-0.)); + check(STR("answer is '-0p+0'"), STR("answer is '{:-a}'"), F(-0.)); + check(STR("answer is '-0p+0'"), STR("answer is '{:+a}'"), F(-0.)); + check(STR("answer is '-0p+0'"), STR("answer is '{: a}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:a}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-a}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: a}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:a}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-a}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+a}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: a}'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:a}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-a}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+a}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: a}'"), nan_neg); + + // *** alternate form *** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0p+0'"), STR("answer is '{:a}'"), F(0)); + check(STR("answer is '0.p+0'"), STR("answer is '{:#a}'"), F(0)); + + check(STR("answer is '1p+1'"), STR("answer is '{:.0a}'"), F(2.5)); + check(STR("answer is '1.p+1'"), STR("answer is '{:#.0a}'"), F(2.5)); + check(STR("answer is '1.4p+1'"), STR("answer is '{:#a}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#a}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#a}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#a}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '1p-5'"), STR("answer is '{:04a}'"), 0.03125); + check(STR("answer is '+1p-5'"), STR("answer is '{:+05a}'"), 0.03125); + check(STR("answer is '+01p-5'"), STR("answer is '{:+06a}'"), 0.03125); + + check(STR("answer is '0001p-5'"), STR("answer is '{:07a}'"), 0.03125); + check(STR("answer is '0001p-5'"), STR("answer is '{:-07a}'"), 0.03125); + check(STR("answer is '+001p-5'"), STR("answer is '{:+07a}'"), 0.03125); + check(STR("answer is ' 001p-5'"), STR("answer is '{: 07a}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010a}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010a}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010a}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010a}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010a}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010a}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010a}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010a}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010a}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010a}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010a}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010a}'"), nan_neg); + + // *** precision *** + // See format_test_floating_point_hex_lower_case_precision + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_hex_upper_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // Test whether the hexadecimal letters are the proper case. + // The precision is too large for float, so two tests are used. + check(STR("answer is '1.ABCP+0'"), STR("answer is '{:A}'"), F(0x1.abcp+0)); + check(STR("answer is '1.DEFP+0'"), STR("answer is '{:A}'"), F(0x1.defp+0)); + + // *** align-fill & width *** + check(STR("answer is ' 1P-2'"), STR("answer is '{:7A}'"), F(0.25)); + check(STR("answer is ' 1P-2'"), STR("answer is '{:>7A}'"), F(0.25)); + check(STR("answer is '1P-2 '"), STR("answer is '{:<7A}'"), F(0.25)); + check(STR("answer is ' 1P-2 '"), STR("answer is '{:^7A}'"), F(0.25)); + + check(STR("answer is '---1P-3'"), STR("answer is '{:->7A}'"), F(125e-3)); + check(STR("answer is '1P-3---'"), STR("answer is '{:-<7A}'"), F(125e-3)); + check(STR("answer is '-1P-3--'"), STR("answer is '{:-^7A}'"), F(125e-3)); + + check(STR("answer is '***INF'"), STR("answer is '{:*>6A}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF***'"), STR("answer is '{:*<6A}'"), std::numeric_limits::infinity()); + check(STR("answer is '*INF**'"), STR("answer is '{:*^6A}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-INF'"), STR("answer is '{:#>7A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF###'"), STR("answer is '{:#<7A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-INF##'"), STR("answer is '{:#^7A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6A}'"), nan_pos); + check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6A}'"), nan_pos); + check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6A}'"), nan_pos); + + check(STR("answer is '000-NAN'"), STR("answer is '{:0>7A}'"), nan_neg); + check(STR("answer is '-NAN000'"), STR("answer is '{:0<7A}'"), nan_neg); + check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7A}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 1P-2'"), STR("answer is '{:>07A}'"), F(0.25)); + check(STR("answer is '1P-2 '"), STR("answer is '{:<07A}'"), F(0.25)); + check(STR("answer is ' 1P-2 '"), STR("answer is '{:^07A}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0P+0'"), STR("answer is '{:A}'"), F(0)); + check(STR("answer is '0P+0'"), STR("answer is '{:-A}'"), F(0)); + check(STR("answer is '+0P+0'"), STR("answer is '{:+A}'"), F(0)); + check(STR("answer is ' 0P+0'"), STR("answer is '{: A}'"), F(0)); + + check(STR("answer is '-0P+0'"), STR("answer is '{:A}'"), F(-0.)); + check(STR("answer is '-0P+0'"), STR("answer is '{:-A}'"), F(-0.)); + check(STR("answer is '-0P+0'"), STR("answer is '{:+A}'"), F(-0.)); + check(STR("answer is '-0P+0'"), STR("answer is '{: A}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'INF'"), STR("answer is '{:A}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF'"), STR("answer is '{:-A}'"), std::numeric_limits::infinity()); + check(STR("answer is '+INF'"), STR("answer is '{:+A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: A}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-INF'"), STR("answer is '{:A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:-A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:+A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{: A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:A}'"), nan_pos); + check(STR("answer is 'NAN'"), STR("answer is '{:-A}'"), nan_pos); + check(STR("answer is '+NAN'"), STR("answer is '{:+A}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: A}'"), nan_pos); + + check(STR("answer is '-NAN'"), STR("answer is '{:A}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:-A}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:+A}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{: A}'"), nan_neg); + + // *** alternate form *** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0P+0'"), STR("answer is '{:A}'"), F(0)); + check(STR("answer is '0.P+0'"), STR("answer is '{:#A}'"), F(0)); + + check(STR("answer is '1P+1'"), STR("answer is '{:.0A}'"), F(2.5)); + check(STR("answer is '1.P+1'"), STR("answer is '{:#.0A}'"), F(2.5)); + check(STR("answer is '1.4P+1'"), STR("answer is '{:#A}'"), F(2.5)); + + check(STR("answer is 'INF'"), STR("answer is '{:#A}'"), std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:#A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:#A}'"), nan_pos); + check(STR("answer is '-NAN'"), STR("answer is '{:#A}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '1P-5'"), STR("answer is '{:04A}'"), 0.03125); + check(STR("answer is '+1P-5'"), STR("answer is '{:+05A}'"), 0.03125); + check(STR("answer is '+01P-5'"), STR("answer is '{:+06A}'"), 0.03125); + + check(STR("answer is '0001P-5'"), STR("answer is '{:07A}'"), 0.03125); + check(STR("answer is '0001P-5'"), STR("answer is '{:-07A}'"), 0.03125); + check(STR("answer is '+001P-5'"), STR("answer is '{:+07A}'"), 0.03125); + check(STR("answer is ' 001P-5'"), STR("answer is '{: 07A}'"), 0.03125); + + check(STR("answer is ' INF'"), STR("answer is '{:010A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{:-010A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +INF'"), STR("answer is '{:+010A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: 010A}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -INF'"), STR("answer is '{:010A}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:-010A}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:+010A}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{: 010A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' NAN'"), STR("answer is '{:010A}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{:-010A}'"), nan_pos); + check(STR("answer is ' +NAN'"), STR("answer is '{:+010A}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: 010A}'"), nan_pos); + + check(STR("answer is ' -NAN'"), STR("answer is '{:010A}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:-010A}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:+010A}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{: 010A}'"), nan_neg); + + // *** precision *** + // See format_test_floating_point_hex_upper_case_precision + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_hex_lower_case_precision(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 1.000000p-2'"), STR("answer is '{:14.6a}'"), F(0.25)); + check(STR("answer is ' 1.000000p-2'"), STR("answer is '{:>14.6a}'"), F(0.25)); + check(STR("answer is '1.000000p-2 '"), STR("answer is '{:<14.6a}'"), F(0.25)); + check(STR("answer is ' 1.000000p-2 '"), STR("answer is '{:^14.6a}'"), F(0.25)); + + check(STR("answer is '---1.000000p-3'"), STR("answer is '{:->14.6a}'"), F(125e-3)); + check(STR("answer is '1.000000p-3---'"), STR("answer is '{:-<14.6a}'"), F(125e-3)); + check(STR("answer is '-1.000000p-3--'"), STR("answer is '{:-^14.6a}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6.6a}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7.6a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6.6a}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6.6a}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6.6a}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7.6a}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7.6a}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7.6a}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 1.000000p-2'"), STR("answer is '{:>014.6a}'"), F(0.25)); + check(STR("answer is '1.000000p-2 '"), STR("answer is '{:<014.6a}'"), F(0.25)); + check(STR("answer is ' 1.000000p-2 '"), STR("answer is '{:^014.6a}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0.000000p+0'"), STR("answer is '{:.6a}'"), F(0)); + check(STR("answer is '0.000000p+0'"), STR("answer is '{:-.6a}'"), F(0)); + check(STR("answer is '+0.000000p+0'"), STR("answer is '{:+.6a}'"), F(0)); + check(STR("answer is ' 0.000000p+0'"), STR("answer is '{: .6a}'"), F(0)); + + check(STR("answer is '-0.000000p+0'"), STR("answer is '{:.6a}'"), F(-0.)); + check(STR("answer is '-0.000000p+0'"), STR("answer is '{:-.6a}'"), F(-0.)); + check(STR("answer is '-0.000000p+0'"), STR("answer is '{:+.6a}'"), F(-0.)); + check(STR("answer is '-0.000000p+0'"), STR("answer is '{: .6a}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: .6a}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: .6a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:.6a}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-.6a}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+.6a}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: .6a}'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:.6a}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-.6a}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+.6a}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: .6a}'"), nan_neg); + + // *** alternate form *** + check(STR("answer is '1.400000p+1'"), STR("answer is '{:#.6a}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#.6a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#.6a}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#.6a}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '1.000000p-5'"), STR("answer is '{:011.6a}'"), 0.03125); + check(STR("answer is '+1.000000p-5'"), STR("answer is '{:+012.6a}'"), 0.03125); + check(STR("answer is '+01.000000p-5'"), STR("answer is '{:+013.6a}'"), 0.03125); + + check(STR("answer is '0001.000000p-5'"), STR("answer is '{:014.6a}'"), 0.03125); + check(STR("answer is '0001.000000p-5'"), STR("answer is '{:-014.6a}'"), 0.03125); + check(STR("answer is '+001.000000p-5'"), STR("answer is '{:+014.6a}'"), 0.03125); + check(STR("answer is ' 001.000000p-5'"), STR("answer is '{: 014.6a}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010.6a}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010.6a}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010.6a}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010.6a}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010.6a}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010.6a}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010.6a}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010.6a}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010.6a}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010.6a}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010.6a}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010.6a}'"), nan_neg); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_hex_upper_case_precision(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 1.000000P-2'"), STR("answer is '{:14.6A}'"), F(0.25)); + check(STR("answer is ' 1.000000P-2'"), STR("answer is '{:>14.6A}'"), F(0.25)); + check(STR("answer is '1.000000P-2 '"), STR("answer is '{:<14.6A}'"), F(0.25)); + check(STR("answer is ' 1.000000P-2 '"), STR("answer is '{:^14.6A}'"), F(0.25)); + + check(STR("answer is '---1.000000P-3'"), STR("answer is '{:->14.6A}'"), F(125e-3)); + check(STR("answer is '1.000000P-3---'"), STR("answer is '{:-<14.6A}'"), F(125e-3)); + check(STR("answer is '-1.000000P-3--'"), STR("answer is '{:-^14.6A}'"), F(125e-3)); + + check(STR("answer is '***INF'"), STR("answer is '{:*>6.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF***'"), STR("answer is '{:*<6.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is '*INF**'"), STR("answer is '{:*^6.6A}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-INF'"), STR("answer is '{:#>7.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF###'"), STR("answer is '{:#<7.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-INF##'"), STR("answer is '{:#^7.6A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6.6A}'"), nan_pos); + check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6.6A}'"), nan_pos); + check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6.6A}'"), nan_pos); + + check(STR("answer is '000-NAN'"), STR("answer is '{:0>7.6A}'"), nan_neg); + check(STR("answer is '-NAN000'"), STR("answer is '{:0<7.6A}'"), nan_neg); + check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7.6A}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 1.000000P-2'"), STR("answer is '{:>014.6A}'"), F(0.25)); + check(STR("answer is '1.000000P-2 '"), STR("answer is '{:<014.6A}'"), F(0.25)); + check(STR("answer is ' 1.000000P-2 '"), STR("answer is '{:^014.6A}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0.000000P+0'"), STR("answer is '{:.6A}'"), F(0)); + check(STR("answer is '0.000000P+0'"), STR("answer is '{:-.6A}'"), F(0)); + check(STR("answer is '+0.000000P+0'"), STR("answer is '{:+.6A}'"), F(0)); + check(STR("answer is ' 0.000000P+0'"), STR("answer is '{: .6A}'"), F(0)); + + check(STR("answer is '-0.000000P+0'"), STR("answer is '{:.6A}'"), F(-0.)); + check(STR("answer is '-0.000000P+0'"), STR("answer is '{:-.6A}'"), F(-0.)); + check(STR("answer is '-0.000000P+0'"), STR("answer is '{:+.6A}'"), F(-0.)); + check(STR("answer is '-0.000000P+0'"), STR("answer is '{: .6A}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'INF'"), STR("answer is '{:.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF'"), STR("answer is '{:-.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is '+INF'"), STR("answer is '{:+.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: .6A}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-INF'"), STR("answer is '{:.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:-.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:+.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{: .6A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:.6A}'"), nan_pos); + check(STR("answer is 'NAN'"), STR("answer is '{:-.6A}'"), nan_pos); + check(STR("answer is '+NAN'"), STR("answer is '{:+.6A}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: .6A}'"), nan_pos); + + check(STR("answer is '-NAN'"), STR("answer is '{:.6A}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:-.6A}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:+.6A}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{: .6A}'"), nan_neg); + + // *** alternate form *** + check(STR("answer is '1.400000P+1'"), STR("answer is '{:#.6A}'"), F(2.5)); + + check(STR("answer is 'INF'"), STR("answer is '{:#.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:#.6A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:#.6A}'"), nan_pos); + check(STR("answer is '-NAN'"), STR("answer is '{:#.6A}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '1.000000P-5'"), STR("answer is '{:011.6A}'"), 0.03125); + check(STR("answer is '+1.000000P-5'"), STR("answer is '{:+012.6A}'"), 0.03125); + check(STR("answer is '+01.000000P-5'"), STR("answer is '{:+013.6A}'"), 0.03125); + + check(STR("answer is '0001.000000P-5'"), STR("answer is '{:014.6A}'"), 0.03125); + check(STR("answer is '0001.000000P-5'"), STR("answer is '{:-014.6A}'"), 0.03125); + check(STR("answer is '+001.000000P-5'"), STR("answer is '{:+014.6A}'"), 0.03125); + check(STR("answer is ' 001.000000P-5'"), STR("answer is '{: 014.6A}'"), 0.03125); + + check(STR("answer is ' INF'"), STR("answer is '{:010.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{:-010.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +INF'"), STR("answer is '{:+010.6A}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: 010.6A}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -INF'"), STR("answer is '{:010.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:-010.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:+010.6A}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{: 010.6A}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' NAN'"), STR("answer is '{:010.6A}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{:-010.6A}'"), nan_pos); + check(STR("answer is ' +NAN'"), STR("answer is '{:+010.6A}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: 010.6A}'"), nan_pos); + + check(STR("answer is ' -NAN'"), STR("answer is '{:010.6A}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:-010.6A}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:+010.6A}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{: 010.6A}'"), nan_neg); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_scientific_lower_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 2.500000e-01'"), STR("answer is '{:15e}'"), F(0.25)); + check(STR("answer is ' 2.500000e-01'"), STR("answer is '{:>15e}'"), F(0.25)); + check(STR("answer is '2.500000e-01 '"), STR("answer is '{:<15e}'"), F(0.25)); + check(STR("answer is ' 2.500000e-01 '"), STR("answer is '{:^15e}'"), F(0.25)); + + check(STR("answer is '---1.250000e-01'"), STR("answer is '{:->15e}'"), F(125e-3)); + check(STR("answer is '1.250000e-01---'"), STR("answer is '{:-<15e}'"), F(125e-3)); + check(STR("answer is '-1.250000e-01--'"), STR("answer is '{:-^15e}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6e}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6e}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6e}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7e}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7e}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7e}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6e}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6e}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6e}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7e}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7e}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7e}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 2.500000e-01'"), STR("answer is '{:>015e}'"), F(0.25)); + check(STR("answer is '2.500000e-01 '"), STR("answer is '{:<015e}'"), F(0.25)); + check(STR("answer is ' 2.500000e-01 '"), STR("answer is '{:^015e}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0.000000e+00'"), STR("answer is '{:e}'"), F(0)); + check(STR("answer is '0.000000e+00'"), STR("answer is '{:-e}'"), F(0)); + check(STR("answer is '+0.000000e+00'"), STR("answer is '{:+e}'"), F(0)); + check(STR("answer is ' 0.000000e+00'"), STR("answer is '{: e}'"), F(0)); + + check(STR("answer is '-0.000000e+00'"), STR("answer is '{:e}'"), F(-0.)); + check(STR("answer is '-0.000000e+00'"), STR("answer is '{:-e}'"), F(-0.)); + check(STR("answer is '-0.000000e+00'"), STR("answer is '{:+e}'"), F(-0.)); + check(STR("answer is '-0.000000e+00'"), STR("answer is '{: e}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:e}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-e}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+e}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: e}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:e}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-e}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+e}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: e}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:e}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-e}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+e}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: e}'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:e}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-e}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+e}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: e}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0e+00'"), STR("answer is '{:.0e}'"), F(0)); + check(STR("answer is '0.e+00'"), STR("answer is '{:#.0e}'"), F(0)); + + check(STR("answer is '0.000000e+00'"), STR("answer is '{:#e}'"), F(0)); + check(STR("answer is '2.500000e+00'"), STR("answer is '{:#e}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#e}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#e}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#e}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#e}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '3.125000e-02'"), STR("answer is '{:07e}'"), 0.03125); + check(STR("answer is '+3.125000e-02'"), STR("answer is '{:+07e}'"), 0.03125); + check(STR("answer is '+3.125000e-02'"), STR("answer is '{:+08e}'"), 0.03125); + check(STR("answer is '+3.125000e-02'"), STR("answer is '{:+09e}'"), 0.03125); + + check(STR("answer is '003.125000e-02'"), STR("answer is '{:014e}'"), 0.03125); + check(STR("answer is '003.125000e-02'"), STR("answer is '{:-014e}'"), 0.03125); + check(STR("answer is '+03.125000e-02'"), STR("answer is '{:+014e}'"), 0.03125); + check(STR("answer is ' 03.125000e-02'"), STR("answer is '{: 014e}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010e}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010e}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010e}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010e}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010e}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010e}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010e}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010e}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010e}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010e}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010e}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010e}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010e}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010e}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010e}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010e}'"), nan_neg); + + // *** precision *** + check(STR("answer is '3e-02'"), STR("answer is '{:.0e}'"), 0.03125); + check(STR("answer is '3.1e-02'"), STR("answer is '{:.1e}'"), 0.03125); + check(STR("answer is '3.125e-02'"), STR("answer is '{:.3e}'"), 0.03125); + check(STR("answer is '3.1250000000e-02'"), STR("answer is '{:.10e}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_scientific_upper_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 2.500000E-01'"), STR("answer is '{:15E}'"), F(0.25)); + check(STR("answer is ' 2.500000E-01'"), STR("answer is '{:>15E}'"), F(0.25)); + check(STR("answer is '2.500000E-01 '"), STR("answer is '{:<15E}'"), F(0.25)); + check(STR("answer is ' 2.500000E-01 '"), STR("answer is '{:^15E}'"), F(0.25)); + + check(STR("answer is '---1.250000E-01'"), STR("answer is '{:->15E}'"), F(125e-3)); + check(STR("answer is '1.250000E-01---'"), STR("answer is '{:-<15E}'"), F(125e-3)); + check(STR("answer is '-1.250000E-01--'"), STR("answer is '{:-^15E}'"), F(125e-3)); + + check(STR("answer is '***INF'"), STR("answer is '{:*>6E}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF***'"), STR("answer is '{:*<6E}'"), std::numeric_limits::infinity()); + check(STR("answer is '*INF**'"), STR("answer is '{:*^6E}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-INF'"), STR("answer is '{:#>7E}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF###'"), STR("answer is '{:#<7E}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-INF##'"), STR("answer is '{:#^7E}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6E}'"), nan_pos); + check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6E}'"), nan_pos); + check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6E}'"), nan_pos); + + check(STR("answer is '000-NAN'"), STR("answer is '{:0>7E}'"), nan_neg); + check(STR("answer is '-NAN000'"), STR("answer is '{:0<7E}'"), nan_neg); + check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7E}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 2.500000E-01'"), STR("answer is '{:>015E}'"), F(0.25)); + check(STR("answer is '2.500000E-01 '"), STR("answer is '{:<015E}'"), F(0.25)); + check(STR("answer is ' 2.500000E-01 '"), STR("answer is '{:^015E}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0.000000E+00'"), STR("answer is '{:E}'"), F(0)); + check(STR("answer is '0.000000E+00'"), STR("answer is '{:-E}'"), F(0)); + check(STR("answer is '+0.000000E+00'"), STR("answer is '{:+E}'"), F(0)); + check(STR("answer is ' 0.000000E+00'"), STR("answer is '{: E}'"), F(0)); + + check(STR("answer is '-0.000000E+00'"), STR("answer is '{:E}'"), F(-0.)); + check(STR("answer is '-0.000000E+00'"), STR("answer is '{:-E}'"), F(-0.)); + check(STR("answer is '-0.000000E+00'"), STR("answer is '{:+E}'"), F(-0.)); + check(STR("answer is '-0.000000E+00'"), STR("answer is '{: E}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'INF'"), STR("answer is '{:E}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF'"), STR("answer is '{:-E}'"), std::numeric_limits::infinity()); + check(STR("answer is '+INF'"), STR("answer is '{:+E}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: E}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-INF'"), STR("answer is '{:E}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:-E}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:+E}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{: E}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:E}'"), nan_pos); + check(STR("answer is 'NAN'"), STR("answer is '{:-E}'"), nan_pos); + check(STR("answer is '+NAN'"), STR("answer is '{:+E}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: E}'"), nan_pos); + + check(STR("answer is '-NAN'"), STR("answer is '{:E}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:-E}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:+E}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{: E}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0E+00'"), STR("answer is '{:.0E}'"), F(0)); + check(STR("answer is '0.E+00'"), STR("answer is '{:#.0E}'"), F(0)); + + check(STR("answer is '0.000000E+00'"), STR("answer is '{:#E}'"), F(0)); + check(STR("answer is '2.500000E+00'"), STR("answer is '{:#E}'"), F(2.5)); + + check(STR("answer is 'INF'"), STR("answer is '{:#E}'"), std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:#E}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:#E}'"), nan_pos); + check(STR("answer is '-NAN'"), STR("answer is '{:#E}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '3.125000E-02'"), STR("answer is '{:07E}'"), 0.03125); + check(STR("answer is '+3.125000E-02'"), STR("answer is '{:+07E}'"), 0.03125); + check(STR("answer is '+3.125000E-02'"), STR("answer is '{:+08E}'"), 0.03125); + check(STR("answer is '+3.125000E-02'"), STR("answer is '{:+09E}'"), 0.03125); + + check(STR("answer is '003.125000E-02'"), STR("answer is '{:014E}'"), 0.03125); + check(STR("answer is '003.125000E-02'"), STR("answer is '{:-014E}'"), 0.03125); + check(STR("answer is '+03.125000E-02'"), STR("answer is '{:+014E}'"), 0.03125); + check(STR("answer is ' 03.125000E-02'"), STR("answer is '{: 014E}'"), 0.03125); + + check(STR("answer is ' INF'"), STR("answer is '{:010E}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{:-010E}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +INF'"), STR("answer is '{:+010E}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: 010E}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -INF'"), STR("answer is '{:010E}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:-010E}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:+010E}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{: 010E}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' NAN'"), STR("answer is '{:010E}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{:-010E}'"), nan_pos); + check(STR("answer is ' +NAN'"), STR("answer is '{:+010E}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: 010E}'"), nan_pos); + + check(STR("answer is ' -NAN'"), STR("answer is '{:010E}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:-010E}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:+010E}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{: 010E}'"), nan_neg); + + // *** precision *** + check(STR("answer is '3E-02'"), STR("answer is '{:.0E}'"), 0.03125); + check(STR("answer is '3.1E-02'"), STR("answer is '{:.1E}'"), 0.03125); + check(STR("answer is '3.125E-02'"), STR("answer is '{:.3E}'"), 0.03125); + check(STR("answer is '3.1250000000E-02'"), STR("answer is '{:.10E}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_fixed_lower_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 0.250000'"), STR("answer is '{:11f}'"), F(0.25)); + check(STR("answer is ' 0.250000'"), STR("answer is '{:>11f}'"), F(0.25)); + check(STR("answer is '0.250000 '"), STR("answer is '{:<11f}'"), F(0.25)); + check(STR("answer is ' 0.250000 '"), STR("answer is '{:^11f}'"), F(0.25)); + + check(STR("answer is '---0.125000'"), STR("answer is '{:->11f}'"), F(125e-3)); + check(STR("answer is '0.125000---'"), STR("answer is '{:-<11f}'"), F(125e-3)); + check(STR("answer is '-0.125000--'"), STR("answer is '{:-^11f}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6f}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6f}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6f}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7f}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7f}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7f}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6f}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6f}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6f}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7f}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7f}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7f}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 0.250000'"), STR("answer is '{:>011f}'"), F(0.25)); + check(STR("answer is '0.250000 '"), STR("answer is '{:<011f}'"), F(0.25)); + check(STR("answer is ' 0.250000 '"), STR("answer is '{:^011f}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0.000000'"), STR("answer is '{:f}'"), F(0)); + check(STR("answer is '0.000000'"), STR("answer is '{:-f}'"), F(0)); + check(STR("answer is '+0.000000'"), STR("answer is '{:+f}'"), F(0)); + check(STR("answer is ' 0.000000'"), STR("answer is '{: f}'"), F(0)); + + check(STR("answer is '-0.000000'"), STR("answer is '{:f}'"), F(-0.)); + check(STR("answer is '-0.000000'"), STR("answer is '{:-f}'"), F(-0.)); + check(STR("answer is '-0.000000'"), STR("answer is '{:+f}'"), F(-0.)); + check(STR("answer is '-0.000000'"), STR("answer is '{: f}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:f}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-f}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+f}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: f}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:f}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-f}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+f}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: f}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:f}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-f}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+f}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: f}'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:f}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-f}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+f}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: f}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0'"), STR("answer is '{:.0f}'"), F(0)); + check(STR("answer is '0.'"), STR("answer is '{:#.0f}'"), F(0)); + + check(STR("answer is '0.000000'"), STR("answer is '{:#f}'"), F(0)); + check(STR("answer is '2.500000'"), STR("answer is '{:#f}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#f}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#f}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#f}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#f}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '0.031250'"), STR("answer is '{:07f}'"), 0.03125); + check(STR("answer is '+0.031250'"), STR("answer is '{:+07f}'"), 0.03125); + check(STR("answer is '+0.031250'"), STR("answer is '{:+08f}'"), 0.03125); + check(STR("answer is '+0.031250'"), STR("answer is '{:+09f}'"), 0.03125); + + check(STR("answer is '000.031250'"), STR("answer is '{:010f}'"), 0.03125); + check(STR("answer is '000.031250'"), STR("answer is '{:-010f}'"), 0.03125); + check(STR("answer is '+00.031250'"), STR("answer is '{:+010f}'"), 0.03125); + check(STR("answer is ' 00.031250'"), STR("answer is '{: 010f}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010f}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010f}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010f}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010f}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010f}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010f}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010f}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010f}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010f}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010f}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010f}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010f}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010f}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010f}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010f}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010f}'"), nan_neg); + + // *** precision *** + check(STR("answer is '0'"), STR("answer is '{:.0f}'"), 0.03125); + check(STR("answer is '0.0'"), STR("answer is '{:.1f}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.5f}'"), 0.03125); + check(STR("answer is '0.0312500000'"), STR("answer is '{:.10f}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_fixed_upper_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 0.250000'"), STR("answer is '{:11F}'"), F(0.25)); + check(STR("answer is ' 0.250000'"), STR("answer is '{:>11F}'"), F(0.25)); + check(STR("answer is '0.250000 '"), STR("answer is '{:<11F}'"), F(0.25)); + check(STR("answer is ' 0.250000 '"), STR("answer is '{:^11F}'"), F(0.25)); + + check(STR("answer is '---0.125000'"), STR("answer is '{:->11F}'"), F(125e-3)); + check(STR("answer is '0.125000---'"), STR("answer is '{:-<11F}'"), F(125e-3)); + check(STR("answer is '-0.125000--'"), STR("answer is '{:-^11F}'"), F(125e-3)); + + check(STR("answer is '***INF'"), STR("answer is '{:*>6F}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF***'"), STR("answer is '{:*<6F}'"), std::numeric_limits::infinity()); + check(STR("answer is '*INF**'"), STR("answer is '{:*^6F}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-INF'"), STR("answer is '{:#>7F}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF###'"), STR("answer is '{:#<7F}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-INF##'"), STR("answer is '{:#^7F}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6F}'"), nan_pos); + check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6F}'"), nan_pos); + check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6F}'"), nan_pos); + + check(STR("answer is '000-NAN'"), STR("answer is '{:0>7F}'"), nan_neg); + check(STR("answer is '-NAN000'"), STR("answer is '{:0<7F}'"), nan_neg); + check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7F}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 0.250000'"), STR("answer is '{:>011F}'"), F(0.25)); + check(STR("answer is '0.250000 '"), STR("answer is '{:<011F}'"), F(0.25)); + check(STR("answer is ' 0.250000 '"), STR("answer is '{:^011F}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0.000000'"), STR("answer is '{:F}'"), F(0)); + check(STR("answer is '0.000000'"), STR("answer is '{:-F}'"), F(0)); + check(STR("answer is '+0.000000'"), STR("answer is '{:+F}'"), F(0)); + check(STR("answer is ' 0.000000'"), STR("answer is '{: F}'"), F(0)); + + check(STR("answer is '-0.000000'"), STR("answer is '{:F}'"), F(-0.)); + check(STR("answer is '-0.000000'"), STR("answer is '{:-F}'"), F(-0.)); + check(STR("answer is '-0.000000'"), STR("answer is '{:+F}'"), F(-0.)); + check(STR("answer is '-0.000000'"), STR("answer is '{: F}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'INF'"), STR("answer is '{:F}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF'"), STR("answer is '{:-F}'"), std::numeric_limits::infinity()); + check(STR("answer is '+INF'"), STR("answer is '{:+F}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: F}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-INF'"), STR("answer is '{:F}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:-F}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:+F}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{: F}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:F}'"), nan_pos); + check(STR("answer is 'NAN'"), STR("answer is '{:-F}'"), nan_pos); + check(STR("answer is '+NAN'"), STR("answer is '{:+F}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: F}'"), nan_pos); + + check(STR("answer is '-NAN'"), STR("answer is '{:F}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:-F}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:+F}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{: F}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0'"), STR("answer is '{:.0F}'"), F(0)); + check(STR("answer is '0.'"), STR("answer is '{:#.0F}'"), F(0)); + + check(STR("answer is '0.000000'"), STR("answer is '{:#F}'"), F(0)); + check(STR("answer is '2.500000'"), STR("answer is '{:#F}'"), F(2.5)); + + check(STR("answer is 'INF'"), STR("answer is '{:#F}'"), std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:#F}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:#F}'"), nan_pos); + check(STR("answer is '-NAN'"), STR("answer is '{:#F}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '0.031250'"), STR("answer is '{:07F}'"), 0.03125); + check(STR("answer is '+0.031250'"), STR("answer is '{:+07F}'"), 0.03125); + check(STR("answer is '+0.031250'"), STR("answer is '{:+08F}'"), 0.03125); + check(STR("answer is '+0.031250'"), STR("answer is '{:+09F}'"), 0.03125); + + check(STR("answer is '000.031250'"), STR("answer is '{:010F}'"), 0.03125); + check(STR("answer is '000.031250'"), STR("answer is '{:-010F}'"), 0.03125); + check(STR("answer is '+00.031250'"), STR("answer is '{:+010F}'"), 0.03125); + check(STR("answer is ' 00.031250'"), STR("answer is '{: 010F}'"), 0.03125); + + check(STR("answer is ' INF'"), STR("answer is '{:010F}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{:-010F}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +INF'"), STR("answer is '{:+010F}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: 010F}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -INF'"), STR("answer is '{:010F}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:-010F}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:+010F}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{: 010F}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' NAN'"), STR("answer is '{:010F}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{:-010F}'"), nan_pos); + check(STR("answer is ' +NAN'"), STR("answer is '{:+010F}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: 010F}'"), nan_pos); + + check(STR("answer is ' -NAN'"), STR("answer is '{:010F}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:-010F}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:+010F}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{: 010F}'"), nan_neg); + + // *** precision *** + check(STR("answer is '0'"), STR("answer is '{:.0F}'"), 0.03125); + check(STR("answer is '0.0'"), STR("answer is '{:.1F}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.5F}'"), 0.03125); + check(STR("answer is '0.0312500000'"), STR("answer is '{:.10F}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_general_lower_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 0.25'"), STR("answer is '{:7g}'"), F(0.25)); + check(STR("answer is ' 0.25'"), STR("answer is '{:>7g}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<7g}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^7g}'"), F(0.25)); + + check(STR("answer is '---0.125'"), STR("answer is '{:->8g}'"), F(125e-3)); + check(STR("answer is '0.125---'"), STR("answer is '{:-<8g}'"), F(125e-3)); + check(STR("answer is '-0.125--'"), STR("answer is '{:-^8g}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6g}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6g}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6g}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7g}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7g}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7g}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6g}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6g}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6g}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7g}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7g}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7g}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 0.25'"), STR("answer is '{:>07g}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<07g}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^07g}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0'"), STR("answer is '{:g}'"), F(0)); + check(STR("answer is '0'"), STR("answer is '{:-g}'"), F(0)); + check(STR("answer is '+0'"), STR("answer is '{:+g}'"), F(0)); + check(STR("answer is ' 0'"), STR("answer is '{: g}'"), F(0)); + + check(STR("answer is '-0'"), STR("answer is '{:g}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:-g}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:+g}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{: g}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:g}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-g}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+g}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: g}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:g}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-g}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+g}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: g}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:g}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-g}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+g}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: g}'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:g}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-g}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+g}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: g}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0'"), STR("answer is '{:.0g}'"), F(0)); + check(STR("answer is '0.'"), STR("answer is '{:#.0g}'"), F(0)); + + check(STR("answer is '0.'"), STR("answer is '{:#g}'"), F(0)); + check(STR("answer is '2.5'"), STR("answer is '{:#g}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#g}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#g}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#g}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#g}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '0.03125'"), STR("answer is '{:06g}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+06g}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+07g}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+08g}'"), 0.03125); + + check(STR("answer is '000.03125'"), STR("answer is '{:09g}'"), 0.03125); + check(STR("answer is '000.03125'"), STR("answer is '{:-09g}'"), 0.03125); + check(STR("answer is '+00.03125'"), STR("answer is '{:+09g}'"), 0.03125); + check(STR("answer is ' 00.03125'"), STR("answer is '{: 09g}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010g}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010g}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010g}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010g}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010g}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010g}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010g}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010g}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010g}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010g}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010g}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010g}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010g}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010g}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010g}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010g}'"), nan_neg); + + // *** precision *** + check(STR("answer is '0.03'"), STR("answer is '{:.0g}'"), 0.03125); + check(STR("answer is '0.03'"), STR("answer is '{:.1g}'"), 0.03125); + check(STR("answer is '0.031'"), STR("answer is '{:.2g}'"), 0.03125); + check(STR("answer is '0.0312'"), STR("answer is '{:.3g}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.4g}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.5g}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.10g}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_general_upper_case(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 0.25'"), STR("answer is '{:7G}'"), F(0.25)); + check(STR("answer is ' 0.25'"), STR("answer is '{:>7G}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<7G}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^7G}'"), F(0.25)); + + check(STR("answer is '---0.125'"), STR("answer is '{:->8G}'"), F(125e-3)); + check(STR("answer is '0.125---'"), STR("answer is '{:-<8G}'"), F(125e-3)); + check(STR("answer is '-0.125--'"), STR("answer is '{:-^8G}'"), F(125e-3)); + + check(STR("answer is '***INF'"), STR("answer is '{:*>6G}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF***'"), STR("answer is '{:*<6G}'"), std::numeric_limits::infinity()); + check(STR("answer is '*INF**'"), STR("answer is '{:*^6G}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-INF'"), STR("answer is '{:#>7G}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF###'"), STR("answer is '{:#<7G}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-INF##'"), STR("answer is '{:#^7G}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^NAN'"), STR("answer is '{:^>6G}'"), nan_pos); + check(STR("answer is 'NAN^^^'"), STR("answer is '{:^<6G}'"), nan_pos); + check(STR("answer is '^NAN^^'"), STR("answer is '{:^^6G}'"), nan_pos); + + check(STR("answer is '000-NAN'"), STR("answer is '{:0>7G}'"), nan_neg); + check(STR("answer is '-NAN000'"), STR("answer is '{:0<7G}'"), nan_neg); + check(STR("answer is '0-NAN00'"), STR("answer is '{:0^7G}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 0.25'"), STR("answer is '{:>07G}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<07G}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^07G}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0'"), STR("answer is '{:G}'"), F(0)); + check(STR("answer is '0'"), STR("answer is '{:-G}'"), F(0)); + check(STR("answer is '+0'"), STR("answer is '{:+G}'"), F(0)); + check(STR("answer is ' 0'"), STR("answer is '{: G}'"), F(0)); + + check(STR("answer is '-0'"), STR("answer is '{:G}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:-G}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:+G}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{: G}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'INF'"), STR("answer is '{:G}'"), std::numeric_limits::infinity()); + check(STR("answer is 'INF'"), STR("answer is '{:-G}'"), std::numeric_limits::infinity()); + check(STR("answer is '+INF'"), STR("answer is '{:+G}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: G}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-INF'"), STR("answer is '{:G}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:-G}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:+G}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{: G}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:G}'"), nan_pos); + check(STR("answer is 'NAN'"), STR("answer is '{:-G}'"), nan_pos); + check(STR("answer is '+NAN'"), STR("answer is '{:+G}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: G}'"), nan_pos); + + check(STR("answer is '-NAN'"), STR("answer is '{:G}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:-G}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{:+G}'"), nan_neg); + check(STR("answer is '-NAN'"), STR("answer is '{: G}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0'"), STR("answer is '{:.0G}'"), F(0)); + check(STR("answer is '0.'"), STR("answer is '{:#.0G}'"), F(0)); + + check(STR("answer is '0.'"), STR("answer is '{:#G}'"), F(0)); + check(STR("answer is '2.5'"), STR("answer is '{:#G}'"), F(2.5)); + + check(STR("answer is 'INF'"), STR("answer is '{:#G}'"), std::numeric_limits::infinity()); + check(STR("answer is '-INF'"), STR("answer is '{:#G}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'NAN'"), STR("answer is '{:#G}'"), nan_pos); + check(STR("answer is '-NAN'"), STR("answer is '{:#G}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '0.03125'"), STR("answer is '{:06G}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+06G}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+07G}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+08G}'"), 0.03125); + + check(STR("answer is '000.03125'"), STR("answer is '{:09G}'"), 0.03125); + check(STR("answer is '000.03125'"), STR("answer is '{:-09G}'"), 0.03125); + check(STR("answer is '+00.03125'"), STR("answer is '{:+09G}'"), 0.03125); + check(STR("answer is ' 00.03125'"), STR("answer is '{: 09G}'"), 0.03125); + + check(STR("answer is ' INF'"), STR("answer is '{:010G}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{:-010G}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +INF'"), STR("answer is '{:+010G}'"), std::numeric_limits::infinity()); + check(STR("answer is ' INF'"), STR("answer is '{: 010G}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -INF'"), STR("answer is '{:010G}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:-010G}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{:+010G}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -INF'"), STR("answer is '{: 010G}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' NAN'"), STR("answer is '{:010G}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{:-010G}'"), nan_pos); + check(STR("answer is ' +NAN'"), STR("answer is '{:+010G}'"), nan_pos); + check(STR("answer is ' NAN'"), STR("answer is '{: 010G}'"), nan_pos); + + check(STR("answer is ' -NAN'"), STR("answer is '{:010G}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:-010G}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{:+010G}'"), nan_neg); + check(STR("answer is ' -NAN'"), STR("answer is '{: 010G}'"), nan_neg); + + // *** precision *** + check(STR("answer is '0.03'"), STR("answer is '{:.0G}'"), 0.03125); + check(STR("answer is '0.03'"), STR("answer is '{:.1G}'"), 0.03125); + check(STR("answer is '0.031'"), STR("answer is '{:.2G}'"), 0.03125); + check(STR("answer is '0.0312'"), STR("answer is '{:.3G}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.4G}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.5G}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.10G}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_default(TestFunction check) { + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 0.25'"), STR("answer is '{:7}'"), F(0.25)); + check(STR("answer is ' 0.25'"), STR("answer is '{:>7}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<7}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^7}'"), F(0.25)); + + check(STR("answer is '---0.125'"), STR("answer is '{:->8}'"), F(125e-3)); + check(STR("answer is '0.125---'"), STR("answer is '{:-<8}'"), F(125e-3)); + check(STR("answer is '-0.125--'"), STR("answer is '{:-^8}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 0.25'"), STR("answer is '{:>07}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<07}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^07}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0'"), STR("answer is '{:}'"), F(0)); + check(STR("answer is '0'"), STR("answer is '{:-}'"), F(0)); + check(STR("answer is '+0'"), STR("answer is '{:+}'"), F(0)); + check(STR("answer is ' 0'"), STR("answer is '{: }'"), F(0)); + + check(STR("answer is '-0'"), STR("answer is '{:}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:-}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:+}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{: }'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: }'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: }'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: }'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: }'"), nan_neg); + + // *** alternate form *** + check(STR("answer is '0.'"), STR("answer is '{:#}'"), F(0)); + check(STR("answer is '2.5'"), STR("answer is '{:#}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '0.03125'"), STR("answer is '{:07}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+07}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+08}'"), 0.03125); + check(STR("answer is '+00.03125'"), STR("answer is '{:+09}'"), 0.03125); + + check(STR("answer is '0000.03125'"), STR("answer is '{:010}'"), 0.03125); + check(STR("answer is '0000.03125'"), STR("answer is '{:-010}'"), 0.03125); + check(STR("answer is '+000.03125'"), STR("answer is '{:+010}'"), 0.03125); + check(STR("answer is ' 000.03125'"), STR("answer is '{: 010}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010}'"), nan_neg); + + // *** precision *** + // See format_test_floating_point_default_precision + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point_default_precision(TestFunction check) { + + auto nan_pos = std::numeric_limits::quiet_NaN(); // "nan" + auto nan_neg = std::copysign(nan_pos, -1.0); // "-nan" + + // *** align-fill & width *** + check(STR("answer is ' 0.25'"), STR("answer is '{:7.6}'"), F(0.25)); + check(STR("answer is ' 0.25'"), STR("answer is '{:>7.6}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<7.6}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^7.6}'"), F(0.25)); + + check(STR("answer is '---0.125'"), STR("answer is '{:->8.6}'"), F(125e-3)); + check(STR("answer is '0.125---'"), STR("answer is '{:-<8.6}'"), F(125e-3)); + check(STR("answer is '-0.125--'"), STR("answer is '{:-^8.6}'"), F(125e-3)); + + check(STR("answer is '***inf'"), STR("answer is '{:*>6.6}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf***'"), STR("answer is '{:*<6.6}'"), std::numeric_limits::infinity()); + check(STR("answer is '*inf**'"), STR("answer is '{:*^6.6}'"), std::numeric_limits::infinity()); + + check(STR("answer is '###-inf'"), STR("answer is '{:#>7.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf###'"), STR("answer is '{:#<7.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is '#-inf##'"), STR("answer is '{:#^7.6}'"), -std::numeric_limits::infinity()); + + check(STR("answer is '^^^nan'"), STR("answer is '{:^>6.6}'"), nan_pos); + check(STR("answer is 'nan^^^'"), STR("answer is '{:^<6.6}'"), nan_pos); + check(STR("answer is '^nan^^'"), STR("answer is '{:^^6.6}'"), nan_pos); + + check(STR("answer is '000-nan'"), STR("answer is '{:0>7.6}'"), nan_neg); + check(STR("answer is '-nan000'"), STR("answer is '{:0<7.6}'"), nan_neg); + check(STR("answer is '0-nan00'"), STR("answer is '{:0^7.6}'"), nan_neg); + + // Test whether zero padding is ignored + check(STR("answer is ' 0.25'"), STR("answer is '{:>07.6}'"), F(0.25)); + check(STR("answer is '0.25 '"), STR("answer is '{:<07.6}'"), F(0.25)); + check(STR("answer is ' 0.25 '"), STR("answer is '{:^07.6}'"), F(0.25)); + + // *** Sign *** + check(STR("answer is '0'"), STR("answer is '{:.6}'"), F(0)); + check(STR("answer is '0'"), STR("answer is '{:-.6}'"), F(0)); + check(STR("answer is '+0'"), STR("answer is '{:+.6}'"), F(0)); + check(STR("answer is ' 0'"), STR("answer is '{: .6}'"), F(0)); + + check(STR("answer is '-0'"), STR("answer is '{:.6}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:-.6}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{:+.6}'"), F(-0.)); + check(STR("answer is '-0'"), STR("answer is '{: .6}'"), F(-0.)); + + // [format.string.std]/5 The sign option applies to floating-point infinity and NaN. + check(STR("answer is 'inf'"), STR("answer is '{:.6}'"), std::numeric_limits::infinity()); + check(STR("answer is 'inf'"), STR("answer is '{:-.6}'"), std::numeric_limits::infinity()); + check(STR("answer is '+inf'"), STR("answer is '{:+.6}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: .6}'"), std::numeric_limits::infinity()); + + check(STR("answer is '-inf'"), STR("answer is '{:.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:-.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:+.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{: .6}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:.6}'"), nan_pos); + check(STR("answer is 'nan'"), STR("answer is '{:-.6}'"), nan_pos); + check(STR("answer is '+nan'"), STR("answer is '{:+.6}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: .6}'"), nan_pos); + + check(STR("answer is '-nan'"), STR("answer is '{:.6}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:-.6}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{:+.6}'"), nan_neg); + check(STR("answer is '-nan'"), STR("answer is '{: .6}'"), nan_neg); + + // *** alternate form ** + // When precision is zero there's no decimal point except when the alternate form is specified. + check(STR("answer is '0'"), STR("answer is '{:.0}'"), F(0)); + check(STR("answer is '0.'"), STR("answer is '{:#.0}'"), F(0)); + + check(STR("answer is '0.'"), STR("answer is '{:#.6}'"), F(0)); + check(STR("answer is '2.5'"), STR("answer is '{:#.6}'"), F(2.5)); + + check(STR("answer is 'inf'"), STR("answer is '{:#.6}'"), std::numeric_limits::infinity()); + check(STR("answer is '-inf'"), STR("answer is '{:#.6}'"), -std::numeric_limits::infinity()); + + check(STR("answer is 'nan'"), STR("answer is '{:#.6}'"), nan_pos); + check(STR("answer is '-nan'"), STR("answer is '{:#.6}'"), nan_neg); + + // *** zero-padding & width *** + check(STR("answer is '0.03125'"), STR("answer is '{:06.6}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+06.6}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+07.6}'"), 0.03125); + check(STR("answer is '+0.03125'"), STR("answer is '{:+08.6}'"), 0.03125); + + check(STR("answer is '000.03125'"), STR("answer is '{:09.6}'"), 0.03125); + check(STR("answer is '000.03125'"), STR("answer is '{:-09.6}'"), 0.03125); + check(STR("answer is '+00.03125'"), STR("answer is '{:+09.6}'"), 0.03125); + check(STR("answer is ' 00.03125'"), STR("answer is '{: 09.6}'"), 0.03125); + + check(STR("answer is ' inf'"), STR("answer is '{:010.6}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{:-010.6}'"), std::numeric_limits::infinity()); + check(STR("answer is ' +inf'"), STR("answer is '{:+010.6}'"), std::numeric_limits::infinity()); + check(STR("answer is ' inf'"), STR("answer is '{: 010.6}'"), std::numeric_limits::infinity()); + + check(STR("answer is ' -inf'"), STR("answer is '{:010.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:-010.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{:+010.6}'"), -std::numeric_limits::infinity()); + check(STR("answer is ' -inf'"), STR("answer is '{: 010.6}'"), -std::numeric_limits::infinity()); + + check(STR("answer is ' nan'"), STR("answer is '{:010.6}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{:-010.6}'"), nan_pos); + check(STR("answer is ' +nan'"), STR("answer is '{:+010.6}'"), nan_pos); + check(STR("answer is ' nan'"), STR("answer is '{: 010.6}'"), nan_pos); + + check(STR("answer is ' -nan'"), STR("answer is '{:010.6}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:-010.6}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{:+010.6}'"), nan_neg); + check(STR("answer is ' -nan'"), STR("answer is '{: 010.6}'"), nan_neg); + + // *** precision *** + check(STR("answer is '0.03'"), STR("answer is '{:.0}'"), 0.03125); + check(STR("answer is '0.03'"), STR("answer is '{:.1}'"), 0.03125); + check(STR("answer is '0.031'"), STR("answer is '{:.2}'"), 0.03125); + check(STR("answer is '0.0312'"), STR("answer is '{:.3}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.4}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.5}'"), 0.03125); + check(STR("answer is '0.03125'"), STR("answer is '{:.10}'"), 0.03125); + + // *** locale-specific form *** + // See locale-specific_form.pass.cpp +} + +template +void format_test_floating_point(TestFunction check, ExceptionTest check_exception) { + format_test_floating_point_hex_lower_case(check); + format_test_floating_point_hex_upper_case(check); + format_test_floating_point_hex_lower_case_precision(check); + format_test_floating_point_hex_upper_case_precision(check); + + format_test_floating_point_scientific_lower_case(check); + format_test_floating_point_scientific_upper_case(check); + + format_test_floating_point_fixed_lower_case(check); + format_test_floating_point_fixed_upper_case(check); + + format_test_floating_point_general_lower_case(check); + format_test_floating_point_general_upper_case(check); + + format_test_floating_point_default(check); + format_test_floating_point_default_precision(check); + + // *** type *** + for (const auto& fmt : invalid_types("aAeEfFgG")) + check_exception("The format-spec type has a type not supported for a floating-point argument", fmt, F(1)); +} + +template +void format_test_floating_point(TestFunction check, ExceptionTest check_exception) { + format_test_floating_point(check, check_exception); + format_test_floating_point(check, check_exception); + format_test_floating_point(check, check_exception); +} + template void format_tests(TestFunction check, ExceptionTest check_exception) { // *** Test escaping *** @@ -1115,12 +2607,10 @@ format_test_unsigned_integer(check, check_exception); // *** Test floating point format argument *** -// TODO FMT Enable after floating-point support has been enabled -#if 0 - check(STR("hello 42.000000"), STR("hello {}"), static_cast(42)); - check(STR("hello 42.000000"), STR("hello {}"), static_cast(42)); - check(STR("hello 42.000000"), STR("hello {}"), static_cast(42)); -#endif + check(STR("hello 42"), STR("hello {}"), static_cast(42)); + check(STR("hello 42"), STR("hello {}"), static_cast(42)); + check(STR("hello 42"), STR("hello {}"), static_cast(42)); + format_test_floating_point(check, check_exception); } #ifndef TEST_HAS_NO_WIDE_CHARACTERS diff --git a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp --- a/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp +++ b/libcxx/test/std/utilities/format/format.functions/locale-specific_form.pass.cpp @@ -110,6 +110,7 @@ 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 '#'; } }; #ifndef TEST_HAS_NO_WIDE_CHARACTERS @@ -120,6 +121,7 @@ std::string do_grouping() const override { return "\1\2\3\2\1"; }; wchar_t do_thousands_sep() const override { return L'_'; } + wchar_t do_decimal_point() const override { return L'#'; } }; #endif @@ -607,10 +609,1725 @@ test(STR("-0X004_A"), loc, STR("{:#08LX}"), -0x4a); } +template +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(STR("1.23456p-3"), STR("{:La}"), F(0x1.23456p-3)); + test(STR("1.23456p-2"), STR("{:La}"), F(0x1.23456p-2)); + test(STR("1.23456p-1"), STR("{:La}"), F(0x1.23456p-1)); + test(STR("1.23456p+0"), STR("{:La}"), F(0x1.23456p0)); + test(STR("1.23456p+1"), STR("{:La}"), F(0x1.23456p+1)); + test(STR("1.23456p+2"), STR("{:La}"), F(0x1.23456p+2)); + test(STR("1.23456p+3"), STR("{:La}"), F(0x1.23456p+3)); + test(STR("1.23456p+20"), STR("{:La}"), F(0x1.23456p+20)); + + std::locale::global(loc); + test(STR("1#23456p-3"), STR("{:La}"), F(0x1.23456p-3)); + test(STR("1#23456p-2"), STR("{:La}"), F(0x1.23456p-2)); + test(STR("1#23456p-1"), STR("{:La}"), F(0x1.23456p-1)); + test(STR("1#23456p+0"), STR("{:La}"), F(0x1.23456p0)); + test(STR("1#23456p+1"), STR("{:La}"), F(0x1.23456p+1)); + test(STR("1#23456p+2"), STR("{:La}"), F(0x1.23456p+2)); + test(STR("1#23456p+3"), STR("{:La}"), F(0x1.23456p+3)); + test(STR("1#23456p+20"), STR("{:La}"), F(0x1.23456p+20)); + + test(STR("1.23456p-3"), en_US, STR("{:La}"), F(0x1.23456p-3)); + test(STR("1.23456p-2"), en_US, STR("{:La}"), F(0x1.23456p-2)); + test(STR("1.23456p-1"), en_US, STR("{:La}"), F(0x1.23456p-1)); + test(STR("1.23456p+0"), en_US, STR("{:La}"), F(0x1.23456p0)); + test(STR("1.23456p+1"), en_US, STR("{:La}"), F(0x1.23456p+1)); + test(STR("1.23456p+2"), en_US, STR("{:La}"), F(0x1.23456p+2)); + test(STR("1.23456p+3"), en_US, STR("{:La}"), F(0x1.23456p+3)); + test(STR("1.23456p+20"), en_US, STR("{:La}"), F(0x1.23456p+20)); + + std::locale::global(en_US); + test(STR("1#23456p-3"), loc, STR("{:La}"), F(0x1.23456p-3)); + test(STR("1#23456p-2"), loc, STR("{:La}"), F(0x1.23456p-2)); + test(STR("1#23456p-1"), loc, STR("{:La}"), F(0x1.23456p-1)); + test(STR("1#23456p+0"), loc, STR("{:La}"), F(0x1.23456p0)); + test(STR("1#23456p+1"), loc, STR("{:La}"), F(0x1.23456p+1)); + test(STR("1#23456p+2"), loc, STR("{:La}"), F(0x1.23456p+2)); + test(STR("1#23456p+3"), loc, STR("{:La}"), F(0x1.23456p+3)); + test(STR("1#23456p+20"), loc, STR("{:La}"), F(0x1.23456p+20)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1.23456p+3$$$"), STR("{:$<13La}"), F(0x1.23456p3)); + test(STR("$$$1.23456p+3"), STR("{:$>13La}"), F(0x1.23456p3)); + test(STR("$1.23456p+3$$"), STR("{:$^13La}"), F(0x1.23456p3)); + test(STR("0001.23456p+3"), STR("{:013La}"), F(0x1.23456p3)); + test(STR("-1.23456p+3$$$"), STR("{:$<14La}"), F(-0x1.23456p3)); + test(STR("$$$-1.23456p+3"), STR("{:$>14La}"), F(-0x1.23456p3)); + test(STR("$-1.23456p+3$$"), STR("{:$^14La}"), F(-0x1.23456p3)); + test(STR("-0001.23456p+3"), STR("{:014La}"), F(-0x1.23456p3)); + + std::locale::global(loc); + test(STR("1#23456p+3$$$"), STR("{:$<13La}"), F(0x1.23456p3)); + test(STR("$$$1#23456p+3"), STR("{:$>13La}"), F(0x1.23456p3)); + test(STR("$1#23456p+3$$"), STR("{:$^13La}"), F(0x1.23456p3)); + test(STR("0001#23456p+3"), STR("{:013La}"), F(0x1.23456p3)); + test(STR("-1#23456p+3$$$"), STR("{:$<14La}"), F(-0x1.23456p3)); + test(STR("$$$-1#23456p+3"), STR("{:$>14La}"), F(-0x1.23456p3)); + test(STR("$-1#23456p+3$$"), STR("{:$^14La}"), F(-0x1.23456p3)); + test(STR("-0001#23456p+3"), STR("{:014La}"), F(-0x1.23456p3)); + + test(STR("1.23456p+3$$$"), en_US, STR("{:$<13La}"), F(0x1.23456p3)); + test(STR("$$$1.23456p+3"), en_US, STR("{:$>13La}"), F(0x1.23456p3)); + test(STR("$1.23456p+3$$"), en_US, STR("{:$^13La}"), F(0x1.23456p3)); + test(STR("0001.23456p+3"), en_US, STR("{:013La}"), F(0x1.23456p3)); + test(STR("-1.23456p+3$$$"), en_US, STR("{:$<14La}"), F(-0x1.23456p3)); + test(STR("$$$-1.23456p+3"), en_US, STR("{:$>14La}"), F(-0x1.23456p3)); + test(STR("$-1.23456p+3$$"), en_US, STR("{:$^14La}"), F(-0x1.23456p3)); + test(STR("-0001.23456p+3"), en_US, STR("{:014La}"), F(-0x1.23456p3)); + + std::locale::global(en_US); + test(STR("1#23456p+3$$$"), loc, STR("{:$<13La}"), F(0x1.23456p3)); + test(STR("$$$1#23456p+3"), loc, STR("{:$>13La}"), F(0x1.23456p3)); + test(STR("$1#23456p+3$$"), loc, STR("{:$^13La}"), F(0x1.23456p3)); + test(STR("0001#23456p+3"), loc, STR("{:013La}"), F(0x1.23456p3)); + test(STR("-1#23456p+3$$$"), loc, STR("{:$<14La}"), F(-0x1.23456p3)); + test(STR("$$$-1#23456p+3"), loc, STR("{:$>14La}"), F(-0x1.23456p3)); + test(STR("$-1#23456p+3$$"), loc, STR("{:$^14La}"), F(-0x1.23456p3)); + test(STR("-0001#23456p+3"), loc, STR("{:014La}"), F(-0x1.23456p3)); +} + +template +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(STR("1.23456P-3"), STR("{:LA}"), F(0x1.23456p-3)); + test(STR("1.23456P-2"), STR("{:LA}"), F(0x1.23456p-2)); + test(STR("1.23456P-1"), STR("{:LA}"), F(0x1.23456p-1)); + test(STR("1.23456P+0"), STR("{:LA}"), F(0x1.23456p0)); + test(STR("1.23456P+1"), STR("{:LA}"), F(0x1.23456p+1)); + test(STR("1.23456P+2"), STR("{:LA}"), F(0x1.23456p+2)); + test(STR("1.23456P+3"), STR("{:LA}"), F(0x1.23456p+3)); + test(STR("1.23456P+20"), STR("{:LA}"), F(0x1.23456p+20)); + + std::locale::global(loc); + test(STR("1#23456P-3"), STR("{:LA}"), F(0x1.23456p-3)); + test(STR("1#23456P-2"), STR("{:LA}"), F(0x1.23456p-2)); + test(STR("1#23456P-1"), STR("{:LA}"), F(0x1.23456p-1)); + test(STR("1#23456P+0"), STR("{:LA}"), F(0x1.23456p0)); + test(STR("1#23456P+1"), STR("{:LA}"), F(0x1.23456p+1)); + test(STR("1#23456P+2"), STR("{:LA}"), F(0x1.23456p+2)); + test(STR("1#23456P+3"), STR("{:LA}"), F(0x1.23456p+3)); + test(STR("1#23456P+20"), STR("{:LA}"), F(0x1.23456p+20)); + + test(STR("1.23456P-3"), en_US, STR("{:LA}"), F(0x1.23456p-3)); + test(STR("1.23456P-2"), en_US, STR("{:LA}"), F(0x1.23456p-2)); + test(STR("1.23456P-1"), en_US, STR("{:LA}"), F(0x1.23456p-1)); + test(STR("1.23456P+0"), en_US, STR("{:LA}"), F(0x1.23456p0)); + test(STR("1.23456P+1"), en_US, STR("{:LA}"), F(0x1.23456p+1)); + test(STR("1.23456P+2"), en_US, STR("{:LA}"), F(0x1.23456p+2)); + test(STR("1.23456P+3"), en_US, STR("{:LA}"), F(0x1.23456p+3)); + test(STR("1.23456P+20"), en_US, STR("{:LA}"), F(0x1.23456p+20)); + + std::locale::global(en_US); + test(STR("1#23456P-3"), loc, STR("{:LA}"), F(0x1.23456p-3)); + test(STR("1#23456P-2"), loc, STR("{:LA}"), F(0x1.23456p-2)); + test(STR("1#23456P-1"), loc, STR("{:LA}"), F(0x1.23456p-1)); + test(STR("1#23456P+0"), loc, STR("{:LA}"), F(0x1.23456p0)); + test(STR("1#23456P+1"), loc, STR("{:LA}"), F(0x1.23456p+1)); + test(STR("1#23456P+2"), loc, STR("{:LA}"), F(0x1.23456p+2)); + test(STR("1#23456P+3"), loc, STR("{:LA}"), F(0x1.23456p+3)); + test(STR("1#23456P+20"), loc, STR("{:LA}"), F(0x1.23456p+20)); + + // *** Fill, align, zero Padding *** + std::locale::global(en_US); + test(STR("1.23456P+3$$$"), STR("{:$<13LA}"), F(0x1.23456p3)); + test(STR("$$$1.23456P+3"), STR("{:$>13LA}"), F(0x1.23456p3)); + test(STR("$1.23456P+3$$"), STR("{:$^13LA}"), F(0x1.23456p3)); + test(STR("0001.23456P+3"), STR("{:013LA}"), F(0x1.23456p3)); + test(STR("-1.23456P+3$$$"), STR("{:$<14LA}"), F(-0x1.23456p3)); + test(STR("$$$-1.23456P+3"), STR("{:$>14LA}"), F(-0x1.23456p3)); + test(STR("$-1.23456P+3$$"), STR("{:$^14LA}"), F(-0x1.23456p3)); + test(STR("-0001.23456P+3"), STR("{:014LA}"), F(-0x1.23456p3)); + + std::locale::global(loc); + test(STR("1#23456P+3$$$"), STR("{:$<13LA}"), F(0x1.23456p3)); + test(STR("$$$1#23456P+3"), STR("{:$>13LA}"), F(0x1.23456p3)); + test(STR("$1#23456P+3$$"), STR("{:$^13LA}"), F(0x1.23456p3)); + test(STR("0001#23456P+3"), STR("{:013LA}"), F(0x1.23456p3)); + test(STR("-1#23456P+3$$$"), STR("{:$<14LA}"), F(-0x1.23456p3)); + test(STR("$$$-1#23456P+3"), STR("{:$>14LA}"), F(-0x1.23456p3)); + test(STR("$-1#23456P+3$$"), STR("{:$^14LA}"), F(-0x1.23456p3)); + test(STR("-0001#23456P+3"), STR("{:014LA}"), F(-0x1.23456p3)); + + test(STR("1.23456P+3$$$"), en_US, STR("{:$<13LA}"), F(0x1.23456p3)); + test(STR("$$$1.23456P+3"), en_US, STR("{:$>13LA}"), F(0x1.23456p3)); + test(STR("$1.23456P+3$$"), en_US, STR("{:$^13LA}"), F(0x1.23456p3)); + test(STR("0001.23456P+3"), en_US, STR("{:013LA}"), F(0x1.23456p3)); + test(STR("-1.23456P+3$$$"), en_US, STR("{:$<14LA}"), F(-0x1.23456p3)); + test(STR("$$$-1.23456P+3"), en_US, STR("{:$>14LA}"), F(-0x1.23456p3)); + test(STR("$-1.23456P+3$$"), en_US, STR("{:$^14LA}"), F(-0x1.23456p3)); + test(STR("-0001.23456P+3"), en_US, STR("{:014LA}"), F(-0x1.23456p3)); + + std::locale::global(en_US); + test(STR("1#23456P+3$$$"), loc, STR("{:$<13LA}"), F(0x1.23456p3)); + test(STR("$$$1#23456P+3"), loc, STR("{:$>13LA}"), F(0x1.23456p3)); + test(STR("$1#23456P+3$$"), loc, STR("{:$^13LA}"), F(0x1.23456p3)); + test(STR("0001#23456P+3"), loc, STR("{:013LA}"), F(0x1.23456p3)); + test(STR("-1#23456P+3$$$"), loc, STR("{:$<14LA}"), F(-0x1.23456p3)); + test(STR("$$$-1#23456P+3"), loc, STR("{:$>14LA}"), F(-0x1.23456p3)); + test(STR("$-1#23456P+3$$"), loc, STR("{:$^14LA}"), F(-0x1.23456p3)); + test(STR("-0001#23456P+3"), loc, STR("{:014LA}"), F(-0x1.23456p3)); +} + +template +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(STR("1.234560p-3"), STR("{:.6La}"), F(0x1.23456p-3)); + test(STR("1.234560p-2"), STR("{:.6La}"), F(0x1.23456p-2)); + test(STR("1.234560p-1"), STR("{:.6La}"), F(0x1.23456p-1)); + test(STR("1.234560p+0"), STR("{:.6La}"), F(0x1.23456p0)); + test(STR("1.234560p+1"), STR("{:.6La}"), F(0x1.23456p+1)); + test(STR("1.234560p+2"), STR("{:.6La}"), F(0x1.23456p+2)); + test(STR("1.234560p+3"), STR("{:.6La}"), F(0x1.23456p+3)); + test(STR("1.234560p+20"), STR("{:.6La}"), F(0x1.23456p+20)); + + std::locale::global(loc); + test(STR("1#234560p-3"), STR("{:.6La}"), F(0x1.23456p-3)); + test(STR("1#234560p-2"), STR("{:.6La}"), F(0x1.23456p-2)); + test(STR("1#234560p-1"), STR("{:.6La}"), F(0x1.23456p-1)); + test(STR("1#234560p+0"), STR("{:.6La}"), F(0x1.23456p0)); + test(STR("1#234560p+1"), STR("{:.6La}"), F(0x1.23456p+1)); + test(STR("1#234560p+2"), STR("{:.6La}"), F(0x1.23456p+2)); + test(STR("1#234560p+3"), STR("{:.6La}"), F(0x1.23456p+3)); + test(STR("1#234560p+20"), STR("{:.6La}"), F(0x1.23456p+20)); + + test(STR("1.234560p-3"), en_US, STR("{:.6La}"), F(0x1.23456p-3)); + test(STR("1.234560p-2"), en_US, STR("{:.6La}"), F(0x1.23456p-2)); + test(STR("1.234560p-1"), en_US, STR("{:.6La}"), F(0x1.23456p-1)); + test(STR("1.234560p+0"), en_US, STR("{:.6La}"), F(0x1.23456p0)); + test(STR("1.234560p+1"), en_US, STR("{:.6La}"), F(0x1.23456p+1)); + test(STR("1.234560p+2"), en_US, STR("{:.6La}"), F(0x1.23456p+2)); + test(STR("1.234560p+3"), en_US, STR("{:.6La}"), F(0x1.23456p+3)); + test(STR("1.234560p+20"), en_US, STR("{:.6La}"), F(0x1.23456p+20)); + + std::locale::global(en_US); + test(STR("1#234560p-3"), loc, STR("{:.6La}"), F(0x1.23456p-3)); + test(STR("1#234560p-2"), loc, STR("{:.6La}"), F(0x1.23456p-2)); + test(STR("1#234560p-1"), loc, STR("{:.6La}"), F(0x1.23456p-1)); + test(STR("1#234560p+0"), loc, STR("{:.6La}"), F(0x1.23456p0)); + test(STR("1#234560p+1"), loc, STR("{:.6La}"), F(0x1.23456p+1)); + test(STR("1#234560p+2"), loc, STR("{:.6La}"), F(0x1.23456p+2)); + test(STR("1#234560p+3"), loc, STR("{:.6La}"), F(0x1.23456p+3)); + test(STR("1#234560p+20"), loc, STR("{:.6La}"), F(0x1.23456p+20)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1.234560p+3$$$"), STR("{:$<14.6La}"), F(0x1.23456p3)); + test(STR("$$$1.234560p+3"), STR("{:$>14.6La}"), F(0x1.23456p3)); + test(STR("$1.234560p+3$$"), STR("{:$^14.6La}"), F(0x1.23456p3)); + test(STR("0001.234560p+3"), STR("{:014.6La}"), F(0x1.23456p3)); + test(STR("-1.234560p+3$$$"), STR("{:$<15.6La}"), F(-0x1.23456p3)); + test(STR("$$$-1.234560p+3"), STR("{:$>15.6La}"), F(-0x1.23456p3)); + test(STR("$-1.234560p+3$$"), STR("{:$^15.6La}"), F(-0x1.23456p3)); + test(STR("-0001.234560p+3"), STR("{:015.6La}"), F(-0x1.23456p3)); + + std::locale::global(loc); + test(STR("1#234560p+3$$$"), STR("{:$<14.6La}"), F(0x1.23456p3)); + test(STR("$$$1#234560p+3"), STR("{:$>14.6La}"), F(0x1.23456p3)); + test(STR("$1#234560p+3$$"), STR("{:$^14.6La}"), F(0x1.23456p3)); + test(STR("0001#234560p+3"), STR("{:014.6La}"), F(0x1.23456p3)); + test(STR("-1#234560p+3$$$"), STR("{:$<15.6La}"), F(-0x1.23456p3)); + test(STR("$$$-1#234560p+3"), STR("{:$>15.6La}"), F(-0x1.23456p3)); + test(STR("$-1#234560p+3$$"), STR("{:$^15.6La}"), F(-0x1.23456p3)); + test(STR("-0001#234560p+3"), STR("{:015.6La}"), F(-0x1.23456p3)); + + test(STR("1.234560p+3$$$"), en_US, STR("{:$<14.6La}"), F(0x1.23456p3)); + test(STR("$$$1.234560p+3"), en_US, STR("{:$>14.6La}"), F(0x1.23456p3)); + test(STR("$1.234560p+3$$"), en_US, STR("{:$^14.6La}"), F(0x1.23456p3)); + test(STR("0001.234560p+3"), en_US, STR("{:014.6La}"), F(0x1.23456p3)); + test(STR("-1.234560p+3$$$"), en_US, STR("{:$<15.6La}"), F(-0x1.23456p3)); + test(STR("$$$-1.234560p+3"), en_US, STR("{:$>15.6La}"), F(-0x1.23456p3)); + test(STR("$-1.234560p+3$$"), en_US, STR("{:$^15.6La}"), F(-0x1.23456p3)); + test(STR("-0001.234560p+3"), en_US, STR("{:015.6La}"), F(-0x1.23456p3)); + + std::locale::global(en_US); + test(STR("1#234560p+3$$$"), loc, STR("{:$<14.6La}"), F(0x1.23456p3)); + test(STR("$$$1#234560p+3"), loc, STR("{:$>14.6La}"), F(0x1.23456p3)); + test(STR("$1#234560p+3$$"), loc, STR("{:$^14.6La}"), F(0x1.23456p3)); + test(STR("0001#234560p+3"), loc, STR("{:014.6La}"), F(0x1.23456p3)); + test(STR("-1#234560p+3$$$"), loc, STR("{:$<15.6La}"), F(-0x1.23456p3)); + test(STR("$$$-1#234560p+3"), loc, STR("{:$>15.6La}"), F(-0x1.23456p3)); + test(STR("$-1#234560p+3$$"), loc, STR("{:$^15.6La}"), F(-0x1.23456p3)); + test(STR("-0001#234560p+3"), loc, STR("{:015.6La}"), F(-0x1.23456p3)); +} + +template +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(STR("1.234560P-3"), STR("{:.6LA}"), F(0x1.23456p-3)); + test(STR("1.234560P-2"), STR("{:.6LA}"), F(0x1.23456p-2)); + test(STR("1.234560P-1"), STR("{:.6LA}"), F(0x1.23456p-1)); + test(STR("1.234560P+0"), STR("{:.6LA}"), F(0x1.23456p0)); + test(STR("1.234560P+1"), STR("{:.6LA}"), F(0x1.23456p+1)); + test(STR("1.234560P+2"), STR("{:.6LA}"), F(0x1.23456p+2)); + test(STR("1.234560P+3"), STR("{:.6LA}"), F(0x1.23456p+3)); + test(STR("1.234560P+20"), STR("{:.6LA}"), F(0x1.23456p+20)); + + std::locale::global(loc); + test(STR("1#234560P-3"), STR("{:.6LA}"), F(0x1.23456p-3)); + test(STR("1#234560P-2"), STR("{:.6LA}"), F(0x1.23456p-2)); + test(STR("1#234560P-1"), STR("{:.6LA}"), F(0x1.23456p-1)); + test(STR("1#234560P+0"), STR("{:.6LA}"), F(0x1.23456p0)); + test(STR("1#234560P+1"), STR("{:.6LA}"), F(0x1.23456p+1)); + test(STR("1#234560P+2"), STR("{:.6LA}"), F(0x1.23456p+2)); + test(STR("1#234560P+3"), STR("{:.6LA}"), F(0x1.23456p+3)); + test(STR("1#234560P+20"), STR("{:.6LA}"), F(0x1.23456p+20)); + + test(STR("1.234560P-3"), en_US, STR("{:.6LA}"), F(0x1.23456p-3)); + test(STR("1.234560P-2"), en_US, STR("{:.6LA}"), F(0x1.23456p-2)); + test(STR("1.234560P-1"), en_US, STR("{:.6LA}"), F(0x1.23456p-1)); + test(STR("1.234560P+0"), en_US, STR("{:.6LA}"), F(0x1.23456p0)); + test(STR("1.234560P+1"), en_US, STR("{:.6LA}"), F(0x1.23456p+1)); + test(STR("1.234560P+2"), en_US, STR("{:.6LA}"), F(0x1.23456p+2)); + test(STR("1.234560P+3"), en_US, STR("{:.6LA}"), F(0x1.23456p+3)); + test(STR("1.234560P+20"), en_US, STR("{:.6LA}"), F(0x1.23456p+20)); + + std::locale::global(en_US); + test(STR("1#234560P-3"), loc, STR("{:.6LA}"), F(0x1.23456p-3)); + test(STR("1#234560P-2"), loc, STR("{:.6LA}"), F(0x1.23456p-2)); + test(STR("1#234560P-1"), loc, STR("{:.6LA}"), F(0x1.23456p-1)); + test(STR("1#234560P+0"), loc, STR("{:.6LA}"), F(0x1.23456p0)); + test(STR("1#234560P+1"), loc, STR("{:.6LA}"), F(0x1.23456p+1)); + test(STR("1#234560P+2"), loc, STR("{:.6LA}"), F(0x1.23456p+2)); + test(STR("1#234560P+3"), loc, STR("{:.6LA}"), F(0x1.23456p+3)); + test(STR("1#234560P+20"), loc, STR("{:.6LA}"), F(0x1.23456p+20)); + + // *** Fill, align, zero Padding *** + std::locale::global(en_US); + test(STR("1.234560P+3$$$"), STR("{:$<14.6LA}"), F(0x1.23456p3)); + test(STR("$$$1.234560P+3"), STR("{:$>14.6LA}"), F(0x1.23456p3)); + test(STR("$1.234560P+3$$"), STR("{:$^14.6LA}"), F(0x1.23456p3)); + test(STR("0001.234560P+3"), STR("{:014.6LA}"), F(0x1.23456p3)); + test(STR("-1.234560P+3$$$"), STR("{:$<15.6LA}"), F(-0x1.23456p3)); + test(STR("$$$-1.234560P+3"), STR("{:$>15.6LA}"), F(-0x1.23456p3)); + test(STR("$-1.234560P+3$$"), STR("{:$^15.6LA}"), F(-0x1.23456p3)); + test(STR("-0001.234560P+3"), STR("{:015.6LA}"), F(-0x1.23456p3)); + + std::locale::global(loc); + test(STR("1#234560P+3$$$"), STR("{:$<14.6LA}"), F(0x1.23456p3)); + test(STR("$$$1#234560P+3"), STR("{:$>14.6LA}"), F(0x1.23456p3)); + test(STR("$1#234560P+3$$"), STR("{:$^14.6LA}"), F(0x1.23456p3)); + test(STR("0001#234560P+3"), STR("{:014.6LA}"), F(0x1.23456p3)); + test(STR("-1#234560P+3$$$"), STR("{:$<15.6LA}"), F(-0x1.23456p3)); + test(STR("$$$-1#234560P+3"), STR("{:$>15.6LA}"), F(-0x1.23456p3)); + test(STR("$-1#234560P+3$$"), STR("{:$^15.6LA}"), F(-0x1.23456p3)); + test(STR("-0001#234560P+3"), STR("{:015.6LA}"), F(-0x1.23456p3)); + + test(STR("1.234560P+3$$$"), en_US, STR("{:$<14.6LA}"), F(0x1.23456p3)); + test(STR("$$$1.234560P+3"), en_US, STR("{:$>14.6LA}"), F(0x1.23456p3)); + test(STR("$1.234560P+3$$"), en_US, STR("{:$^14.6LA}"), F(0x1.23456p3)); + test(STR("0001.234560P+3"), en_US, STR("{:014.6LA}"), F(0x1.23456p3)); + test(STR("-1.234560P+3$$$"), en_US, STR("{:$<15.6LA}"), F(-0x1.23456p3)); + test(STR("$$$-1.234560P+3"), en_US, STR("{:$>15.6LA}"), F(-0x1.23456p3)); + test(STR("$-1.234560P+3$$"), en_US, STR("{:$^15.6LA}"), F(-0x1.23456p3)); + test(STR("-0001.234560P+3"), en_US, STR("{:015.6LA}"), F(-0x1.23456p3)); + + std::locale::global(en_US); + test(STR("1#234560P+3$$$"), loc, STR("{:$<14.6LA}"), F(0x1.23456p3)); + test(STR("$$$1#234560P+3"), loc, STR("{:$>14.6LA}"), F(0x1.23456p3)); + test(STR("$1#234560P+3$$"), loc, STR("{:$^14.6LA}"), F(0x1.23456p3)); + test(STR("0001#234560P+3"), loc, STR("{:014.6LA}"), F(0x1.23456p3)); + test(STR("-1#234560P+3$$$"), loc, STR("{:$<15.6LA}"), F(-0x1.23456p3)); + test(STR("$$$-1#234560P+3"), loc, STR("{:$>15.6LA}"), F(-0x1.23456p3)); + test(STR("$-1#234560P+3$$"), loc, STR("{:$^15.6LA}"), F(-0x1.23456p3)); + test(STR("-0001#234560P+3"), loc, STR("{:015.6LA}"), F(-0x1.23456p3)); +} + +template +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(STR("1.234567e-03"), STR("{:.6Le}"), F(1.234567e-3)); + test(STR("1.234567e-02"), STR("{:.6Le}"), F(1.234567e-2)); + test(STR("1.234567e-01"), STR("{:.6Le}"), F(1.234567e-1)); + test(STR("1.234567e+00"), STR("{:.6Le}"), F(1.234567e0)); + test(STR("1.234567e+01"), STR("{:.6Le}"), F(1.234567e1)); + test(STR("1.234567e+02"), STR("{:.6Le}"), F(1.234567e2)); + test(STR("1.234567e+03"), STR("{:.6Le}"), F(1.234567e3)); + test(STR("1.234567e+20"), STR("{:.6Le}"), F(1.234567e20)); + test(STR("-1.234567e-03"), STR("{:.6Le}"), F(-1.234567e-3)); + test(STR("-1.234567e-02"), STR("{:.6Le}"), F(-1.234567e-2)); + test(STR("-1.234567e-01"), STR("{:.6Le}"), F(-1.234567e-1)); + test(STR("-1.234567e+00"), STR("{:.6Le}"), F(-1.234567e0)); + test(STR("-1.234567e+01"), STR("{:.6Le}"), F(-1.234567e1)); + test(STR("-1.234567e+02"), STR("{:.6Le}"), F(-1.234567e2)); + test(STR("-1.234567e+03"), STR("{:.6Le}"), F(-1.234567e3)); + test(STR("-1.234567e+20"), STR("{:.6Le}"), F(-1.234567e20)); + + std::locale::global(loc); + test(STR("1#234567e-03"), STR("{:.6Le}"), F(1.234567e-3)); + test(STR("1#234567e-02"), STR("{:.6Le}"), F(1.234567e-2)); + test(STR("1#234567e-01"), STR("{:.6Le}"), F(1.234567e-1)); + test(STR("1#234567e+00"), STR("{:.6Le}"), F(1.234567e0)); + test(STR("1#234567e+01"), STR("{:.6Le}"), F(1.234567e1)); + test(STR("1#234567e+02"), STR("{:.6Le}"), F(1.234567e2)); + test(STR("1#234567e+03"), STR("{:.6Le}"), F(1.234567e3)); + test(STR("1#234567e+20"), STR("{:.6Le}"), F(1.234567e20)); + test(STR("-1#234567e-03"), STR("{:.6Le}"), F(-1.234567e-3)); + test(STR("-1#234567e-02"), STR("{:.6Le}"), F(-1.234567e-2)); + test(STR("-1#234567e-01"), STR("{:.6Le}"), F(-1.234567e-1)); + test(STR("-1#234567e+00"), STR("{:.6Le}"), F(-1.234567e0)); + test(STR("-1#234567e+01"), STR("{:.6Le}"), F(-1.234567e1)); + test(STR("-1#234567e+02"), STR("{:.6Le}"), F(-1.234567e2)); + test(STR("-1#234567e+03"), STR("{:.6Le}"), F(-1.234567e3)); + test(STR("-1#234567e+20"), STR("{:.6Le}"), F(-1.234567e20)); + + test(STR("1.234567e-03"), en_US, STR("{:.6Le}"), F(1.234567e-3)); + test(STR("1.234567e-02"), en_US, STR("{:.6Le}"), F(1.234567e-2)); + test(STR("1.234567e-01"), en_US, STR("{:.6Le}"), F(1.234567e-1)); + test(STR("1.234567e+00"), en_US, STR("{:.6Le}"), F(1.234567e0)); + test(STR("1.234567e+01"), en_US, STR("{:.6Le}"), F(1.234567e1)); + test(STR("1.234567e+02"), en_US, STR("{:.6Le}"), F(1.234567e2)); + test(STR("1.234567e+03"), en_US, STR("{:.6Le}"), F(1.234567e3)); + test(STR("1.234567e+20"), en_US, STR("{:.6Le}"), F(1.234567e20)); + test(STR("-1.234567e-03"), en_US, STR("{:.6Le}"), F(-1.234567e-3)); + test(STR("-1.234567e-02"), en_US, STR("{:.6Le}"), F(-1.234567e-2)); + test(STR("-1.234567e-01"), en_US, STR("{:.6Le}"), F(-1.234567e-1)); + test(STR("-1.234567e+00"), en_US, STR("{:.6Le}"), F(-1.234567e0)); + test(STR("-1.234567e+01"), en_US, STR("{:.6Le}"), F(-1.234567e1)); + test(STR("-1.234567e+02"), en_US, STR("{:.6Le}"), F(-1.234567e2)); + test(STR("-1.234567e+03"), en_US, STR("{:.6Le}"), F(-1.234567e3)); + test(STR("-1.234567e+20"), en_US, STR("{:.6Le}"), F(-1.234567e20)); + + std::locale::global(en_US); + test(STR("1#234567e-03"), loc, STR("{:.6Le}"), F(1.234567e-3)); + test(STR("1#234567e-02"), loc, STR("{:.6Le}"), F(1.234567e-2)); + test(STR("1#234567e-01"), loc, STR("{:.6Le}"), F(1.234567e-1)); + test(STR("1#234567e+00"), loc, STR("{:.6Le}"), F(1.234567e0)); + test(STR("1#234567e+01"), loc, STR("{:.6Le}"), F(1.234567e1)); + test(STR("1#234567e+02"), loc, STR("{:.6Le}"), F(1.234567e2)); + test(STR("1#234567e+03"), loc, STR("{:.6Le}"), F(1.234567e3)); + test(STR("1#234567e+20"), loc, STR("{:.6Le}"), F(1.234567e20)); + test(STR("-1#234567e-03"), loc, STR("{:.6Le}"), F(-1.234567e-3)); + test(STR("-1#234567e-02"), loc, STR("{:.6Le}"), F(-1.234567e-2)); + test(STR("-1#234567e-01"), loc, STR("{:.6Le}"), F(-1.234567e-1)); + test(STR("-1#234567e+00"), loc, STR("{:.6Le}"), F(-1.234567e0)); + test(STR("-1#234567e+01"), loc, STR("{:.6Le}"), F(-1.234567e1)); + test(STR("-1#234567e+02"), loc, STR("{:.6Le}"), F(-1.234567e2)); + test(STR("-1#234567e+03"), loc, STR("{:.6Le}"), F(-1.234567e3)); + test(STR("-1#234567e+20"), loc, STR("{:.6Le}"), F(-1.234567e20)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1.234567e+03$$$"), STR("{:$<15.6Le}"), F(1.234567e3)); + test(STR("$$$1.234567e+03"), STR("{:$>15.6Le}"), F(1.234567e3)); + test(STR("$1.234567e+03$$"), STR("{:$^15.6Le}"), F(1.234567e3)); + test(STR("0001.234567e+03"), STR("{:015.6Le}"), F(1.234567e3)); + test(STR("-1.234567e+03$$$"), STR("{:$<16.6Le}"), F(-1.234567e3)); + test(STR("$$$-1.234567e+03"), STR("{:$>16.6Le}"), F(-1.234567e3)); + test(STR("$-1.234567e+03$$"), STR("{:$^16.6Le}"), F(-1.234567e3)); + test(STR("-0001.234567e+03"), STR("{:016.6Le}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1#234567e+03$$$"), STR("{:$<15.6Le}"), F(1.234567e3)); + test(STR("$$$1#234567e+03"), STR("{:$>15.6Le}"), F(1.234567e3)); + test(STR("$1#234567e+03$$"), STR("{:$^15.6Le}"), F(1.234567e3)); + test(STR("0001#234567e+03"), STR("{:015.6Le}"), F(1.234567e3)); + test(STR("-1#234567e+03$$$"), STR("{:$<16.6Le}"), F(-1.234567e3)); + test(STR("$$$-1#234567e+03"), STR("{:$>16.6Le}"), F(-1.234567e3)); + test(STR("$-1#234567e+03$$"), STR("{:$^16.6Le}"), F(-1.234567e3)); + test(STR("-0001#234567e+03"), STR("{:016.6Le}"), F(-1.234567e3)); + + test(STR("1.234567e+03$$$"), en_US, STR("{:$<15.6Le}"), F(1.234567e3)); + test(STR("$$$1.234567e+03"), en_US, STR("{:$>15.6Le}"), F(1.234567e3)); + test(STR("$1.234567e+03$$"), en_US, STR("{:$^15.6Le}"), F(1.234567e3)); + test(STR("0001.234567e+03"), en_US, STR("{:015.6Le}"), F(1.234567e3)); + test(STR("-1.234567e+03$$$"), en_US, STR("{:$<16.6Le}"), F(-1.234567e3)); + test(STR("$$$-1.234567e+03"), en_US, STR("{:$>16.6Le}"), F(-1.234567e3)); + test(STR("$-1.234567e+03$$"), en_US, STR("{:$^16.6Le}"), F(-1.234567e3)); + test(STR("-0001.234567e+03"), en_US, STR("{:016.6Le}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1#234567e+03$$$"), loc, STR("{:$<15.6Le}"), F(1.234567e3)); + test(STR("$$$1#234567e+03"), loc, STR("{:$>15.6Le}"), F(1.234567e3)); + test(STR("$1#234567e+03$$"), loc, STR("{:$^15.6Le}"), F(1.234567e3)); + test(STR("0001#234567e+03"), loc, STR("{:015.6Le}"), F(1.234567e3)); + test(STR("-1#234567e+03$$$"), loc, STR("{:$<16.6Le}"), F(-1.234567e3)); + test(STR("$$$-1#234567e+03"), loc, STR("{:$>16.6Le}"), F(-1.234567e3)); + test(STR("$-1#234567e+03$$"), loc, STR("{:$^16.6Le}"), F(-1.234567e3)); + test(STR("-0001#234567e+03"), loc, STR("{:016.6Le}"), F(-1.234567e3)); +} + +template +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(STR("1.234567E-03"), STR("{:.6LE}"), F(1.234567e-3)); + test(STR("1.234567E-02"), STR("{:.6LE}"), F(1.234567e-2)); + test(STR("1.234567E-01"), STR("{:.6LE}"), F(1.234567e-1)); + test(STR("1.234567E+00"), STR("{:.6LE}"), F(1.234567e0)); + test(STR("1.234567E+01"), STR("{:.6LE}"), F(1.234567e1)); + test(STR("1.234567E+02"), STR("{:.6LE}"), F(1.234567e2)); + test(STR("1.234567E+03"), STR("{:.6LE}"), F(1.234567e3)); + test(STR("1.234567E+20"), STR("{:.6LE}"), F(1.234567e20)); + test(STR("-1.234567E-03"), STR("{:.6LE}"), F(-1.234567e-3)); + test(STR("-1.234567E-02"), STR("{:.6LE}"), F(-1.234567e-2)); + test(STR("-1.234567E-01"), STR("{:.6LE}"), F(-1.234567e-1)); + test(STR("-1.234567E+00"), STR("{:.6LE}"), F(-1.234567e0)); + test(STR("-1.234567E+01"), STR("{:.6LE}"), F(-1.234567e1)); + test(STR("-1.234567E+02"), STR("{:.6LE}"), F(-1.234567e2)); + test(STR("-1.234567E+03"), STR("{:.6LE}"), F(-1.234567e3)); + test(STR("-1.234567E+20"), STR("{:.6LE}"), F(-1.234567e20)); + + std::locale::global(loc); + test(STR("1#234567E-03"), STR("{:.6LE}"), F(1.234567e-3)); + test(STR("1#234567E-02"), STR("{:.6LE}"), F(1.234567e-2)); + test(STR("1#234567E-01"), STR("{:.6LE}"), F(1.234567e-1)); + test(STR("1#234567E+00"), STR("{:.6LE}"), F(1.234567e0)); + test(STR("1#234567E+01"), STR("{:.6LE}"), F(1.234567e1)); + test(STR("1#234567E+02"), STR("{:.6LE}"), F(1.234567e2)); + test(STR("1#234567E+03"), STR("{:.6LE}"), F(1.234567e3)); + test(STR("1#234567E+20"), STR("{:.6LE}"), F(1.234567e20)); + test(STR("-1#234567E-03"), STR("{:.6LE}"), F(-1.234567e-3)); + test(STR("-1#234567E-02"), STR("{:.6LE}"), F(-1.234567e-2)); + test(STR("-1#234567E-01"), STR("{:.6LE}"), F(-1.234567e-1)); + test(STR("-1#234567E+00"), STR("{:.6LE}"), F(-1.234567e0)); + test(STR("-1#234567E+01"), STR("{:.6LE}"), F(-1.234567e1)); + test(STR("-1#234567E+02"), STR("{:.6LE}"), F(-1.234567e2)); + test(STR("-1#234567E+03"), STR("{:.6LE}"), F(-1.234567e3)); + test(STR("-1#234567E+20"), STR("{:.6LE}"), F(-1.234567e20)); + + test(STR("1.234567E-03"), en_US, STR("{:.6LE}"), F(1.234567e-3)); + test(STR("1.234567E-02"), en_US, STR("{:.6LE}"), F(1.234567e-2)); + test(STR("1.234567E-01"), en_US, STR("{:.6LE}"), F(1.234567e-1)); + test(STR("1.234567E+00"), en_US, STR("{:.6LE}"), F(1.234567e0)); + test(STR("1.234567E+01"), en_US, STR("{:.6LE}"), F(1.234567e1)); + test(STR("1.234567E+02"), en_US, STR("{:.6LE}"), F(1.234567e2)); + test(STR("1.234567E+03"), en_US, STR("{:.6LE}"), F(1.234567e3)); + test(STR("1.234567E+20"), en_US, STR("{:.6LE}"), F(1.234567e20)); + test(STR("-1.234567E-03"), en_US, STR("{:.6LE}"), F(-1.234567e-3)); + test(STR("-1.234567E-02"), en_US, STR("{:.6LE}"), F(-1.234567e-2)); + test(STR("-1.234567E-01"), en_US, STR("{:.6LE}"), F(-1.234567e-1)); + test(STR("-1.234567E+00"), en_US, STR("{:.6LE}"), F(-1.234567e0)); + test(STR("-1.234567E+01"), en_US, STR("{:.6LE}"), F(-1.234567e1)); + test(STR("-1.234567E+02"), en_US, STR("{:.6LE}"), F(-1.234567e2)); + test(STR("-1.234567E+03"), en_US, STR("{:.6LE}"), F(-1.234567e3)); + test(STR("-1.234567E+20"), en_US, STR("{:.6LE}"), F(-1.234567e20)); + + std::locale::global(en_US); + test(STR("1#234567E-03"), loc, STR("{:.6LE}"), F(1.234567e-3)); + test(STR("1#234567E-02"), loc, STR("{:.6LE}"), F(1.234567e-2)); + test(STR("1#234567E-01"), loc, STR("{:.6LE}"), F(1.234567e-1)); + test(STR("1#234567E+00"), loc, STR("{:.6LE}"), F(1.234567e0)); + test(STR("1#234567E+01"), loc, STR("{:.6LE}"), F(1.234567e1)); + test(STR("1#234567E+02"), loc, STR("{:.6LE}"), F(1.234567e2)); + test(STR("1#234567E+03"), loc, STR("{:.6LE}"), F(1.234567e3)); + test(STR("1#234567E+20"), loc, STR("{:.6LE}"), F(1.234567e20)); + test(STR("-1#234567E-03"), loc, STR("{:.6LE}"), F(-1.234567e-3)); + test(STR("-1#234567E-02"), loc, STR("{:.6LE}"), F(-1.234567e-2)); + test(STR("-1#234567E-01"), loc, STR("{:.6LE}"), F(-1.234567e-1)); + test(STR("-1#234567E+00"), loc, STR("{:.6LE}"), F(-1.234567e0)); + test(STR("-1#234567E+01"), loc, STR("{:.6LE}"), F(-1.234567e1)); + test(STR("-1#234567E+02"), loc, STR("{:.6LE}"), F(-1.234567e2)); + test(STR("-1#234567E+03"), loc, STR("{:.6LE}"), F(-1.234567e3)); + test(STR("-1#234567E+20"), loc, STR("{:.6LE}"), F(-1.234567e20)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1.234567E+03$$$"), STR("{:$<15.6LE}"), F(1.234567e3)); + test(STR("$$$1.234567E+03"), STR("{:$>15.6LE}"), F(1.234567e3)); + test(STR("$1.234567E+03$$"), STR("{:$^15.6LE}"), F(1.234567e3)); + test(STR("0001.234567E+03"), STR("{:015.6LE}"), F(1.234567e3)); + test(STR("-1.234567E+03$$$"), STR("{:$<16.6LE}"), F(-1.234567e3)); + test(STR("$$$-1.234567E+03"), STR("{:$>16.6LE}"), F(-1.234567e3)); + test(STR("$-1.234567E+03$$"), STR("{:$^16.6LE}"), F(-1.234567e3)); + test(STR("-0001.234567E+03"), STR("{:016.6LE}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1#234567E+03$$$"), STR("{:$<15.6LE}"), F(1.234567e3)); + test(STR("$$$1#234567E+03"), STR("{:$>15.6LE}"), F(1.234567e3)); + test(STR("$1#234567E+03$$"), STR("{:$^15.6LE}"), F(1.234567e3)); + test(STR("0001#234567E+03"), STR("{:015.6LE}"), F(1.234567e3)); + test(STR("-1#234567E+03$$$"), STR("{:$<16.6LE}"), F(-1.234567e3)); + test(STR("$$$-1#234567E+03"), STR("{:$>16.6LE}"), F(-1.234567e3)); + test(STR("$-1#234567E+03$$"), STR("{:$^16.6LE}"), F(-1.234567e3)); + test(STR("-0001#234567E+03"), STR("{:016.6LE}"), F(-1.234567e3)); + + test(STR("1.234567E+03$$$"), en_US, STR("{:$<15.6LE}"), F(1.234567e3)); + test(STR("$$$1.234567E+03"), en_US, STR("{:$>15.6LE}"), F(1.234567e3)); + test(STR("$1.234567E+03$$"), en_US, STR("{:$^15.6LE}"), F(1.234567e3)); + test(STR("0001.234567E+03"), en_US, STR("{:015.6LE}"), F(1.234567e3)); + test(STR("-1.234567E+03$$$"), en_US, STR("{:$<16.6LE}"), F(-1.234567e3)); + test(STR("$$$-1.234567E+03"), en_US, STR("{:$>16.6LE}"), F(-1.234567e3)); + test(STR("$-1.234567E+03$$"), en_US, STR("{:$^16.6LE}"), F(-1.234567e3)); + test(STR("-0001.234567E+03"), en_US, STR("{:016.6LE}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1#234567E+03$$$"), loc, STR("{:$<15.6LE}"), F(1.234567e3)); + test(STR("$$$1#234567E+03"), loc, STR("{:$>15.6LE}"), F(1.234567e3)); + test(STR("$1#234567E+03$$"), loc, STR("{:$^15.6LE}"), F(1.234567e3)); + test(STR("0001#234567E+03"), loc, STR("{:015.6LE}"), F(1.234567e3)); + test(STR("-1#234567E+03$$$"), loc, STR("{:$<16.6LE}"), F(-1.234567e3)); + test(STR("$$$-1#234567E+03"), loc, STR("{:$>16.6LE}"), F(-1.234567e3)); + test(STR("$-1#234567E+03$$"), loc, STR("{:$^16.6LE}"), F(-1.234567e3)); + test(STR("-0001#234567E+03"), loc, STR("{:016.6LE}"), F(-1.234567e3)); +} + +template +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(STR("0.000001"), STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0.000012"), STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0.000123"), STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0.001235"), STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0.012346"), STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0.123457"), STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1.234567"), STR("{:.6Lf}"), F(1.234567e0)); + test(STR("12.345670"), STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("123.456700"), STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1,234.567000"), STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12,345.670000"), STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123,456.700000"), STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1,234,567.000000"), STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12,345,670.000000"), STR("{:.6Lf}"), F(1.234567e7)); + test(STR("123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0.000001"), STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0.000012"), STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0.000123"), STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0.001235"), STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0.012346"), STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0.123457"), STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1.234567"), STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-12.345670"), STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-123.456700"), STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1,234.567000"), STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12,345.670000"), STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123,456.700000"), STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1,234,567.000000"), STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12,345,670.000000"), STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(-1.234567e20)); + } + + std::locale::global(loc); + test(STR("0#000001"), STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0#000012"), STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0#000123"), STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0#001235"), STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0#012346"), STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0#123457"), STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1#234567"), STR("{:.6Lf}"), F(1.234567e0)); + test(STR("1_2#345670"), STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("12_3#456700"), STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1_23_4#567000"), STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12_34_5#670000"), STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123_45_6#700000"), STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1_234_56_7#000000"), STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12_345_67_0#000000"), STR("{:.6Lf}"), F(1.234567e7)); + test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0#000001"), STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0#000012"), STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0#000123"), STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0#001235"), STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0#012346"), STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0#123457"), STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1#234567"), STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-1_2#345670"), STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-12_3#456700"), STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1_23_4#567000"), STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12_34_5#670000"), STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123_45_6#700000"), STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1_234_56_7#000000"), STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12_345_67_0#000000"), STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(-1.234567e20)); + } + + test(STR("0.000001"), en_US, STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0.000012"), en_US, STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0.000123"), en_US, STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0.001235"), en_US, STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0.012346"), en_US, STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0.123457"), en_US, STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1.234567"), en_US, STR("{:.6Lf}"), F(1.234567e0)); + test(STR("12.345670"), en_US, STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("123.456700"), en_US, STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1,234.567000"), en_US, STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12,345.670000"), en_US, STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123,456.700000"), en_US, STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1,234,567.000000"), en_US, STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12,345,670.000000"), en_US, STR("{:.6Lf}"), F(1.234567e7)); + test(STR("123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0.000001"), en_US, STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0.000012"), en_US, STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0.000123"), en_US, STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0.001235"), en_US, STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0.012346"), en_US, STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0.123457"), en_US, STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1.234567"), en_US, STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-12.345670"), en_US, STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-123.456700"), en_US, STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1,234.567000"), en_US, STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12,345.670000"), en_US, STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123,456.700000"), en_US, STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1,234,567.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12,345,670.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e20)); + } + + std::locale::global(en_US); + test(STR("0#000001"), loc, STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0#000012"), loc, STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0#000123"), loc, STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0#001235"), loc, STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0#012346"), loc, STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0#123457"), loc, STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1#234567"), loc, STR("{:.6Lf}"), F(1.234567e0)); + test(STR("1_2#345670"), loc, STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("12_3#456700"), loc, STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1_23_4#567000"), loc, STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12_34_5#670000"), loc, STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123_45_6#700000"), loc, STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e7)); + test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0#000001"), loc, STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0#000012"), loc, STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0#000123"), loc, STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0#001235"), loc, STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0#012346"), loc, STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0#123457"), loc, STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1#234567"), loc, STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-1_2#345670"), loc, STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-12_3#456700"), loc, STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1_23_4#567000"), loc, STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12_34_5#670000"), loc, STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123_45_6#700000"), loc, STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e20)); + } + + // *** Fill, align, zero padding *** + if constexpr (sizeof(F) > sizeof(float)) { + std::locale::global(en_US); + test(STR("1,234.567000$$$"), STR("{:$<15.6Lf}"), F(1.234567e3)); + test(STR("$$$1,234.567000"), STR("{:$>15.6Lf}"), F(1.234567e3)); + test(STR("$1,234.567000$$"), STR("{:$^15.6Lf}"), F(1.234567e3)); + test(STR("0001,234.567000"), STR("{:015.6Lf}"), F(1.234567e3)); + test(STR("-1,234.567000$$$"), STR("{:$<16.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1,234.567000"), STR("{:$>16.6Lf}"), F(-1.234567e3)); + test(STR("$-1,234.567000$$"), STR("{:$^16.6Lf}"), F(-1.234567e3)); + test(STR("-0001,234.567000"), STR("{:016.6Lf}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1_23_4#567000$$$"), STR("{:$<16.6Lf}"), F(1.234567e3)); + test(STR("$$$1_23_4#567000"), STR("{:$>16.6Lf}"), F(1.234567e3)); + test(STR("$1_23_4#567000$$"), STR("{:$^16.6Lf}"), F(1.234567e3)); + test(STR("0001_23_4#567000"), STR("{:016.6Lf}"), F(1.234567e3)); + test(STR("-1_23_4#567000$$$"), STR("{:$<17.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#567000"), STR("{:$>17.6Lf}"), F(-1.234567e3)); + test(STR("$-1_23_4#567000$$"), STR("{:$^17.6Lf}"), F(-1.234567e3)); + test(STR("-0001_23_4#567000"), STR("{:017.6Lf}"), F(-1.234567e3)); + + test(STR("1,234.567000$$$"), en_US, STR("{:$<15.6Lf}"), F(1.234567e3)); + test(STR("$$$1,234.567000"), en_US, STR("{:$>15.6Lf}"), F(1.234567e3)); + test(STR("$1,234.567000$$"), en_US, STR("{:$^15.6Lf}"), F(1.234567e3)); + test(STR("0001,234.567000"), en_US, STR("{:015.6Lf}"), F(1.234567e3)); + test(STR("-1,234.567000$$$"), en_US, STR("{:$<16.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1,234.567000"), en_US, STR("{:$>16.6Lf}"), F(-1.234567e3)); + test(STR("$-1,234.567000$$"), en_US, STR("{:$^16.6Lf}"), F(-1.234567e3)); + test(STR("-0001,234.567000"), en_US, STR("{:016.6Lf}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1_23_4#567000$$$"), loc, STR("{:$<16.6Lf}"), F(1.234567e3)); + test(STR("$$$1_23_4#567000"), loc, STR("{:$>16.6Lf}"), F(1.234567e3)); + test(STR("$1_23_4#567000$$"), loc, STR("{:$^16.6Lf}"), F(1.234567e3)); + test(STR("0001_23_4#567000"), loc, STR("{:016.6Lf}"), F(1.234567e3)); + test(STR("-1_23_4#567000$$$"), loc, STR("{:$<17.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#567000"), loc, STR("{:$>17.6Lf}"), F(-1.234567e3)); + test(STR("$-1_23_4#567000$$"), loc, STR("{:$^17.6Lf}"), F(-1.234567e3)); + test(STR("-0001_23_4#567000"), loc, STR("{:017.6Lf}"), F(-1.234567e3)); + } +} + +template +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(STR("0.000001"), STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0.000012"), STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0.000123"), STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0.001235"), STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0.012346"), STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0.123457"), STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1.234567"), STR("{:.6Lf}"), F(1.234567e0)); + test(STR("12.345670"), STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("123.456700"), STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1,234.567000"), STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12,345.670000"), STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123,456.700000"), STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1,234,567.000000"), STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12,345,670.000000"), STR("{:.6Lf}"), F(1.234567e7)); + test(STR("123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0.000001"), STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0.000012"), STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0.000123"), STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0.001235"), STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0.012346"), STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0.123457"), STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1.234567"), STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-12.345670"), STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-123.456700"), STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1,234.567000"), STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12,345.670000"), STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123,456.700000"), STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1,234,567.000000"), STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12,345,670.000000"), STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-123,456,700,000,000,000,000.000000"), STR("{:.6Lf}"), F(-1.234567e20)); + } + + std::locale::global(loc); + test(STR("0#000001"), STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0#000012"), STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0#000123"), STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0#001235"), STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0#012346"), STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0#123457"), STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1#234567"), STR("{:.6Lf}"), F(1.234567e0)); + test(STR("1_2#345670"), STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("12_3#456700"), STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1_23_4#567000"), STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12_34_5#670000"), STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123_45_6#700000"), STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1_234_56_7#000000"), STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12_345_67_0#000000"), STR("{:.6Lf}"), F(1.234567e7)); + test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0#000001"), STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0#000012"), STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0#000123"), STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0#001235"), STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0#012346"), STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0#123457"), STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1#234567"), STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-1_2#345670"), STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-12_3#456700"), STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1_23_4#567000"), STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12_34_5#670000"), STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123_45_6#700000"), STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1_234_56_7#000000"), STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12_345_67_0#000000"), STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), STR("{:.6Lf}"), F(-1.234567e20)); + } + + test(STR("0.000001"), en_US, STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0.000012"), en_US, STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0.000123"), en_US, STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0.001235"), en_US, STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0.012346"), en_US, STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0.123457"), en_US, STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1.234567"), en_US, STR("{:.6Lf}"), F(1.234567e0)); + test(STR("12.345670"), en_US, STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("123.456700"), en_US, STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1,234.567000"), en_US, STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12,345.670000"), en_US, STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123,456.700000"), en_US, STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1,234,567.000000"), en_US, STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12,345,670.000000"), en_US, STR("{:.6Lf}"), F(1.234567e7)); + test(STR("123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0.000001"), en_US, STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0.000012"), en_US, STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0.000123"), en_US, STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0.001235"), en_US, STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0.012346"), en_US, STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0.123457"), en_US, STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1.234567"), en_US, STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-12.345670"), en_US, STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-123.456700"), en_US, STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1,234.567000"), en_US, STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12,345.670000"), en_US, STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123,456.700000"), en_US, STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1,234,567.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12,345,670.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-123,456,700,000,000,000,000.000000"), en_US, STR("{:.6Lf}"), F(-1.234567e20)); + } + + std::locale::global(en_US); + test(STR("0#000001"), loc, STR("{:.6Lf}"), F(1.234567e-6)); + test(STR("0#000012"), loc, STR("{:.6Lf}"), F(1.234567e-5)); + test(STR("0#000123"), loc, STR("{:.6Lf}"), F(1.234567e-4)); + test(STR("0#001235"), loc, STR("{:.6Lf}"), F(1.234567e-3)); + test(STR("0#012346"), loc, STR("{:.6Lf}"), F(1.234567e-2)); + test(STR("0#123457"), loc, STR("{:.6Lf}"), F(1.234567e-1)); + test(STR("1#234567"), loc, STR("{:.6Lf}"), F(1.234567e0)); + test(STR("1_2#345670"), loc, STR("{:.6Lf}"), F(1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("12_3#456700"), loc, STR("{:.6Lf}"), F(1.234567e2)); + test(STR("1_23_4#567000"), loc, STR("{:.6Lf}"), F(1.234567e3)); + test(STR("12_34_5#670000"), loc, STR("{:.6Lf}"), F(1.234567e4)); + test(STR("123_45_6#700000"), loc, STR("{:.6Lf}"), F(1.234567e5)); + test(STR("1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(1.234567e6)); + test(STR("12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e7)); + test(STR("1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(1.234567e20)); + } + test(STR("-0#000001"), loc, STR("{:.6Lf}"), F(-1.234567e-6)); + test(STR("-0#000012"), loc, STR("{:.6Lf}"), F(-1.234567e-5)); + test(STR("-0#000123"), loc, STR("{:.6Lf}"), F(-1.234567e-4)); + test(STR("-0#001235"), loc, STR("{:.6Lf}"), F(-1.234567e-3)); + test(STR("-0#012346"), loc, STR("{:.6Lf}"), F(-1.234567e-2)); + test(STR("-0#123457"), loc, STR("{:.6Lf}"), F(-1.234567e-1)); + test(STR("-1#234567"), loc, STR("{:.6Lf}"), F(-1.234567e0)); + test(STR("-1_2#345670"), loc, STR("{:.6Lf}"), F(-1.234567e1)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-12_3#456700"), loc, STR("{:.6Lf}"), F(-1.234567e2)); + test(STR("-1_23_4#567000"), loc, STR("{:.6Lf}"), F(-1.234567e3)); + test(STR("-12_34_5#670000"), loc, STR("{:.6Lf}"), F(-1.234567e4)); + test(STR("-123_45_6#700000"), loc, STR("{:.6Lf}"), F(-1.234567e5)); + test(STR("-1_234_56_7#000000"), loc, STR("{:.6Lf}"), F(-1.234567e6)); + test(STR("-12_345_67_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e7)); + test(STR("-1_2_3_4_5_6_7_0_0_0_0_0_0_00_000_00_0#000000"), loc, STR("{:.6Lf}"), F(-1.234567e20)); + } + + // *** Fill, align, zero padding *** + if constexpr (sizeof(F) > sizeof(float)) { + std::locale::global(en_US); + test(STR("1,234.567000$$$"), STR("{:$<15.6Lf}"), F(1.234567e3)); + test(STR("$$$1,234.567000"), STR("{:$>15.6Lf}"), F(1.234567e3)); + test(STR("$1,234.567000$$"), STR("{:$^15.6Lf}"), F(1.234567e3)); + test(STR("0001,234.567000"), STR("{:015.6Lf}"), F(1.234567e3)); + test(STR("-1,234.567000$$$"), STR("{:$<16.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1,234.567000"), STR("{:$>16.6Lf}"), F(-1.234567e3)); + test(STR("$-1,234.567000$$"), STR("{:$^16.6Lf}"), F(-1.234567e3)); + test(STR("-0001,234.567000"), STR("{:016.6Lf}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1_23_4#567000$$$"), STR("{:$<16.6Lf}"), F(1.234567e3)); + test(STR("$$$1_23_4#567000"), STR("{:$>16.6Lf}"), F(1.234567e3)); + test(STR("$1_23_4#567000$$"), STR("{:$^16.6Lf}"), F(1.234567e3)); + test(STR("0001_23_4#567000"), STR("{:016.6Lf}"), F(1.234567e3)); + test(STR("-1_23_4#567000$$$"), STR("{:$<17.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#567000"), STR("{:$>17.6Lf}"), F(-1.234567e3)); + test(STR("$-1_23_4#567000$$"), STR("{:$^17.6Lf}"), F(-1.234567e3)); + test(STR("-0001_23_4#567000"), STR("{:017.6Lf}"), F(-1.234567e3)); + + test(STR("1,234.567000$$$"), en_US, STR("{:$<15.6Lf}"), F(1.234567e3)); + test(STR("$$$1,234.567000"), en_US, STR("{:$>15.6Lf}"), F(1.234567e3)); + test(STR("$1,234.567000$$"), en_US, STR("{:$^15.6Lf}"), F(1.234567e3)); + test(STR("0001,234.567000"), en_US, STR("{:015.6Lf}"), F(1.234567e3)); + test(STR("-1,234.567000$$$"), en_US, STR("{:$<16.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1,234.567000"), en_US, STR("{:$>16.6Lf}"), F(-1.234567e3)); + test(STR("$-1,234.567000$$"), en_US, STR("{:$^16.6Lf}"), F(-1.234567e3)); + test(STR("-0001,234.567000"), en_US, STR("{:016.6Lf}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1_23_4#567000$$$"), loc, STR("{:$<16.6Lf}"), F(1.234567e3)); + test(STR("$$$1_23_4#567000"), loc, STR("{:$>16.6Lf}"), F(1.234567e3)); + test(STR("$1_23_4#567000$$"), loc, STR("{:$^16.6Lf}"), F(1.234567e3)); + test(STR("0001_23_4#567000"), loc, STR("{:016.6Lf}"), F(1.234567e3)); + test(STR("-1_23_4#567000$$$"), loc, STR("{:$<17.6Lf}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#567000"), loc, STR("{:$>17.6Lf}"), F(-1.234567e3)); + test(STR("$-1_23_4#567000$$"), loc, STR("{:$^17.6Lf}"), F(-1.234567e3)); + test(STR("-0001_23_4#567000"), loc, STR("{:017.6Lf}"), F(-1.234567e3)); + } +} + +template +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(STR("1.23457e-06"), STR("{:.6Lg}"), F(1.234567e-6)); + test(STR("1.23457e-05"), STR("{:.6Lg}"), F(1.234567e-5)); + test(STR("0.000123457"), STR("{:.6Lg}"), F(1.234567e-4)); + test(STR("0.00123457"), STR("{:.6Lg}"), F(1.234567e-3)); + test(STR("0.0123457"), STR("{:.6Lg}"), F(1.234567e-2)); + test(STR("0.123457"), STR("{:.6Lg}"), F(1.234567e-1)); + test(STR("1.23457"), STR("{:.6Lg}"), F(1.234567e0)); + test(STR("12.3457"), STR("{:.6Lg}"), F(1.234567e1)); + test(STR("123.457"), STR("{:.6Lg}"), F(1.234567e2)); + test(STR("1,234.57"), STR("{:.6Lg}"), F(1.234567e3)); + test(STR("12,345.7"), STR("{:.6Lg}"), F(1.234567e4)); + test(STR("123,457"), STR("{:.6Lg}"), F(1.234567e5)); + test(STR("1.23457e+06"), STR("{:.6Lg}"), F(1.234567e6)); + test(STR("1.23457e+07"), STR("{:.6Lg}"), F(1.234567e7)); + test(STR("-1.23457e-06"), STR("{:.6Lg}"), F(-1.234567e-6)); + test(STR("-1.23457e-05"), STR("{:.6Lg}"), F(-1.234567e-5)); + test(STR("-0.000123457"), STR("{:.6Lg}"), F(-1.234567e-4)); + test(STR("-0.00123457"), STR("{:.6Lg}"), F(-1.234567e-3)); + test(STR("-0.0123457"), STR("{:.6Lg}"), F(-1.234567e-2)); + test(STR("-0.123457"), STR("{:.6Lg}"), F(-1.234567e-1)); + test(STR("-1.23457"), STR("{:.6Lg}"), F(-1.234567e0)); + test(STR("-12.3457"), STR("{:.6Lg}"), F(-1.234567e1)); + test(STR("-123.457"), STR("{:.6Lg}"), F(-1.234567e2)); + test(STR("-1,234.57"), STR("{:.6Lg}"), F(-1.234567e3)); + test(STR("-12,345.7"), STR("{:.6Lg}"), F(-1.234567e4)); + test(STR("-123,457"), STR("{:.6Lg}"), F(-1.234567e5)); + test(STR("-1.23457e+06"), STR("{:.6Lg}"), F(-1.234567e6)); + test(STR("-1.23457e+07"), STR("{:.6Lg}"), F(-1.234567e7)); + + std::locale::global(loc); + test(STR("1#23457e-06"), STR("{:.6Lg}"), F(1.234567e-6)); + test(STR("1#23457e-05"), STR("{:.6Lg}"), F(1.234567e-5)); + test(STR("0#000123457"), STR("{:.6Lg}"), F(1.234567e-4)); + test(STR("0#00123457"), STR("{:.6Lg}"), F(1.234567e-3)); + test(STR("0#0123457"), STR("{:.6Lg}"), F(1.234567e-2)); + test(STR("0#123457"), STR("{:.6Lg}"), F(1.234567e-1)); + test(STR("1#23457"), STR("{:.6Lg}"), F(1.234567e0)); + test(STR("1_2#3457"), STR("{:.6Lg}"), F(1.234567e1)); + test(STR("12_3#457"), STR("{:.6Lg}"), F(1.234567e2)); + test(STR("1_23_4#57"), STR("{:.6Lg}"), F(1.234567e3)); + test(STR("12_34_5#7"), STR("{:.6Lg}"), F(1.234567e4)); + test(STR("123_45_7"), STR("{:.6Lg}"), F(1.234567e5)); + test(STR("1#23457e+06"), STR("{:.6Lg}"), F(1.234567e6)); + test(STR("1#23457e+07"), STR("{:.6Lg}"), F(1.234567e7)); + test(STR("-1#23457e-06"), STR("{:.6Lg}"), F(-1.234567e-6)); + test(STR("-1#23457e-05"), STR("{:.6Lg}"), F(-1.234567e-5)); + test(STR("-0#000123457"), STR("{:.6Lg}"), F(-1.234567e-4)); + test(STR("-0#00123457"), STR("{:.6Lg}"), F(-1.234567e-3)); + test(STR("-0#0123457"), STR("{:.6Lg}"), F(-1.234567e-2)); + test(STR("-0#123457"), STR("{:.6Lg}"), F(-1.234567e-1)); + test(STR("-1#23457"), STR("{:.6Lg}"), F(-1.234567e0)); + test(STR("-1_2#3457"), STR("{:.6Lg}"), F(-1.234567e1)); + test(STR("-12_3#457"), STR("{:.6Lg}"), F(-1.234567e2)); + test(STR("-1_23_4#57"), STR("{:.6Lg}"), F(-1.234567e3)); + test(STR("-12_34_5#7"), STR("{:.6Lg}"), F(-1.234567e4)); + test(STR("-123_45_7"), STR("{:.6Lg}"), F(-1.234567e5)); + test(STR("-1#23457e+06"), STR("{:.6Lg}"), F(-1.234567e6)); + test(STR("-1#23457e+07"), STR("{:.6Lg}"), F(-1.234567e7)); + + test(STR("1.23457e-06"), en_US, STR("{:.6Lg}"), F(1.234567e-6)); + test(STR("1.23457e-05"), en_US, STR("{:.6Lg}"), F(1.234567e-5)); + test(STR("0.000123457"), en_US, STR("{:.6Lg}"), F(1.234567e-4)); + test(STR("0.00123457"), en_US, STR("{:.6Lg}"), F(1.234567e-3)); + test(STR("0.0123457"), en_US, STR("{:.6Lg}"), F(1.234567e-2)); + test(STR("0.123457"), en_US, STR("{:.6Lg}"), F(1.234567e-1)); + test(STR("1.23457"), en_US, STR("{:.6Lg}"), F(1.234567e0)); + test(STR("12.3457"), en_US, STR("{:.6Lg}"), F(1.234567e1)); + test(STR("123.457"), en_US, STR("{:.6Lg}"), F(1.234567e2)); + test(STR("1,234.57"), en_US, STR("{:.6Lg}"), F(1.234567e3)); + test(STR("12,345.7"), en_US, STR("{:.6Lg}"), F(1.234567e4)); + test(STR("123,457"), en_US, STR("{:.6Lg}"), F(1.234567e5)); + test(STR("1.23457e+06"), en_US, STR("{:.6Lg}"), F(1.234567e6)); + test(STR("1.23457e+07"), en_US, STR("{:.6Lg}"), F(1.234567e7)); + test(STR("-1.23457e-06"), en_US, STR("{:.6Lg}"), F(-1.234567e-6)); + test(STR("-1.23457e-05"), en_US, STR("{:.6Lg}"), F(-1.234567e-5)); + test(STR("-0.000123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-4)); + test(STR("-0.00123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-3)); + test(STR("-0.0123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-2)); + test(STR("-0.123457"), en_US, STR("{:.6Lg}"), F(-1.234567e-1)); + test(STR("-1.23457"), en_US, STR("{:.6Lg}"), F(-1.234567e0)); + test(STR("-12.3457"), en_US, STR("{:.6Lg}"), F(-1.234567e1)); + test(STR("-123.457"), en_US, STR("{:.6Lg}"), F(-1.234567e2)); + test(STR("-1,234.57"), en_US, STR("{:.6Lg}"), F(-1.234567e3)); + test(STR("-12,345.7"), en_US, STR("{:.6Lg}"), F(-1.234567e4)); + test(STR("-123,457"), en_US, STR("{:.6Lg}"), F(-1.234567e5)); + test(STR("-1.23457e+06"), en_US, STR("{:.6Lg}"), F(-1.234567e6)); + test(STR("-1.23457e+07"), en_US, STR("{:.6Lg}"), F(-1.234567e7)); + + std::locale::global(en_US); + test(STR("1#23457e-06"), loc, STR("{:.6Lg}"), F(1.234567e-6)); + test(STR("1#23457e-05"), loc, STR("{:.6Lg}"), F(1.234567e-5)); + test(STR("0#000123457"), loc, STR("{:.6Lg}"), F(1.234567e-4)); + test(STR("0#00123457"), loc, STR("{:.6Lg}"), F(1.234567e-3)); + test(STR("0#0123457"), loc, STR("{:.6Lg}"), F(1.234567e-2)); + test(STR("0#123457"), loc, STR("{:.6Lg}"), F(1.234567e-1)); + test(STR("1#23457"), loc, STR("{:.6Lg}"), F(1.234567e0)); + test(STR("1_2#3457"), loc, STR("{:.6Lg}"), F(1.234567e1)); + test(STR("12_3#457"), loc, STR("{:.6Lg}"), F(1.234567e2)); + test(STR("1_23_4#57"), loc, STR("{:.6Lg}"), F(1.234567e3)); + test(STR("12_34_5#7"), loc, STR("{:.6Lg}"), F(1.234567e4)); + test(STR("123_45_7"), loc, STR("{:.6Lg}"), F(1.234567e5)); + test(STR("1#23457e+06"), loc, STR("{:.6Lg}"), F(1.234567e6)); + test(STR("1#23457e+07"), loc, STR("{:.6Lg}"), F(1.234567e7)); + test(STR("-1#23457e-06"), loc, STR("{:.6Lg}"), F(-1.234567e-6)); + test(STR("-1#23457e-05"), loc, STR("{:.6Lg}"), F(-1.234567e-5)); + test(STR("-0#000123457"), loc, STR("{:.6Lg}"), F(-1.234567e-4)); + test(STR("-0#00123457"), loc, STR("{:.6Lg}"), F(-1.234567e-3)); + test(STR("-0#0123457"), loc, STR("{:.6Lg}"), F(-1.234567e-2)); + test(STR("-0#123457"), loc, STR("{:.6Lg}"), F(-1.234567e-1)); + test(STR("-1#23457"), loc, STR("{:.6Lg}"), F(-1.234567e0)); + test(STR("-1_2#3457"), loc, STR("{:.6Lg}"), F(-1.234567e1)); + test(STR("-12_3#457"), loc, STR("{:.6Lg}"), F(-1.234567e2)); + test(STR("-1_23_4#57"), loc, STR("{:.6Lg}"), F(-1.234567e3)); + test(STR("-12_34_5#7"), loc, STR("{:.6Lg}"), F(-1.234567e4)); + test(STR("-123_45_7"), loc, STR("{:.6Lg}"), F(-1.234567e5)); + test(STR("-1#23457e+06"), loc, STR("{:.6Lg}"), F(-1.234567e6)); + test(STR("-1#23457e+07"), loc, STR("{:.6Lg}"), F(-1.234567e7)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1,234.57$$$"), STR("{:$<11.6Lg}"), F(1.234567e3)); + test(STR("$$$1,234.57"), STR("{:$>11.6Lg}"), F(1.234567e3)); + test(STR("$1,234.57$$"), STR("{:$^11.6Lg}"), F(1.234567e3)); + test(STR("0001,234.57"), STR("{:011.6Lg}"), F(1.234567e3)); + test(STR("-1,234.57$$$"), STR("{:$<12.6Lg}"), F(-1.234567e3)); + test(STR("$$$-1,234.57"), STR("{:$>12.6Lg}"), F(-1.234567e3)); + test(STR("$-1,234.57$$"), STR("{:$^12.6Lg}"), F(-1.234567e3)); + test(STR("-0001,234.57"), STR("{:012.6Lg}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1_23_4#57$$$"), STR("{:$<12.6Lg}"), F(1.234567e3)); + test(STR("$$$1_23_4#57"), STR("{:$>12.6Lg}"), F(1.234567e3)); + test(STR("$1_23_4#57$$"), STR("{:$^12.6Lg}"), F(1.234567e3)); + test(STR("0001_23_4#57"), STR("{:012.6Lg}"), F(1.234567e3)); + test(STR("-1_23_4#57$$$"), STR("{:$<13.6Lg}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#57"), STR("{:$>13.6Lg}"), F(-1.234567e3)); + test(STR("$-1_23_4#57$$"), STR("{:$^13.6Lg}"), F(-1.234567e3)); + test(STR("-0001_23_4#57"), STR("{:013.6Lg}"), F(-1.234567e3)); + + test(STR("1,234.57$$$"), en_US, STR("{:$<11.6Lg}"), F(1.234567e3)); + test(STR("$$$1,234.57"), en_US, STR("{:$>11.6Lg}"), F(1.234567e3)); + test(STR("$1,234.57$$"), en_US, STR("{:$^11.6Lg}"), F(1.234567e3)); + test(STR("0001,234.57"), en_US, STR("{:011.6Lg}"), F(1.234567e3)); + test(STR("-1,234.57$$$"), en_US, STR("{:$<12.6Lg}"), F(-1.234567e3)); + test(STR("$$$-1,234.57"), en_US, STR("{:$>12.6Lg}"), F(-1.234567e3)); + test(STR("$-1,234.57$$"), en_US, STR("{:$^12.6Lg}"), F(-1.234567e3)); + test(STR("-0001,234.57"), en_US, STR("{:012.6Lg}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1_23_4#57$$$"), loc, STR("{:$<12.6Lg}"), F(1.234567e3)); + test(STR("$$$1_23_4#57"), loc, STR("{:$>12.6Lg}"), F(1.234567e3)); + test(STR("$1_23_4#57$$"), loc, STR("{:$^12.6Lg}"), F(1.234567e3)); + test(STR("0001_23_4#57"), loc, STR("{:012.6Lg}"), F(1.234567e3)); + test(STR("-1_23_4#57$$$"), loc, STR("{:$<13.6Lg}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#57"), loc, STR("{:$>13.6Lg}"), F(-1.234567e3)); + test(STR("$-1_23_4#57$$"), loc, STR("{:$^13.6Lg}"), F(-1.234567e3)); + test(STR("-0001_23_4#57"), loc, STR("{:013.6Lg}"), F(-1.234567e3)); +} + +template +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(STR("1.23457E-06"), STR("{:.6LG}"), F(1.234567e-6)); + test(STR("1.23457E-05"), STR("{:.6LG}"), F(1.234567e-5)); + test(STR("0.000123457"), STR("{:.6LG}"), F(1.234567e-4)); + test(STR("0.00123457"), STR("{:.6LG}"), F(1.234567e-3)); + test(STR("0.0123457"), STR("{:.6LG}"), F(1.234567e-2)); + test(STR("0.123457"), STR("{:.6LG}"), F(1.234567e-1)); + test(STR("1.23457"), STR("{:.6LG}"), F(1.234567e0)); + test(STR("12.3457"), STR("{:.6LG}"), F(1.234567e1)); + test(STR("123.457"), STR("{:.6LG}"), F(1.234567e2)); + test(STR("1,234.57"), STR("{:.6LG}"), F(1.234567e3)); + test(STR("12,345.7"), STR("{:.6LG}"), F(1.234567e4)); + test(STR("123,457"), STR("{:.6LG}"), F(1.234567e5)); + test(STR("1.23457E+06"), STR("{:.6LG}"), F(1.234567e6)); + test(STR("1.23457E+07"), STR("{:.6LG}"), F(1.234567e7)); + test(STR("-1.23457E-06"), STR("{:.6LG}"), F(-1.234567e-6)); + test(STR("-1.23457E-05"), STR("{:.6LG}"), F(-1.234567e-5)); + test(STR("-0.000123457"), STR("{:.6LG}"), F(-1.234567e-4)); + test(STR("-0.00123457"), STR("{:.6LG}"), F(-1.234567e-3)); + test(STR("-0.0123457"), STR("{:.6LG}"), F(-1.234567e-2)); + test(STR("-0.123457"), STR("{:.6LG}"), F(-1.234567e-1)); + test(STR("-1.23457"), STR("{:.6LG}"), F(-1.234567e0)); + test(STR("-12.3457"), STR("{:.6LG}"), F(-1.234567e1)); + test(STR("-123.457"), STR("{:.6LG}"), F(-1.234567e2)); + test(STR("-1,234.57"), STR("{:.6LG}"), F(-1.234567e3)); + test(STR("-12,345.7"), STR("{:.6LG}"), F(-1.234567e4)); + test(STR("-123,457"), STR("{:.6LG}"), F(-1.234567e5)); + test(STR("-1.23457E+06"), STR("{:.6LG}"), F(-1.234567e6)); + test(STR("-1.23457E+07"), STR("{:.6LG}"), F(-1.234567e7)); + + std::locale::global(loc); + test(STR("1#23457E-06"), STR("{:.6LG}"), F(1.234567e-6)); + test(STR("1#23457E-05"), STR("{:.6LG}"), F(1.234567e-5)); + test(STR("0#000123457"), STR("{:.6LG}"), F(1.234567e-4)); + test(STR("0#00123457"), STR("{:.6LG}"), F(1.234567e-3)); + test(STR("0#0123457"), STR("{:.6LG}"), F(1.234567e-2)); + test(STR("0#123457"), STR("{:.6LG}"), F(1.234567e-1)); + test(STR("1#23457"), STR("{:.6LG}"), F(1.234567e0)); + test(STR("1_2#3457"), STR("{:.6LG}"), F(1.234567e1)); + test(STR("12_3#457"), STR("{:.6LG}"), F(1.234567e2)); + test(STR("1_23_4#57"), STR("{:.6LG}"), F(1.234567e3)); + test(STR("12_34_5#7"), STR("{:.6LG}"), F(1.234567e4)); + test(STR("123_45_7"), STR("{:.6LG}"), F(1.234567e5)); + test(STR("1#23457E+06"), STR("{:.6LG}"), F(1.234567e6)); + test(STR("1#23457E+07"), STR("{:.6LG}"), F(1.234567e7)); + test(STR("-1#23457E-06"), STR("{:.6LG}"), F(-1.234567e-6)); + test(STR("-1#23457E-05"), STR("{:.6LG}"), F(-1.234567e-5)); + test(STR("-0#000123457"), STR("{:.6LG}"), F(-1.234567e-4)); + test(STR("-0#00123457"), STR("{:.6LG}"), F(-1.234567e-3)); + test(STR("-0#0123457"), STR("{:.6LG}"), F(-1.234567e-2)); + test(STR("-0#123457"), STR("{:.6LG}"), F(-1.234567e-1)); + test(STR("-1#23457"), STR("{:.6LG}"), F(-1.234567e0)); + test(STR("-1_2#3457"), STR("{:.6LG}"), F(-1.234567e1)); + test(STR("-12_3#457"), STR("{:.6LG}"), F(-1.234567e2)); + test(STR("-1_23_4#57"), STR("{:.6LG}"), F(-1.234567e3)); + test(STR("-12_34_5#7"), STR("{:.6LG}"), F(-1.234567e4)); + test(STR("-123_45_7"), STR("{:.6LG}"), F(-1.234567e5)); + test(STR("-1#23457E+06"), STR("{:.6LG}"), F(-1.234567e6)); + test(STR("-1#23457E+07"), STR("{:.6LG}"), F(-1.234567e7)); + + test(STR("1.23457E-06"), en_US, STR("{:.6LG}"), F(1.234567e-6)); + test(STR("1.23457E-05"), en_US, STR("{:.6LG}"), F(1.234567e-5)); + test(STR("0.000123457"), en_US, STR("{:.6LG}"), F(1.234567e-4)); + test(STR("0.00123457"), en_US, STR("{:.6LG}"), F(1.234567e-3)); + test(STR("0.0123457"), en_US, STR("{:.6LG}"), F(1.234567e-2)); + test(STR("0.123457"), en_US, STR("{:.6LG}"), F(1.234567e-1)); + test(STR("1.23457"), en_US, STR("{:.6LG}"), F(1.234567e0)); + test(STR("12.3457"), en_US, STR("{:.6LG}"), F(1.234567e1)); + test(STR("123.457"), en_US, STR("{:.6LG}"), F(1.234567e2)); + test(STR("1,234.57"), en_US, STR("{:.6LG}"), F(1.234567e3)); + test(STR("12,345.7"), en_US, STR("{:.6LG}"), F(1.234567e4)); + test(STR("123,457"), en_US, STR("{:.6LG}"), F(1.234567e5)); + test(STR("1.23457E+06"), en_US, STR("{:.6LG}"), F(1.234567e6)); + test(STR("1.23457E+07"), en_US, STR("{:.6LG}"), F(1.234567e7)); + test(STR("-1.23457E-06"), en_US, STR("{:.6LG}"), F(-1.234567e-6)); + test(STR("-1.23457E-05"), en_US, STR("{:.6LG}"), F(-1.234567e-5)); + test(STR("-0.000123457"), en_US, STR("{:.6LG}"), F(-1.234567e-4)); + test(STR("-0.00123457"), en_US, STR("{:.6LG}"), F(-1.234567e-3)); + test(STR("-0.0123457"), en_US, STR("{:.6LG}"), F(-1.234567e-2)); + test(STR("-0.123457"), en_US, STR("{:.6LG}"), F(-1.234567e-1)); + test(STR("-1.23457"), en_US, STR("{:.6LG}"), F(-1.234567e0)); + test(STR("-12.3457"), en_US, STR("{:.6LG}"), F(-1.234567e1)); + test(STR("-123.457"), en_US, STR("{:.6LG}"), F(-1.234567e2)); + test(STR("-1,234.57"), en_US, STR("{:.6LG}"), F(-1.234567e3)); + test(STR("-12,345.7"), en_US, STR("{:.6LG}"), F(-1.234567e4)); + test(STR("-123,457"), en_US, STR("{:.6LG}"), F(-1.234567e5)); + test(STR("-1.23457E+06"), en_US, STR("{:.6LG}"), F(-1.234567e6)); + test(STR("-1.23457E+07"), en_US, STR("{:.6LG}"), F(-1.234567e7)); + + std::locale::global(en_US); + test(STR("1#23457E-06"), loc, STR("{:.6LG}"), F(1.234567e-6)); + test(STR("1#23457E-05"), loc, STR("{:.6LG}"), F(1.234567e-5)); + test(STR("0#000123457"), loc, STR("{:.6LG}"), F(1.234567e-4)); + test(STR("0#00123457"), loc, STR("{:.6LG}"), F(1.234567e-3)); + test(STR("0#0123457"), loc, STR("{:.6LG}"), F(1.234567e-2)); + test(STR("0#123457"), loc, STR("{:.6LG}"), F(1.234567e-1)); + test(STR("1#23457"), loc, STR("{:.6LG}"), F(1.234567e0)); + test(STR("1_2#3457"), loc, STR("{:.6LG}"), F(1.234567e1)); + test(STR("12_3#457"), loc, STR("{:.6LG}"), F(1.234567e2)); + test(STR("1_23_4#57"), loc, STR("{:.6LG}"), F(1.234567e3)); + test(STR("12_34_5#7"), loc, STR("{:.6LG}"), F(1.234567e4)); + test(STR("123_45_7"), loc, STR("{:.6LG}"), F(1.234567e5)); + test(STR("1#23457E+06"), loc, STR("{:.6LG}"), F(1.234567e6)); + test(STR("1#23457E+07"), loc, STR("{:.6LG}"), F(1.234567e7)); + test(STR("-1#23457E-06"), loc, STR("{:.6LG}"), F(-1.234567e-6)); + test(STR("-1#23457E-05"), loc, STR("{:.6LG}"), F(-1.234567e-5)); + test(STR("-0#000123457"), loc, STR("{:.6LG}"), F(-1.234567e-4)); + test(STR("-0#00123457"), loc, STR("{:.6LG}"), F(-1.234567e-3)); + test(STR("-0#0123457"), loc, STR("{:.6LG}"), F(-1.234567e-2)); + test(STR("-0#123457"), loc, STR("{:.6LG}"), F(-1.234567e-1)); + test(STR("-1#23457"), loc, STR("{:.6LG}"), F(-1.234567e0)); + test(STR("-1_2#3457"), loc, STR("{:.6LG}"), F(-1.234567e1)); + test(STR("-12_3#457"), loc, STR("{:.6LG}"), F(-1.234567e2)); + test(STR("-1_23_4#57"), loc, STR("{:.6LG}"), F(-1.234567e3)); + test(STR("-12_34_5#7"), loc, STR("{:.6LG}"), F(-1.234567e4)); + test(STR("-123_45_7"), loc, STR("{:.6LG}"), F(-1.234567e5)); + test(STR("-1#23457E+06"), loc, STR("{:.6LG}"), F(-1.234567e6)); + test(STR("-1#23457E+07"), loc, STR("{:.6LG}"), F(-1.234567e7)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1,234.57$$$"), STR("{:$<11.6LG}"), F(1.234567e3)); + test(STR("$$$1,234.57"), STR("{:$>11.6LG}"), F(1.234567e3)); + test(STR("$1,234.57$$"), STR("{:$^11.6LG}"), F(1.234567e3)); + test(STR("0001,234.57"), STR("{:011.6LG}"), F(1.234567e3)); + test(STR("-1,234.57$$$"), STR("{:$<12.6LG}"), F(-1.234567e3)); + test(STR("$$$-1,234.57"), STR("{:$>12.6LG}"), F(-1.234567e3)); + test(STR("$-1,234.57$$"), STR("{:$^12.6LG}"), F(-1.234567e3)); + test(STR("-0001,234.57"), STR("{:012.6LG}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1_23_4#57$$$"), STR("{:$<12.6LG}"), F(1.234567e3)); + test(STR("$$$1_23_4#57"), STR("{:$>12.6LG}"), F(1.234567e3)); + test(STR("$1_23_4#57$$"), STR("{:$^12.6LG}"), F(1.234567e3)); + test(STR("0001_23_4#57"), STR("{:012.6LG}"), F(1.234567e3)); + test(STR("-1_23_4#57$$$"), STR("{:$<13.6LG}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#57"), STR("{:$>13.6LG}"), F(-1.234567e3)); + test(STR("$-1_23_4#57$$"), STR("{:$^13.6LG}"), F(-1.234567e3)); + test(STR("-0001_23_4#57"), STR("{:013.6LG}"), F(-1.234567e3)); + + test(STR("1,234.57$$$"), en_US, STR("{:$<11.6LG}"), F(1.234567e3)); + test(STR("$$$1,234.57"), en_US, STR("{:$>11.6LG}"), F(1.234567e3)); + test(STR("$1,234.57$$"), en_US, STR("{:$^11.6LG}"), F(1.234567e3)); + test(STR("0001,234.57"), en_US, STR("{:011.6LG}"), F(1.234567e3)); + test(STR("-1,234.57$$$"), en_US, STR("{:$<12.6LG}"), F(-1.234567e3)); + test(STR("$$$-1,234.57"), en_US, STR("{:$>12.6LG}"), F(-1.234567e3)); + test(STR("$-1,234.57$$"), en_US, STR("{:$^12.6LG}"), F(-1.234567e3)); + test(STR("-0001,234.57"), en_US, STR("{:012.6LG}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1_23_4#57$$$"), loc, STR("{:$<12.6LG}"), F(1.234567e3)); + test(STR("$$$1_23_4#57"), loc, STR("{:$>12.6LG}"), F(1.234567e3)); + test(STR("$1_23_4#57$$"), loc, STR("{:$^12.6LG}"), F(1.234567e3)); + test(STR("0001_23_4#57"), loc, STR("{:012.6LG}"), F(1.234567e3)); + test(STR("-1_23_4#57$$$"), loc, STR("{:$<13.6LG}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#57"), loc, STR("{:$>13.6LG}"), F(-1.234567e3)); + test(STR("$-1_23_4#57$$"), loc, STR("{:$^13.6LG}"), F(-1.234567e3)); + test(STR("-0001_23_4#57"), loc, STR("{:013.6LG}"), F(-1.234567e3)); +} + +template +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(STR("1.234567e-06"), STR("{:L}"), F(1.234567e-6)); + test(STR("1.234567e-05"), STR("{:L}"), F(1.234567e-5)); + test(STR("0.0001234567"), STR("{:L}"), F(1.234567e-4)); + test(STR("0.001234567"), STR("{:L}"), F(1.234567e-3)); + test(STR("0.01234567"), STR("{:L}"), F(1.234567e-2)); + test(STR("0.1234567"), STR("{:L}"), F(1.234567e-1)); + test(STR("1.234567"), STR("{:L}"), F(1.234567e0)); + test(STR("12.34567"), STR("{:L}"), F(1.234567e1)); + test(STR("123.4567"), STR("{:L}"), F(1.234567e2)); + test(STR("1,234.567"), STR("{:L}"), F(1.234567e3)); + test(STR("12,345.67"), STR("{:L}"), F(1.234567e4)); + test(STR("123,456.7"), STR("{:L}"), F(1.234567e5)); + test(STR("1,234,567"), STR("{:L}"), F(1.234567e6)); + test(STR("12,345,670"), STR("{:L}"), F(1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("123,456,700"), STR("{:L}"), F(1.234567e8)); + test(STR("1,234,567,000"), STR("{:L}"), F(1.234567e9)); + test(STR("12,345,670,000"), STR("{:L}"), F(1.234567e10)); + test(STR("123,456,700,000"), STR("{:L}"), F(1.234567e11)); + test(STR("1.234567e+12"), STR("{:L}"), F(1.234567e12)); + test(STR("1.234567e+13"), STR("{:L}"), F(1.234567e13)); + } + test(STR("-1.234567e-06"), STR("{:L}"), F(-1.234567e-6)); + test(STR("-1.234567e-05"), STR("{:L}"), F(-1.234567e-5)); + test(STR("-0.0001234567"), STR("{:L}"), F(-1.234567e-4)); + test(STR("-0.001234567"), STR("{:L}"), F(-1.234567e-3)); + test(STR("-0.01234567"), STR("{:L}"), F(-1.234567e-2)); + test(STR("-0.1234567"), STR("{:L}"), F(-1.234567e-1)); + test(STR("-1.234567"), STR("{:L}"), F(-1.234567e0)); + test(STR("-12.34567"), STR("{:L}"), F(-1.234567e1)); + test(STR("-123.4567"), STR("{:L}"), F(-1.234567e2)); + test(STR("-1,234.567"), STR("{:L}"), F(-1.234567e3)); + test(STR("-12,345.67"), STR("{:L}"), F(-1.234567e4)); + test(STR("-123,456.7"), STR("{:L}"), F(-1.234567e5)); + test(STR("-1,234,567"), STR("{:L}"), F(-1.234567e6)); + test(STR("-12,345,670"), STR("{:L}"), F(-1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-123,456,700"), STR("{:L}"), F(-1.234567e8)); + test(STR("-1,234,567,000"), STR("{:L}"), F(-1.234567e9)); + test(STR("-12,345,670,000"), STR("{:L}"), F(-1.234567e10)); + test(STR("-123,456,700,000"), STR("{:L}"), F(-1.234567e11)); + test(STR("-1.234567e+12"), STR("{:L}"), F(-1.234567e12)); + test(STR("-1.234567e+13"), STR("{:L}"), F(-1.234567e13)); + } + + std::locale::global(loc); + test(STR("1#234567e-06"), STR("{:L}"), F(1.234567e-6)); + test(STR("1#234567e-05"), STR("{:L}"), F(1.234567e-5)); + test(STR("0#0001234567"), STR("{:L}"), F(1.234567e-4)); + test(STR("0#001234567"), STR("{:L}"), F(1.234567e-3)); + test(STR("0#01234567"), STR("{:L}"), F(1.234567e-2)); + test(STR("0#1234567"), STR("{:L}"), F(1.234567e-1)); + test(STR("1#234567"), STR("{:L}"), F(1.234567e0)); + test(STR("1_2#34567"), STR("{:L}"), F(1.234567e1)); + test(STR("12_3#4567"), STR("{:L}"), F(1.234567e2)); + test(STR("1_23_4#567"), STR("{:L}"), F(1.234567e3)); + test(STR("12_34_5#67"), STR("{:L}"), F(1.234567e4)); + test(STR("123_45_6#7"), STR("{:L}"), F(1.234567e5)); + test(STR("1_234_56_7"), STR("{:L}"), F(1.234567e6)); + test(STR("12_345_67_0"), STR("{:L}"), F(1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("1_23_456_70_0"), STR("{:L}"), F(1.234567e8)); + test(STR("1_2_34_567_00_0"), STR("{:L}"), F(1.234567e9)); + test(STR("1_2_3_45_670_00_0"), STR("{:L}"), F(1.234567e10)); + test(STR("1_2_3_4_56_700_00_0"), STR("{:L}"), F(1.234567e11)); + test(STR("1#234567e+12"), STR("{:L}"), F(1.234567e12)); + test(STR("1#234567e+13"), STR("{:L}"), F(1.234567e13)); + } + test(STR("-1#234567e-06"), STR("{:L}"), F(-1.234567e-6)); + test(STR("-1#234567e-05"), STR("{:L}"), F(-1.234567e-5)); + test(STR("-0#0001234567"), STR("{:L}"), F(-1.234567e-4)); + test(STR("-0#001234567"), STR("{:L}"), F(-1.234567e-3)); + test(STR("-0#01234567"), STR("{:L}"), F(-1.234567e-2)); + test(STR("-0#1234567"), STR("{:L}"), F(-1.234567e-1)); + test(STR("-1#234567"), STR("{:L}"), F(-1.234567e0)); + test(STR("-1_2#34567"), STR("{:L}"), F(-1.234567e1)); + test(STR("-12_3#4567"), STR("{:L}"), F(-1.234567e2)); + test(STR("-1_23_4#567"), STR("{:L}"), F(-1.234567e3)); + test(STR("-12_34_5#67"), STR("{:L}"), F(-1.234567e4)); + test(STR("-123_45_6#7"), STR("{:L}"), F(-1.234567e5)); + test(STR("-1_234_56_7"), STR("{:L}"), F(-1.234567e6)); + test(STR("-12_345_67_0"), STR("{:L}"), F(-1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-1_23_456_70_0"), STR("{:L}"), F(-1.234567e8)); + test(STR("-1_2_34_567_00_0"), STR("{:L}"), F(-1.234567e9)); + test(STR("-1_2_3_45_670_00_0"), STR("{:L}"), F(-1.234567e10)); + test(STR("-1_2_3_4_56_700_00_0"), STR("{:L}"), F(-1.234567e11)); + test(STR("-1#234567e+12"), STR("{:L}"), F(-1.234567e12)); + test(STR("-1#234567e+13"), STR("{:L}"), F(-1.234567e13)); + } + + test(STR("1.234567e-06"), en_US, STR("{:L}"), F(1.234567e-6)); + test(STR("1.234567e-05"), en_US, STR("{:L}"), F(1.234567e-5)); + test(STR("0.0001234567"), en_US, STR("{:L}"), F(1.234567e-4)); + test(STR("0.001234567"), en_US, STR("{:L}"), F(1.234567e-3)); + test(STR("0.01234567"), en_US, STR("{:L}"), F(1.234567e-2)); + test(STR("0.1234567"), en_US, STR("{:L}"), F(1.234567e-1)); + test(STR("1.234567"), en_US, STR("{:L}"), F(1.234567e0)); + test(STR("12.34567"), en_US, STR("{:L}"), F(1.234567e1)); + test(STR("123.4567"), en_US, STR("{:L}"), F(1.234567e2)); + test(STR("1,234.567"), en_US, STR("{:L}"), F(1.234567e3)); + test(STR("12,345.67"), en_US, STR("{:L}"), F(1.234567e4)); + test(STR("123,456.7"), en_US, STR("{:L}"), F(1.234567e5)); + test(STR("1,234,567"), en_US, STR("{:L}"), F(1.234567e6)); + test(STR("12,345,670"), en_US, STR("{:L}"), F(1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("123,456,700"), en_US, STR("{:L}"), F(1.234567e8)); + test(STR("1,234,567,000"), en_US, STR("{:L}"), F(1.234567e9)); + test(STR("12,345,670,000"), en_US, STR("{:L}"), F(1.234567e10)); + test(STR("123,456,700,000"), en_US, STR("{:L}"), F(1.234567e11)); + test(STR("1.234567e+12"), en_US, STR("{:L}"), F(1.234567e12)); + test(STR("1.234567e+13"), en_US, STR("{:L}"), F(1.234567e13)); + } + test(STR("-1.234567e-06"), en_US, STR("{:L}"), F(-1.234567e-6)); + test(STR("-1.234567e-05"), en_US, STR("{:L}"), F(-1.234567e-5)); + test(STR("-0.0001234567"), en_US, STR("{:L}"), F(-1.234567e-4)); + test(STR("-0.001234567"), en_US, STR("{:L}"), F(-1.234567e-3)); + test(STR("-0.01234567"), en_US, STR("{:L}"), F(-1.234567e-2)); + test(STR("-0.1234567"), en_US, STR("{:L}"), F(-1.234567e-1)); + test(STR("-1.234567"), en_US, STR("{:L}"), F(-1.234567e0)); + test(STR("-12.34567"), en_US, STR("{:L}"), F(-1.234567e1)); + test(STR("-123.4567"), en_US, STR("{:L}"), F(-1.234567e2)); + test(STR("-1,234.567"), en_US, STR("{:L}"), F(-1.234567e3)); + test(STR("-12,345.67"), en_US, STR("{:L}"), F(-1.234567e4)); + test(STR("-123,456.7"), en_US, STR("{:L}"), F(-1.234567e5)); + test(STR("-1,234,567"), en_US, STR("{:L}"), F(-1.234567e6)); + test(STR("-12,345,670"), en_US, STR("{:L}"), F(-1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-123,456,700"), en_US, STR("{:L}"), F(-1.234567e8)); + test(STR("-1,234,567,000"), en_US, STR("{:L}"), F(-1.234567e9)); + test(STR("-12,345,670,000"), en_US, STR("{:L}"), F(-1.234567e10)); + test(STR("-123,456,700,000"), en_US, STR("{:L}"), F(-1.234567e11)); + test(STR("-1.234567e+12"), en_US, STR("{:L}"), F(-1.234567e12)); + test(STR("-1.234567e+13"), en_US, STR("{:L}"), F(-1.234567e13)); + } + + std::locale::global(en_US); + test(STR("1#234567e-06"), loc, STR("{:L}"), F(1.234567e-6)); + test(STR("1#234567e-05"), loc, STR("{:L}"), F(1.234567e-5)); + test(STR("0#0001234567"), loc, STR("{:L}"), F(1.234567e-4)); + test(STR("0#001234567"), loc, STR("{:L}"), F(1.234567e-3)); + test(STR("0#01234567"), loc, STR("{:L}"), F(1.234567e-2)); + test(STR("0#1234567"), loc, STR("{:L}"), F(1.234567e-1)); + test(STR("1#234567"), loc, STR("{:L}"), F(1.234567e0)); + test(STR("1_2#34567"), loc, STR("{:L}"), F(1.234567e1)); + test(STR("12_3#4567"), loc, STR("{:L}"), F(1.234567e2)); + test(STR("1_23_4#567"), loc, STR("{:L}"), F(1.234567e3)); + test(STR("12_34_5#67"), loc, STR("{:L}"), F(1.234567e4)); + test(STR("123_45_6#7"), loc, STR("{:L}"), F(1.234567e5)); + test(STR("1_234_56_7"), loc, STR("{:L}"), F(1.234567e6)); + test(STR("12_345_67_0"), loc, STR("{:L}"), F(1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("1_23_456_70_0"), loc, STR("{:L}"), F(1.234567e8)); + test(STR("1_2_34_567_00_0"), loc, STR("{:L}"), F(1.234567e9)); + test(STR("1_2_3_45_670_00_0"), loc, STR("{:L}"), F(1.234567e10)); + test(STR("1_2_3_4_56_700_00_0"), loc, STR("{:L}"), F(1.234567e11)); + test(STR("1#234567e+12"), loc, STR("{:L}"), F(1.234567e12)); + test(STR("1#234567e+13"), loc, STR("{:L}"), F(1.234567e13)); + } + test(STR("-1#234567e-06"), loc, STR("{:L}"), F(-1.234567e-6)); + test(STR("-1#234567e-05"), loc, STR("{:L}"), F(-1.234567e-5)); + test(STR("-0#0001234567"), loc, STR("{:L}"), F(-1.234567e-4)); + test(STR("-0#001234567"), loc, STR("{:L}"), F(-1.234567e-3)); + test(STR("-0#01234567"), loc, STR("{:L}"), F(-1.234567e-2)); + test(STR("-0#1234567"), loc, STR("{:L}"), F(-1.234567e-1)); + test(STR("-1#234567"), loc, STR("{:L}"), F(-1.234567e0)); + test(STR("-1_2#34567"), loc, STR("{:L}"), F(-1.234567e1)); + test(STR("-12_3#4567"), loc, STR("{:L}"), F(-1.234567e2)); + test(STR("-1_23_4#567"), loc, STR("{:L}"), F(-1.234567e3)); + test(STR("-12_34_5#67"), loc, STR("{:L}"), F(-1.234567e4)); + test(STR("-123_45_6#7"), loc, STR("{:L}"), F(-1.234567e5)); + test(STR("-1_234_56_7"), loc, STR("{:L}"), F(-1.234567e6)); + test(STR("-12_345_67_0"), loc, STR("{:L}"), F(-1.234567e7)); + if constexpr (sizeof(F) > sizeof(float)) { + test(STR("-1_23_456_70_0"), loc, STR("{:L}"), F(-1.234567e8)); + test(STR("-1_2_34_567_00_0"), loc, STR("{:L}"), F(-1.234567e9)); + test(STR("-1_2_3_45_670_00_0"), loc, STR("{:L}"), F(-1.234567e10)); + test(STR("-1_2_3_4_56_700_00_0"), loc, STR("{:L}"), F(-1.234567e11)); + test(STR("-1#234567e+12"), loc, STR("{:L}"), F(-1.234567e12)); + test(STR("-1#234567e+13"), loc, STR("{:L}"), F(-1.234567e13)); + } + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1,234.567$$$"), STR("{:$<12L}"), F(1.234567e3)); + test(STR("$$$1,234.567"), STR("{:$>12L}"), F(1.234567e3)); + test(STR("$1,234.567$$"), STR("{:$^12L}"), F(1.234567e3)); + test(STR("0001,234.567"), STR("{:012L}"), F(1.234567e3)); + test(STR("-1,234.567$$$"), STR("{:$<13L}"), F(-1.234567e3)); + test(STR("$$$-1,234.567"), STR("{:$>13L}"), F(-1.234567e3)); + test(STR("$-1,234.567$$"), STR("{:$^13L}"), F(-1.234567e3)); + test(STR("-0001,234.567"), STR("{:013L}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1_23_4#567$$$"), STR("{:$<13L}"), F(1.234567e3)); + test(STR("$$$1_23_4#567"), STR("{:$>13L}"), F(1.234567e3)); + test(STR("$1_23_4#567$$"), STR("{:$^13L}"), F(1.234567e3)); + test(STR("0001_23_4#567"), STR("{:013L}"), F(1.234567e3)); + test(STR("-1_23_4#567$$$"), STR("{:$<14L}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#567"), STR("{:$>14L}"), F(-1.234567e3)); + test(STR("$-1_23_4#567$$"), STR("{:$^14L}"), F(-1.234567e3)); + test(STR("-0001_23_4#567"), STR("{:014L}"), F(-1.234567e3)); + + test(STR("1,234.567$$$"), en_US, STR("{:$<12L}"), F(1.234567e3)); + test(STR("$$$1,234.567"), en_US, STR("{:$>12L}"), F(1.234567e3)); + test(STR("$1,234.567$$"), en_US, STR("{:$^12L}"), F(1.234567e3)); + test(STR("0001,234.567"), en_US, STR("{:012L}"), F(1.234567e3)); + test(STR("-1,234.567$$$"), en_US, STR("{:$<13L}"), F(-1.234567e3)); + test(STR("$$$-1,234.567"), en_US, STR("{:$>13L}"), F(-1.234567e3)); + test(STR("$-1,234.567$$"), en_US, STR("{:$^13L}"), F(-1.234567e3)); + test(STR("-0001,234.567"), en_US, STR("{:013L}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1_23_4#567$$$"), loc, STR("{:$<13L}"), F(1.234567e3)); + test(STR("$$$1_23_4#567"), loc, STR("{:$>13L}"), F(1.234567e3)); + test(STR("$1_23_4#567$$"), loc, STR("{:$^13L}"), F(1.234567e3)); + test(STR("0001_23_4#567"), loc, STR("{:013L}"), F(1.234567e3)); + test(STR("-1_23_4#567$$$"), loc, STR("{:$<14L}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#567"), loc, STR("{:$>14L}"), F(-1.234567e3)); + test(STR("$-1_23_4#567$$"), loc, STR("{:$^14L}"), F(-1.234567e3)); + test(STR("-0001_23_4#567"), loc, STR("{:014L}"), F(-1.234567e3)); +} + +template +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(STR("1.23457e-06"), STR("{:.6L}"), F(1.234567e-6)); + test(STR("1.23457e-05"), STR("{:.6L}"), F(1.234567e-5)); + test(STR("0.000123457"), STR("{:.6L}"), F(1.234567e-4)); + test(STR("0.00123457"), STR("{:.6L}"), F(1.234567e-3)); + test(STR("0.0123457"), STR("{:.6L}"), F(1.234567e-2)); + test(STR("0.123457"), STR("{:.6L}"), F(1.234567e-1)); + test(STR("1.23457"), STR("{:.6L}"), F(1.234567e0)); + test(STR("12.3457"), STR("{:.6L}"), F(1.234567e1)); + test(STR("123.457"), STR("{:.6L}"), F(1.234567e2)); + test(STR("1,234.57"), STR("{:.6L}"), F(1.234567e3)); + test(STR("12,345.7"), STR("{:.6L}"), F(1.234567e4)); + test(STR("123,457"), STR("{:.6L}"), F(1.234567e5)); + test(STR("1.23457e+06"), STR("{:.6L}"), F(1.234567e6)); + test(STR("1.23457e+07"), STR("{:.6L}"), F(1.234567e7)); + test(STR("-1.23457e-06"), STR("{:.6L}"), F(-1.234567e-6)); + test(STR("-1.23457e-05"), STR("{:.6L}"), F(-1.234567e-5)); + test(STR("-0.000123457"), STR("{:.6L}"), F(-1.234567e-4)); + test(STR("-0.00123457"), STR("{:.6L}"), F(-1.234567e-3)); + test(STR("-0.0123457"), STR("{:.6L}"), F(-1.234567e-2)); + test(STR("-0.123457"), STR("{:.6L}"), F(-1.234567e-1)); + test(STR("-1.23457"), STR("{:.6L}"), F(-1.234567e0)); + test(STR("-12.3457"), STR("{:.6L}"), F(-1.234567e1)); + test(STR("-123.457"), STR("{:.6L}"), F(-1.234567e2)); + test(STR("-1,234.57"), STR("{:.6L}"), F(-1.234567e3)); + test(STR("-12,345.7"), STR("{:.6L}"), F(-1.234567e4)); + test(STR("-123,457"), STR("{:.6L}"), F(-1.234567e5)); + test(STR("-1.23457e+06"), STR("{:.6L}"), F(-1.234567e6)); + test(STR("-1.23457e+07"), STR("{:.6L}"), F(-1.234567e7)); + + std::locale::global(loc); + test(STR("1#23457e-06"), STR("{:.6L}"), F(1.234567e-6)); + test(STR("1#23457e-05"), STR("{:.6L}"), F(1.234567e-5)); + test(STR("0#000123457"), STR("{:.6L}"), F(1.234567e-4)); + test(STR("0#00123457"), STR("{:.6L}"), F(1.234567e-3)); + test(STR("0#0123457"), STR("{:.6L}"), F(1.234567e-2)); + test(STR("0#123457"), STR("{:.6L}"), F(1.234567e-1)); + test(STR("1#23457"), STR("{:.6L}"), F(1.234567e0)); + test(STR("1_2#3457"), STR("{:.6L}"), F(1.234567e1)); + test(STR("12_3#457"), STR("{:.6L}"), F(1.234567e2)); + test(STR("1_23_4#57"), STR("{:.6L}"), F(1.234567e3)); + test(STR("12_34_5#7"), STR("{:.6L}"), F(1.234567e4)); + test(STR("123_45_7"), STR("{:.6L}"), F(1.234567e5)); + test(STR("1#23457e+06"), STR("{:.6L}"), F(1.234567e6)); + test(STR("1#23457e+07"), STR("{:.6L}"), F(1.234567e7)); + test(STR("-1#23457e-06"), STR("{:.6L}"), F(-1.234567e-6)); + test(STR("-1#23457e-05"), STR("{:.6L}"), F(-1.234567e-5)); + test(STR("-0#000123457"), STR("{:.6L}"), F(-1.234567e-4)); + test(STR("-0#00123457"), STR("{:.6L}"), F(-1.234567e-3)); + test(STR("-0#0123457"), STR("{:.6L}"), F(-1.234567e-2)); + test(STR("-0#123457"), STR("{:.6L}"), F(-1.234567e-1)); + test(STR("-1#23457"), STR("{:.6L}"), F(-1.234567e0)); + test(STR("-1_2#3457"), STR("{:.6L}"), F(-1.234567e1)); + test(STR("-12_3#457"), STR("{:.6L}"), F(-1.234567e2)); + test(STR("-1_23_4#57"), STR("{:.6L}"), F(-1.234567e3)); + test(STR("-12_34_5#7"), STR("{:.6L}"), F(-1.234567e4)); + test(STR("-123_45_7"), STR("{:.6L}"), F(-1.234567e5)); + test(STR("-1#23457e+06"), STR("{:.6L}"), F(-1.234567e6)); + test(STR("-1#23457e+07"), STR("{:.6L}"), F(-1.234567e7)); + + test(STR("1.23457e-06"), en_US, STR("{:.6L}"), F(1.234567e-6)); + test(STR("1.23457e-05"), en_US, STR("{:.6L}"), F(1.234567e-5)); + test(STR("0.000123457"), en_US, STR("{:.6L}"), F(1.234567e-4)); + test(STR("0.00123457"), en_US, STR("{:.6L}"), F(1.234567e-3)); + test(STR("0.0123457"), en_US, STR("{:.6L}"), F(1.234567e-2)); + test(STR("0.123457"), en_US, STR("{:.6L}"), F(1.234567e-1)); + test(STR("1.23457"), en_US, STR("{:.6L}"), F(1.234567e0)); + test(STR("12.3457"), en_US, STR("{:.6L}"), F(1.234567e1)); + test(STR("123.457"), en_US, STR("{:.6L}"), F(1.234567e2)); + test(STR("1,234.57"), en_US, STR("{:.6L}"), F(1.234567e3)); + test(STR("12,345.7"), en_US, STR("{:.6L}"), F(1.234567e4)); + test(STR("123,457"), en_US, STR("{:.6L}"), F(1.234567e5)); + test(STR("1.23457e+06"), en_US, STR("{:.6L}"), F(1.234567e6)); + test(STR("1.23457e+07"), en_US, STR("{:.6L}"), F(1.234567e7)); + test(STR("-1.23457e-06"), en_US, STR("{:.6L}"), F(-1.234567e-6)); + test(STR("-1.23457e-05"), en_US, STR("{:.6L}"), F(-1.234567e-5)); + test(STR("-0.000123457"), en_US, STR("{:.6L}"), F(-1.234567e-4)); + test(STR("-0.00123457"), en_US, STR("{:.6L}"), F(-1.234567e-3)); + test(STR("-0.0123457"), en_US, STR("{:.6L}"), F(-1.234567e-2)); + test(STR("-0.123457"), en_US, STR("{:.6L}"), F(-1.234567e-1)); + test(STR("-1.23457"), en_US, STR("{:.6L}"), F(-1.234567e0)); + test(STR("-12.3457"), en_US, STR("{:.6L}"), F(-1.234567e1)); + test(STR("-123.457"), en_US, STR("{:.6L}"), F(-1.234567e2)); + test(STR("-1,234.57"), en_US, STR("{:.6L}"), F(-1.234567e3)); + test(STR("-12,345.7"), en_US, STR("{:.6L}"), F(-1.234567e4)); + test(STR("-123,457"), en_US, STR("{:.6L}"), F(-1.234567e5)); + test(STR("-1.23457e+06"), en_US, STR("{:.6L}"), F(-1.234567e6)); + test(STR("-1.23457e+07"), en_US, STR("{:.6L}"), F(-1.234567e7)); + + std::locale::global(en_US); + test(STR("1#23457e-06"), loc, STR("{:.6L}"), F(1.234567e-6)); + test(STR("1#23457e-05"), loc, STR("{:.6L}"), F(1.234567e-5)); + test(STR("0#000123457"), loc, STR("{:.6L}"), F(1.234567e-4)); + test(STR("0#00123457"), loc, STR("{:.6L}"), F(1.234567e-3)); + test(STR("0#0123457"), loc, STR("{:.6L}"), F(1.234567e-2)); + test(STR("0#123457"), loc, STR("{:.6L}"), F(1.234567e-1)); + test(STR("1#23457"), loc, STR("{:.6L}"), F(1.234567e0)); + test(STR("1_2#3457"), loc, STR("{:.6L}"), F(1.234567e1)); + test(STR("12_3#457"), loc, STR("{:.6L}"), F(1.234567e2)); + test(STR("1_23_4#57"), loc, STR("{:.6L}"), F(1.234567e3)); + test(STR("12_34_5#7"), loc, STR("{:.6L}"), F(1.234567e4)); + test(STR("123_45_7"), loc, STR("{:.6L}"), F(1.234567e5)); + test(STR("1#23457e+06"), loc, STR("{:.6L}"), F(1.234567e6)); + test(STR("1#23457e+07"), loc, STR("{:.6L}"), F(1.234567e7)); + test(STR("-1#23457e-06"), loc, STR("{:.6L}"), F(-1.234567e-6)); + test(STR("-1#23457e-05"), loc, STR("{:.6L}"), F(-1.234567e-5)); + test(STR("-0#000123457"), loc, STR("{:.6L}"), F(-1.234567e-4)); + test(STR("-0#00123457"), loc, STR("{:.6L}"), F(-1.234567e-3)); + test(STR("-0#0123457"), loc, STR("{:.6L}"), F(-1.234567e-2)); + test(STR("-0#123457"), loc, STR("{:.6L}"), F(-1.234567e-1)); + test(STR("-1#23457"), loc, STR("{:.6L}"), F(-1.234567e0)); + test(STR("-1_2#3457"), loc, STR("{:.6L}"), F(-1.234567e1)); + test(STR("-12_3#457"), loc, STR("{:.6L}"), F(-1.234567e2)); + test(STR("-1_23_4#57"), loc, STR("{:.6L}"), F(-1.234567e3)); + test(STR("-12_34_5#7"), loc, STR("{:.6L}"), F(-1.234567e4)); + test(STR("-123_45_7"), loc, STR("{:.6L}"), F(-1.234567e5)); + test(STR("-1#23457e+06"), loc, STR("{:.6L}"), F(-1.234567e6)); + test(STR("-1#23457e+07"), loc, STR("{:.6L}"), F(-1.234567e7)); + + // *** Fill, align, zero padding *** + std::locale::global(en_US); + test(STR("1,234.57$$$"), STR("{:$<11.6L}"), F(1.234567e3)); + test(STR("$$$1,234.57"), STR("{:$>11.6L}"), F(1.234567e3)); + test(STR("$1,234.57$$"), STR("{:$^11.6L}"), F(1.234567e3)); + test(STR("0001,234.57"), STR("{:011.6L}"), F(1.234567e3)); + test(STR("-1,234.57$$$"), STR("{:$<12.6L}"), F(-1.234567e3)); + test(STR("$$$-1,234.57"), STR("{:$>12.6L}"), F(-1.234567e3)); + test(STR("$-1,234.57$$"), STR("{:$^12.6L}"), F(-1.234567e3)); + test(STR("-0001,234.57"), STR("{:012.6L}"), F(-1.234567e3)); + + std::locale::global(loc); + test(STR("1_23_4#57$$$"), STR("{:$<12.6L}"), F(1.234567e3)); + test(STR("$$$1_23_4#57"), STR("{:$>12.6L}"), F(1.234567e3)); + test(STR("$1_23_4#57$$"), STR("{:$^12.6L}"), F(1.234567e3)); + test(STR("0001_23_4#57"), STR("{:012.6L}"), F(1.234567e3)); + test(STR("-1_23_4#57$$$"), STR("{:$<13.6L}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#57"), STR("{:$>13.6L}"), F(-1.234567e3)); + test(STR("$-1_23_4#57$$"), STR("{:$^13.6L}"), F(-1.234567e3)); + test(STR("-0001_23_4#57"), STR("{:013.6L}"), F(-1.234567e3)); + + test(STR("1,234.57$$$"), en_US, STR("{:$<11.6L}"), F(1.234567e3)); + test(STR("$$$1,234.57"), en_US, STR("{:$>11.6L}"), F(1.234567e3)); + test(STR("$1,234.57$$"), en_US, STR("{:$^11.6L}"), F(1.234567e3)); + test(STR("0001,234.57"), en_US, STR("{:011.6L}"), F(1.234567e3)); + test(STR("-1,234.57$$$"), en_US, STR("{:$<12.6L}"), F(-1.234567e3)); + test(STR("$$$-1,234.57"), en_US, STR("{:$>12.6L}"), F(-1.234567e3)); + test(STR("$-1,234.57$$"), en_US, STR("{:$^12.6L}"), F(-1.234567e3)); + test(STR("-0001,234.57"), en_US, STR("{:012.6L}"), F(-1.234567e3)); + + std::locale::global(en_US); + test(STR("1_23_4#57$$$"), loc, STR("{:$<12.6L}"), F(1.234567e3)); + test(STR("$$$1_23_4#57"), loc, STR("{:$>12.6L}"), F(1.234567e3)); + test(STR("$1_23_4#57$$"), loc, STR("{:$^12.6L}"), F(1.234567e3)); + test(STR("0001_23_4#57"), loc, STR("{:012.6L}"), F(1.234567e3)); + test(STR("-1_23_4#57$$$"), loc, STR("{:$<13.6L}"), F(-1.234567e3)); + test(STR("$$$-1_23_4#57"), loc, STR("{:$>13.6L}"), F(-1.234567e3)); + test(STR("$-1_23_4#57$$"), loc, STR("{:$^13.6L}"), F(-1.234567e3)); + test(STR("-0001_23_4#57"), loc, STR("{:013.6L}"), F(-1.234567e3)); +} + +template +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(); +} + template void test() { test_bool(); test_integer(); + test_floating_point(); + test_floating_point(); + test_floating_point(); } int main(int, char**) {