mirror of
https://github.com/fmtlib/fmt.git
synced 2024-12-25 15:21:54 +00:00
Simplify snprintf_float
This commit is contained in:
parent
440512f08d
commit
f5cdf7cb04
@ -1373,34 +1373,26 @@ FMT_API auto fmt_snprintf(char* buf, size_t size, const char* fmt, ...) -> int;
|
||||
# define FMT_SNPRINTF fmt_snprintf
|
||||
#endif // _MSC_VER
|
||||
|
||||
// Formats a floating-point number with snprintf.
|
||||
// Formats a floating-point number with snprintf using the hexfloat format.
|
||||
template <typename T>
|
||||
auto snprintf_float(T value, int precision, float_specs specs,
|
||||
buffer<char>& buf) -> int {
|
||||
// Buffer capacity must be non-zero, otherwise MSVC's vsnprintf_s will fail.
|
||||
FMT_ASSERT(buf.capacity() > buf.size(), "empty buffer");
|
||||
FMT_ASSERT(specs.format == float_format::hex, "");
|
||||
static_assert(!std::is_same<T, float>::value, "");
|
||||
|
||||
// Subtract 1 to account for the difference in precision since we use %e for
|
||||
// both general and exponent format.
|
||||
if (specs.format == float_format::general ||
|
||||
specs.format == float_format::exp) {
|
||||
precision = (precision >= 0 ? precision : 6) - 1;
|
||||
}
|
||||
|
||||
// Build the format string.
|
||||
char format[7]; // The longest format is "%#.*Le".
|
||||
char* format_ptr = format;
|
||||
*format_ptr++ = '%';
|
||||
if (specs.showpoint && specs.format == float_format::hex) *format_ptr++ = '#';
|
||||
if (specs.showpoint) *format_ptr++ = '#';
|
||||
if (precision >= 0) {
|
||||
*format_ptr++ = '.';
|
||||
*format_ptr++ = '*';
|
||||
}
|
||||
if (std::is_same<T, long double>()) *format_ptr++ = 'L';
|
||||
*format_ptr++ = specs.format != float_format::hex
|
||||
? (specs.format == float_format::fixed ? 'f' : 'e')
|
||||
: (specs.upper ? 'A' : 'a');
|
||||
*format_ptr++ = specs.upper ? 'A' : 'a';
|
||||
*format_ptr = '\0';
|
||||
|
||||
// Format using snprintf.
|
||||
@ -1422,55 +1414,11 @@ auto snprintf_float(T value, int precision, float_specs specs,
|
||||
}
|
||||
auto size = to_unsigned(result);
|
||||
// Size equal to capacity means that the last character was truncated.
|
||||
if (size >= capacity) {
|
||||
buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'.
|
||||
continue;
|
||||
}
|
||||
auto is_digit = [](char c) { return c >= '0' && c <= '9'; };
|
||||
if (specs.format == float_format::fixed) {
|
||||
if (precision == 0) {
|
||||
buf.try_resize(size);
|
||||
return 0;
|
||||
}
|
||||
// Find and remove the decimal point.
|
||||
auto end = begin + size, p = end;
|
||||
do {
|
||||
--p;
|
||||
} while (is_digit(*p));
|
||||
int fraction_size = static_cast<int>(end - p - 1);
|
||||
std::memmove(p, p + 1, to_unsigned(fraction_size));
|
||||
buf.try_resize(size - 1);
|
||||
return -fraction_size;
|
||||
}
|
||||
if (specs.format == float_format::hex) {
|
||||
if (size < capacity) {
|
||||
buf.try_resize(size + offset);
|
||||
return 0;
|
||||
}
|
||||
// Find and parse the exponent.
|
||||
auto end = begin + size, exp_pos = end;
|
||||
do {
|
||||
--exp_pos;
|
||||
} while (*exp_pos != 'e');
|
||||
char sign = exp_pos[1];
|
||||
FMT_ASSERT(sign == '+' || sign == '-', "");
|
||||
int exp = 0;
|
||||
auto p = exp_pos + 2; // Skip 'e' and sign.
|
||||
do {
|
||||
FMT_ASSERT(is_digit(*p), "");
|
||||
exp = exp * 10 + (*p++ - '0');
|
||||
} while (p != end);
|
||||
if (sign == '-') exp = -exp;
|
||||
int fraction_size = 0;
|
||||
if (exp_pos != begin + 1) {
|
||||
// Remove trailing zeros.
|
||||
auto fraction_end = exp_pos - 1;
|
||||
while (*fraction_end == '0') --fraction_end;
|
||||
// Move the fractional part left to get rid of the decimal point.
|
||||
fraction_size = static_cast<int>(fraction_end - begin - 1);
|
||||
std::memmove(begin + 1, begin + 2, to_unsigned(fraction_size));
|
||||
}
|
||||
buf.try_resize(to_unsigned(fraction_size) + offset + 1);
|
||||
return exp - fraction_size;
|
||||
buf.try_reserve(size + offset + 1); // Add 1 for the terminating '\0'.
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user