Integrate Grisu and sprintf digit generators

This commit is contained in:
Victor Zverovich
2019-11-23 06:22:30 -08:00
parent 7395472dde
commit 4cf59ce734
4 changed files with 53 additions and 58 deletions

View File

@@ -1076,6 +1076,7 @@ struct float_spec {
bool percent;
bool alt;
bool binary32;
bool use_grisu;
};
struct gen_digits_params {
@@ -1208,25 +1209,15 @@ template <typename Char> class float_writer {
}
};
// Formats value using the Grisu algorithm:
// https://www.cs.tufts.edu/~nr/cs257/archive/florian-loitsch/printf.pdf
template <typename Float, FMT_ENABLE_IF(sizeof(Float) == sizeof(uint64_t))>
FMT_API bool grisu_format(Float, int, buffer<char>&, float_spec, int&);
template <typename Float, FMT_ENABLE_IF(sizeof(Float) != sizeof(uint64_t))>
inline bool grisu_format(Float, int, buffer<char>&, float_spec, int&) {
return false;
}
template <typename T>
int format_float(T value, int precision, float_spec spec, buffer<char>& buf);
template <typename Float>
int sprintf_format(Float value, int precision, float_spec spec,
buffer<char>& buf);
// Formats a floating-point number with snprintf.
template <typename T>
int snprintf_float(T value, int precision, float_spec spec, buffer<char>& buf);
template <>
inline int sprintf_format<float>(float value, int precision, float_spec spec,
buffer<char>& buf) {
// sprintf does not support float so convert to double.
return sprintf_format<double>(value, precision, spec, buf);
}
template <typename T> T promote_float(T value) { return value; }
inline double promote_float(float value) { return value; }
template <typename Handler>
FMT_CONSTEXPR void handle_int_type_spec(char spec, Handler&& handler) {
@@ -1715,7 +1706,9 @@ template <typename Range> class basic_writer {
return write_padded(specs, inf_or_nan_writer<char_type>{sign, str});
}
if (specs.align == align::numeric) {
if (specs.align == align::none) {
specs.align = align::right;
} else if (specs.align == align::numeric) {
if (sign) {
auto&& it = reserve(1);
*it++ = static_cast<char_type>(data::signs[sign]);
@@ -1723,28 +1716,22 @@ template <typename Range> class basic_writer {
if (specs.width != 0) --specs.width;
}
specs.align = align::right;
} else if (specs.align == align::none) {
specs.align = align::right;
}
memory_buffer buffer;
if (fspec.format == float_format::hex) {
if (sign) buffer.push_back(data::signs[sign]);
fspec.alt = specs.alt;
sprintf_format(value, specs.precision, fspec, buffer);
snprintf_float(promote_float(value), specs.precision, fspec, buffer);
write_padded(specs, str_writer<char>{buffer.data(), buffer.size()});
return;
}
int precision = specs.precision >= 0 || !specs.type ? specs.precision : 6;
if (fspec.format == float_format::exp) ++precision;
if (const_check(std::is_same<T, float>())) fspec.binary32 = true;
fspec.use_grisu = use_grisu<T>();
if (const_check(FMT_DEPRECATED_PERCENT) && fspec.percent) value *= 100;
int exp = 0;
bool use_grisu =
internal::use_grisu<T>() &&
grisu_format(static_cast<double>(value), precision, buffer, fspec, exp);
if (!use_grisu) exp = sprintf_format(value, precision, fspec, buffer);
int exp = format_float(promote_float(value), precision, fspec, buffer);
if (const_check(FMT_DEPRECATED_PERCENT) && fspec.percent) {
buffer.push_back('%');
--exp; // Adjust decimal place position.