Simplify grisu_writer
This commit is contained in:
parent
7aa58c30bf
commit
b7a157401e
@ -1028,6 +1028,14 @@ using format_specs = basic_format_specs<char>;
|
|||||||
|
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
|
struct gen_digits_params {
|
||||||
|
int num_digits;
|
||||||
|
sign_t sign : 3;
|
||||||
|
bool fixed;
|
||||||
|
bool upper;
|
||||||
|
bool trailing_zeros;
|
||||||
|
};
|
||||||
|
|
||||||
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
// Writes the exponent exp in the form "[+-]d{2,3}" to buffer.
|
||||||
template <typename Char, typename It> It write_exponent(int exp, It it) {
|
template <typename Char, typename It> It write_exponent(int exp, It it) {
|
||||||
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
FMT_ASSERT(-1000 < exp && exp < 1000, "exponent out of range");
|
||||||
@ -1047,79 +1055,9 @@ template <typename Char, typename It> It write_exponent(int exp, It it) {
|
|||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct gen_digits_params {
|
|
||||||
int num_digits;
|
|
||||||
sign_t sign : 3;
|
|
||||||
bool fixed;
|
|
||||||
bool upper;
|
|
||||||
bool trailing_zeros;
|
|
||||||
};
|
|
||||||
|
|
||||||
// The number is given as v = digits * pow(10, exp).
|
|
||||||
template <typename Char, typename It>
|
|
||||||
It grisu_prettify(const char* digits, int size, int exp, It it,
|
|
||||||
gen_digits_params params, Char decimal_point) {
|
|
||||||
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
|
||||||
int full_exp = size + exp;
|
|
||||||
if (!params.fixed) {
|
|
||||||
// Insert a decimal point after the first digit and add an exponent.
|
|
||||||
*it++ = static_cast<Char>(*digits);
|
|
||||||
if (size > 1) *it++ = decimal_point;
|
|
||||||
exp += size - 1;
|
|
||||||
it = copy_str<Char>(digits + 1, digits + size, it);
|
|
||||||
if (size < params.num_digits)
|
|
||||||
it = std::fill_n(it, params.num_digits - size, static_cast<Char>('0'));
|
|
||||||
*it++ = static_cast<Char>(params.upper ? 'E' : 'e');
|
|
||||||
return write_exponent<Char>(exp, it);
|
|
||||||
}
|
|
||||||
if (size <= full_exp) {
|
|
||||||
// 1234e7 -> 12340000000[.0+]
|
|
||||||
it = copy_str<Char>(digits, digits + size, it);
|
|
||||||
it = std::fill_n(it, full_exp - size, static_cast<Char>('0'));
|
|
||||||
int num_zeros = (std::max)(params.num_digits - full_exp, 1);
|
|
||||||
if (params.trailing_zeros) {
|
|
||||||
*it++ = decimal_point;
|
|
||||||
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
|
||||||
if (num_zeros > 1000)
|
|
||||||
throw std::runtime_error("fuzz mode - avoiding excessive cpu use");
|
|
||||||
#endif
|
|
||||||
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
|
||||||
}
|
|
||||||
} else if (full_exp > 0) {
|
|
||||||
// 1234e-2 -> 12.34[0+]
|
|
||||||
it = copy_str<Char>(digits, digits + full_exp, it);
|
|
||||||
if (!params.trailing_zeros) {
|
|
||||||
// Remove trailing zeros.
|
|
||||||
while (size > full_exp && digits[size - 1] == '0') --size;
|
|
||||||
if (size != full_exp) *it++ = decimal_point;
|
|
||||||
return copy_str<Char>(digits + full_exp, digits + size, it);
|
|
||||||
}
|
|
||||||
*it++ = decimal_point;
|
|
||||||
it = copy_str<Char>(digits + full_exp, digits + size, it);
|
|
||||||
if (params.num_digits > size) {
|
|
||||||
// Add trailing zeros.
|
|
||||||
int num_zeros = params.num_digits - size;
|
|
||||||
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// 1234e-6 -> 0.001234
|
|
||||||
*it++ = static_cast<Char>('0');
|
|
||||||
int num_zeros = -full_exp;
|
|
||||||
if (params.num_digits >= 0 && params.num_digits < num_zeros)
|
|
||||||
num_zeros = params.num_digits;
|
|
||||||
if (!params.trailing_zeros)
|
|
||||||
while (size > 0 && digits[size - 1] == '0') --size;
|
|
||||||
if (num_zeros != 0 || size != 0) {
|
|
||||||
*it++ = decimal_point;
|
|
||||||
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
|
||||||
it = copy_str<Char>(digits, digits + size, it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return it;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Char> class grisu_writer {
|
template <typename Char> class grisu_writer {
|
||||||
private:
|
private:
|
||||||
|
// The number is given as v = digits_ * pow(10, exp_).
|
||||||
const char* digits_;
|
const char* digits_;
|
||||||
int num_digits_;
|
int num_digits_;
|
||||||
int exp_;
|
int exp_;
|
||||||
@ -1127,6 +1065,70 @@ template <typename Char> class grisu_writer {
|
|||||||
gen_digits_params params_;
|
gen_digits_params params_;
|
||||||
Char decimal_point_;
|
Char decimal_point_;
|
||||||
|
|
||||||
|
template <typename It> It grisu_prettify(It it) const {
|
||||||
|
// pow(10, full_exp - 1) <= v <= pow(10, full_exp).
|
||||||
|
int full_exp = num_digits_ + exp_;
|
||||||
|
if (!params_.fixed) {
|
||||||
|
// Insert a decimal point after the first digit and add an exponent.
|
||||||
|
*it++ = static_cast<Char>(*digits_);
|
||||||
|
if (num_digits_ > 1) *it++ = decimal_point_;
|
||||||
|
it = copy_str<Char>(digits_ + 1, digits_ + num_digits_, it);
|
||||||
|
if (num_digits_ < params_.num_digits) {
|
||||||
|
it = std::fill_n(it, params_.num_digits - num_digits_,
|
||||||
|
static_cast<Char>('0'));
|
||||||
|
}
|
||||||
|
*it++ = static_cast<Char>(params_.upper ? 'E' : 'e');
|
||||||
|
return write_exponent<Char>(full_exp - 1, it);
|
||||||
|
}
|
||||||
|
if (num_digits_ <= full_exp) {
|
||||||
|
// 1234e7 -> 12340000000[.0+]
|
||||||
|
it = copy_str<Char>(digits_, digits_ + num_digits_, it);
|
||||||
|
it = std::fill_n(it, full_exp - num_digits_, static_cast<Char>('0'));
|
||||||
|
int num_zeros = (std::max)(params_.num_digits - full_exp, 1);
|
||||||
|
if (params_.trailing_zeros) {
|
||||||
|
*it++ = decimal_point_;
|
||||||
|
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
|
||||||
|
if (num_zeros > 1000)
|
||||||
|
throw std::runtime_error("fuzz mode - avoiding excessive cpu use");
|
||||||
|
#endif
|
||||||
|
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
||||||
|
}
|
||||||
|
} else if (full_exp > 0) {
|
||||||
|
// 1234e-2 -> 12.34[0+]
|
||||||
|
it = copy_str<Char>(digits_, digits_ + full_exp, it);
|
||||||
|
if (!params_.trailing_zeros) {
|
||||||
|
// Remove trailing zeros.
|
||||||
|
int num_digits = num_digits_;
|
||||||
|
while (num_digits > full_exp && digits_[num_digits - 1] == '0')
|
||||||
|
--num_digits;
|
||||||
|
if (num_digits != full_exp) *it++ = decimal_point_;
|
||||||
|
return copy_str<Char>(digits_ + full_exp, digits_ + num_digits, it);
|
||||||
|
}
|
||||||
|
*it++ = decimal_point_;
|
||||||
|
it = copy_str<Char>(digits_ + full_exp, digits_ + num_digits_, it);
|
||||||
|
if (params_.num_digits > num_digits_) {
|
||||||
|
// Add trailing zeros.
|
||||||
|
int num_zeros = params_.num_digits - num_digits_;
|
||||||
|
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 1234e-6 -> 0.001234
|
||||||
|
*it++ = static_cast<Char>('0');
|
||||||
|
int num_zeros = -full_exp;
|
||||||
|
if (params_.num_digits >= 0 && params_.num_digits < num_zeros)
|
||||||
|
num_zeros = params_.num_digits;
|
||||||
|
int num_digits = num_digits_;
|
||||||
|
if (!params_.trailing_zeros)
|
||||||
|
while (num_digits > 0 && digits_[num_digits - 1] == '0') --num_digits;
|
||||||
|
if (num_zeros != 0 || num_digits != 0) {
|
||||||
|
*it++ = decimal_point_;
|
||||||
|
it = std::fill_n(it, num_zeros, static_cast<Char>('0'));
|
||||||
|
it = copy_str<Char>(digits_, digits_ + num_digits, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
grisu_writer(const char* digits, int num_digits, int exp,
|
grisu_writer(const char* digits, int num_digits, int exp,
|
||||||
gen_digits_params params, Char decimal_point)
|
gen_digits_params params, Char decimal_point)
|
||||||
@ -1138,18 +1140,16 @@ template <typename Char> class grisu_writer {
|
|||||||
int full_exp = num_digits + exp - 1;
|
int full_exp = num_digits + exp - 1;
|
||||||
int precision = params.num_digits > 0 ? params.num_digits : 16;
|
int precision = params.num_digits > 0 ? params.num_digits : 16;
|
||||||
params_.fixed |= full_exp >= -4 && full_exp < precision;
|
params_.fixed |= full_exp >= -4 && full_exp < precision;
|
||||||
auto it = grisu_prettify(digits, num_digits, exp, counting_iterator(),
|
size_ = grisu_prettify(counting_iterator()).count();
|
||||||
params_, '\0');
|
size_ += params_.sign ? 1 : 0;
|
||||||
size_ = it.count();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return size_ + (params_.sign ? 1 : 0); }
|
size_t size() const { return size_; }
|
||||||
size_t width() const { return size(); }
|
size_t width() const { return size(); }
|
||||||
|
|
||||||
template <typename It> void operator()(It&& it) {
|
template <typename It> void operator()(It&& it) {
|
||||||
if (params_.sign) *it++ = static_cast<Char>(data::signs[params_.sign]);
|
if (params_.sign) *it++ = static_cast<Char>(data::signs[params_.sign]);
|
||||||
it =
|
it = grisu_prettify(it);
|
||||||
grisu_prettify(digits_, num_digits_, exp_, it, params_, decimal_point_);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user