much better integer formatting (less stack space, better precision handling)
parent
baf0dd4ca6
commit
e5a21382af
|
@ -142,7 +142,8 @@ int main() {
|
||||||
writefln(
|
writefln(
|
||||||
"\"%d\", \"%f\", \"%X\"", 123456789, 12345.6789123, 0x123456789ABCDEF
|
"\"%d\", \"%f\", \"%X\"", 123456789, 12345.6789123, 0x123456789ABCDEF
|
||||||
);
|
);
|
||||||
cout.imbue(std::locale{""});
|
std::locale::global(std::locale{""});
|
||||||
|
cout.imbue(std::locale{});
|
||||||
writefln("\n-- number format with system locale --");
|
writefln("\n-- number format with system locale --");
|
||||||
writefln(
|
writefln(
|
||||||
"\"%d\", \"%f\", \"%X\"", 123456789, 12345.6789123, 0x123456789ABCDEF
|
"\"%d\", \"%f\", \"%X\"", 123456789, 12345.6789123, 0x123456789ABCDEF
|
||||||
|
|
121
ostd/format.hh
121
ostd/format.hh
|
@ -1017,9 +1017,9 @@ private:
|
||||||
|
|
||||||
template<typename R, typename T>
|
template<typename R, typename T>
|
||||||
void write_int(R &writer, bool ptr, bool neg, T val) const {
|
void write_int(R &writer, bool ptr, bool neg, T val) const {
|
||||||
/* binary representation is the biggest, assume grouping */
|
/* binary representation is the longest */
|
||||||
char buf[sizeof(T) * CHAR_BIT * (detail::MaxMultibyte + 1)];
|
char buf[sizeof(T) * CHAR_BIT];
|
||||||
std::size_t n = 0;
|
std::size_t ndig = 0;
|
||||||
|
|
||||||
char isp = spec();
|
char isp = spec();
|
||||||
if (isp == 's') {
|
if (isp == 's') {
|
||||||
|
@ -1033,46 +1033,56 @@ private:
|
||||||
int cmask = ((isp >= 'a') << 5);
|
int cmask = ((isp >= 'a') << 5);
|
||||||
|
|
||||||
int base = detail::fmt_bases[specn];
|
int base = detail::fmt_bases[specn];
|
||||||
bool zval = !val;
|
if (!val) {
|
||||||
if (zval) {
|
ndig = 1;
|
||||||
buf[n++] = '0';
|
buf[0] = '0';
|
||||||
|
} else {
|
||||||
|
for (; val; val /= base) {
|
||||||
|
T vb = val % base;
|
||||||
|
buf[ndig++] = (vb + "70"[vb < 10]) | cmask;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* this is bullshit */
|
std::size_t tdig = ndig;
|
||||||
auto const &fac = std::use_facet<std::numpunct<wchar_t>>(p_loc);
|
|
||||||
auto const &grp = fac.grouping();
|
|
||||||
char tseps[detail::MaxMultibyte];
|
|
||||||
int ntsep = wctomb(tseps, fac.thousands_sep());
|
|
||||||
auto grpp = reinterpret_cast<unsigned char const *>(grp.data());
|
|
||||||
unsigned char grpn = *grpp;
|
|
||||||
for (; val; val /= base) {
|
|
||||||
if (!ptr && *grpp) {
|
|
||||||
if (!grpn) {
|
|
||||||
for (int i = ntsep - 1; i >= 0; --i) {
|
|
||||||
buf[n++] = tseps[i];
|
|
||||||
}
|
|
||||||
if (*(grpp + 1)) {
|
|
||||||
++grpp;
|
|
||||||
}
|
|
||||||
grpn = *grpp;
|
|
||||||
}
|
|
||||||
if (grpn) {
|
|
||||||
--grpn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
T vb = val % base;
|
|
||||||
buf[n++] = (vb + "70"[vb < 10]) | cmask;
|
|
||||||
}
|
|
||||||
std::size_t tn = n;
|
|
||||||
if (has_precision()) {
|
if (has_precision()) {
|
||||||
int prec = precision();
|
int prec = precision();
|
||||||
if (std::size_t(prec) > tn) {
|
if (std::size_t(prec) > tdig) {
|
||||||
tn = std::size_t(prec);
|
tdig = std::size_t(prec);
|
||||||
} else if (!prec && zval) {
|
} else if (!prec && !val) {
|
||||||
tn = 0;
|
tdig = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* here starts the bullshit */
|
||||||
|
auto const &fac = std::use_facet<std::numpunct<wchar_t>>(p_loc);
|
||||||
|
|
||||||
|
char tseps[detail::MaxMultibyte];
|
||||||
|
int ntsep = wctomb(tseps, fac.thousands_sep());
|
||||||
|
|
||||||
|
auto const &grp = fac.grouping();
|
||||||
|
auto grpp = reinterpret_cast<unsigned char const *>(grp.data());
|
||||||
|
|
||||||
|
std::size_t nseps = 0, sreps = 0;
|
||||||
|
std::size_t total = tdig;
|
||||||
|
if (!ptr && (ntsep >= 0)) {
|
||||||
|
int cndig = int(ndig);
|
||||||
|
while (*grpp) {
|
||||||
|
cndig -= *grpp;
|
||||||
|
if (cndig > 0) {
|
||||||
|
++nseps;
|
||||||
|
if (!grpp[1]) {
|
||||||
|
++sreps;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
++grpp;
|
||||||
|
}
|
||||||
|
total += nseps * ntsep;
|
||||||
|
}
|
||||||
|
/* here ends the bullshit */
|
||||||
|
|
||||||
int fl = flags();
|
int fl = flags();
|
||||||
bool lsgn = fl & FMT_FLAG_PLUS;
|
bool lsgn = fl & FMT_FLAG_PLUS;
|
||||||
bool lsp = fl & FMT_FLAG_SPACE;
|
bool lsp = fl & FMT_FLAG_SPACE;
|
||||||
|
@ -1084,28 +1094,53 @@ private:
|
||||||
pfx = ("XB"[(specn == 3)]) | cmask;
|
pfx = ("XB"[(specn == 3)]) | cmask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* leading spaces if they apply */
|
||||||
if (!zero) {
|
if (!zero) {
|
||||||
write_spaces(writer, tn + (!!pfx * 2) + sign, true, ' ');
|
write_spaces(writer, total + (!!pfx * 2) + sign, true, ' ');
|
||||||
}
|
}
|
||||||
|
/* sign (either forced or a minus) */
|
||||||
if (sign) {
|
if (sign) {
|
||||||
writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
|
writer.put(neg ? '-' : *((" \0+") + lsgn * 2));
|
||||||
}
|
}
|
||||||
|
/* prefix such as 0x */
|
||||||
if (pfx) {
|
if (pfx) {
|
||||||
writer.put('0');
|
writer.put('0');
|
||||||
writer.put(pfx);
|
writer.put(pfx);
|
||||||
}
|
}
|
||||||
|
/* if we chose to pad with leading zeroes instead */
|
||||||
if (zero) {
|
if (zero) {
|
||||||
write_spaces(writer, tn + (!!pfx * 2) + sign, true, '0');
|
write_spaces(writer, total + (!!pfx * 2) + sign, true, '0');
|
||||||
}
|
}
|
||||||
if (tn) {
|
/* number itself (with potential thousands grouping) */
|
||||||
for (std::size_t i = 0; i < (tn - n); ++i) {
|
if (total) {
|
||||||
|
/* potential higher precision, no grouping applies */
|
||||||
|
for (std::size_t i = 0; i < (tdig - ndig); ++i) {
|
||||||
writer.put('0');
|
writer.put('0');
|
||||||
}
|
}
|
||||||
for (std::size_t i = 0; i < n; ++i) {
|
/* the rest of the number, with thousands grouping */
|
||||||
writer.put(buf[n - i - 1]);
|
unsigned char grpn = *grpp;
|
||||||
|
for (std::size_t i = 0; i < ndig; ++i) {
|
||||||
|
if (nseps) {
|
||||||
|
if (!grpn) {
|
||||||
|
for (int j = 0; j < ntsep; ++j) {
|
||||||
|
writer.put(tseps[j]);
|
||||||
|
}
|
||||||
|
if (sreps) {
|
||||||
|
--sreps;
|
||||||
|
} else {
|
||||||
|
--grpp;
|
||||||
|
}
|
||||||
|
grpn = *grpp;
|
||||||
|
--nseps;
|
||||||
|
}
|
||||||
|
if (grpn) {
|
||||||
|
--grpn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writer.put(buf[ndig - i - 1]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
write_spaces(writer, tn + sign + (!!pfx * 2), false);
|
write_spaces(writer, total + sign + (!!pfx * 2), false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* floating point */
|
/* floating point */
|
||||||
|
|
Loading…
Reference in New Issue