aboutsummaryrefslogtreecommitdiff
path: root/libcxx/include/__format/formatter_floating_point.h
diff options
context:
space:
mode:
Diffstat (limited to 'libcxx/include/__format/formatter_floating_point.h')
-rw-r--r--libcxx/include/__format/formatter_floating_point.h108
1 files changed, 72 insertions, 36 deletions
diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h
index 90a76193196e..a544b53f7e6d 100644
--- a/libcxx/include/__format/formatter_floating_point.h
+++ b/libcxx/include/__format/formatter_floating_point.h
@@ -10,17 +10,16 @@
#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/max.h>
#include <__algorithm/min.h>
#include <__algorithm/rotate.h>
#include <__algorithm/transform.h>
#include <__concepts/arithmetic.h>
#include <__concepts/same_as.h>
#include <__config>
-#include <__format/format_fwd.h>
+#include <__format/concepts.h>
#include <__format/format_parse_context.h>
#include <__format/formatter.h>
#include <__format/formatter_integral.h>
@@ -103,7 +102,7 @@ template <class _Tp>
struct __traits;
template <floating_point _Fp>
-static constexpr size_t __float_buffer_size(int __precision) {
+_LIBCPP_HIDE_FROM_ABI constexpr size_t __float_buffer_size(int __precision) {
using _Traits = __traits<_Fp>;
return 4 + _Traits::__max_integral + __precision + _Traits::__max_fractional_value;
}
@@ -183,6 +182,7 @@ public:
_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; }
+ _LIBCPP_HIDE_FROM_ABI void __add_trailing_zeros(int __zeros) { __num_trailing_zeros_ += __zeros; }
private:
int __precision_;
@@ -216,7 +216,7 @@ struct __float_result {
/// \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) {
+ if (__size >= 4) {
__first = __last - _VSTD::min(__size, ptrdiff_t(6));
for (; __first != __last - 3; ++__first) {
if (*__first == 'e')
@@ -404,6 +404,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_general_lower_case(__float_
// 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, '.');
}
}
@@ -454,7 +455,10 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer(
char* __first = __formatter::__insert_sign(__buffer.begin(), __negative, __sign);
switch (__type) {
case __format_spec::__type::__default:
- return __formatter::__format_buffer_default(__buffer, __value, __first);
+ if (__has_precision)
+ return __formatter::__format_buffer_general_lower_case(__buffer, __value, __buffer.__precision(), __first);
+ else
+ return __formatter::__format_buffer_default(__buffer, __value, __first);
case __format_spec::__type::__hexfloat_lower_case:
return __formatter::__format_buffer_hexadecimal_lower_case(
@@ -494,7 +498,7 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
const __float_result& __result,
_VSTD::locale __loc,
__format_spec::__parsed_specifications<_CharT> __specs) {
- const auto& __np = use_facet<numpunct<_CharT>>(__loc);
+ const auto& __np = std::use_facet<numpunct<_CharT>>(__loc);
string __grouping = __np.grouping();
char* __first = __result.__integral;
// When no radix point or exponent are present __last will be __result.__last.
@@ -528,13 +532,13 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
// 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_, __specs.__fill_);
+ __out_it = __formatter::__fill(_VSTD::move(__out_it), __padding.__before_, __specs.__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));
+ __out_it = __formatter::__copy(__first, __digits, _VSTD::move(__out_it));
} else {
auto __r = __grouping.rbegin();
auto __e = __grouping.rend() - 1;
@@ -546,7 +550,7 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
// 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));
+ __out_it = __formatter::__copy(__first, *__r, _VSTD::move(__out_it));
__first += *__r;
if (__r == __e)
@@ -560,16 +564,16 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __format_locale_specific_form(
// 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'));
+ __out_it = __formatter::__copy(__result.__radix_point + 1, __result.__exponent, _VSTD::move(__out_it));
+ __out_it = __formatter::__fill(_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));
+ __out_it = __formatter::__copy(__result.__exponent, __result.__last, _VSTD::move(__out_it));
// alignment
- return _VSTD::fill_n(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
+ return __formatter::__fill(_VSTD::move(__out_it), __padding.__after_, __specs.__fill_);
}
# endif // _LIBCPP_HAS_NO_LOCALIZATION
@@ -625,20 +629,51 @@ __format_floating_point(_Tp __value, auto& __ctx, __format_spec::__parsed_specif
__float_result __result = __formatter::__format_buffer(
__buffer, __value, __negative, (__specs.__has_precision()), __specs.__std_.__sign_, __specs.__std_.__type_);
- if (__specs.__std_.__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;
+ if (__specs.__std_.__alternate_form_) {
+ if (__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;
+ }
- // 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;
+ // [format.string.std]/6
+ // In addition, for g and G conversions, trailing zeros are not removed
+ // from the result.
+ //
+ // If the type option for a floating-point type is none it may use the
+ // general formatting, but it's not a g or G conversion. So in that case
+ // the formatting should not append trailing zeros.
+ bool __is_general = __specs.__std_.__type_ == __format_spec::__type::__general_lower_case ||
+ __specs.__std_.__type_ == __format_spec::__type::__general_upper_case;
+
+ if (__is_general) {
+ // https://en.cppreference.com/w/c/io/fprintf
+ // Let P equal the precision if nonzero, 6 if the precision is not
+ // specified, or 1 if the precision is 0. Then, if a conversion with
+ // style E would have an exponent of X:
+ int __p = _VSTD::max(1, (__specs.__has_precision() ? __specs.__precision_ : 6));
+ if (__result.__exponent == __result.__last)
+ // if P > X >= -4, the conversion is with style f or F and precision P - 1 - X.
+ // By including the radix point it calculates P - (1 + X)
+ __p -= __result.__radix_point - __buffer.begin();
+ else
+ // otherwise, the conversion is with style e or E and precision P - 1.
+ --__p;
+
+ ptrdiff_t __precision = (__result.__exponent - __result.__radix_point) - 1;
+ if (__precision < __p)
+ __buffer.__add_trailing_zeros(__p - __precision);
+ }
}
# ifndef _LIBCPP_HAS_NO_LOCALIZATION
@@ -651,14 +686,15 @@ __format_floating_point(_Tp __value, auto& __ctx, __format_spec::__parsed_specif
if (__size + __num_trailing_zeros >= __specs.__width_) {
if (__num_trailing_zeros && __result.__exponent != __result.__last)
// Insert trailing zeros before exponent character.
- return _VSTD::copy(
+ return __formatter::__copy(
__result.__exponent,
__result.__last,
- _VSTD::fill_n(
- _VSTD::copy(__buffer.begin(), __result.__exponent, __ctx.out()), __num_trailing_zeros, _CharT('0')));
+ __formatter::__fill(__formatter::__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'));
+ return __formatter::__fill(
+ __formatter::__copy(__buffer.begin(), __result.__last, __ctx.out()), __num_trailing_zeros, _CharT('0'));
}
auto __out_it = __ctx.out();
@@ -684,7 +720,7 @@ __format_floating_point(_Tp __value, auto& __ctx, __format_spec::__parsed_specif
} // namespace __formatter
-template <__formatter::__char_type _CharT>
+template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS __formatter_floating_point {
public:
_LIBCPP_HIDE_FROM_ABI constexpr auto
@@ -702,13 +738,13 @@ public:
__format_spec::__parser<_CharT> __parser_;
};
-template <__formatter::__char_type _CharT>
+template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<float, _CharT>
: public __formatter_floating_point<_CharT> {};
-template <__formatter::__char_type _CharT>
+template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<double, _CharT>
: public __formatter_floating_point<_CharT> {};
-template <__formatter::__char_type _CharT>
+template <__fmt_char_type _CharT>
struct _LIBCPP_TEMPLATE_VIS _LIBCPP_AVAILABILITY_FORMAT formatter<long double, _CharT>
: public __formatter_floating_point<_CharT> {};