Remove buffer argument from format

This commit is contained in:
Eugen Wissner 2017-11-28 22:11:19 +01:00
parent c199cdd47c
commit 664298f038

View File

@ -432,12 +432,8 @@ NoRound:
// Kill long trailing runs of zeros. // Kill long trailing runs of zeros.
if (bits) if (bits)
{ {
for (;;) while (bits > 0xffffffff)
{ {
if (bits <= 0xffffffff)
{
break;
}
if (bits % 1000) if (bits % 1000)
{ {
goto Zeroed; goto Zeroed;
@ -497,17 +493,6 @@ Zeroed:
return result[0 .. length]; return result[0 .. length];
} }
private void leadSign(bool negative, ref char[8] sign)
@nogc nothrow pure @safe
{
sign[0] = 0;
if (negative)
{
sign[0] = 1;
sign[1] = '-';
}
}
/* /*
* Copies double into long and back bitwise. * Copies double into long and back bitwise.
*/ */
@ -517,26 +502,7 @@ if (T.sizeof == U.sizeof)
copy((&src)[0 .. 1], (&dest)[0 .. 1]); copy((&src)[0 .. 1], (&dest)[0 .. 1]);
} }
private void ddmulthi(ref double oh, package(tanya) String format(string fmt, Args...)(auto ref Args args)
ref double ol,
ref double xh,
const ref double yh) @nogc nothrow pure
{
double ahi, bhi;
long bt;
oh = xh * yh;
copyFp(xh, bt);
bt &= ((~cast(ulong) 0) << 27);
copyFp(bt, ahi);
double alo = xh - ahi;
copyFp(yh, bt);
bt &= ((~cast(ulong) 0) << 27);
copyFp(bt, bhi);
double blo = yh - bhi;
ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo;
}
package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
{ {
String result; String result;
@ -557,94 +523,72 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
} }
else static if (isFloatingPoint!(Args[0])) // Float else static if (isFloatingPoint!(Args[0])) // Float
{ {
char[512] num; // Big enough for e308 (with commas) or e-307. char[512] buffer; // Big enough for e+308 or e-307.
char[8] lead;
char[8] tail = 0; char[8] tail = 0;
char *s; char *s;
int precision = 6; uint precision = 6;
int tz;
bool negative; bool negative;
char* bf = buf.ptr;
int decimalPos; int decimalPos;
// Read the double into a string. // Read the double into a string.
auto fv = real2String(args[0], num, decimalPos, negative); auto realString = real2String(args[0], buffer, decimalPos, negative);
const(char)* sn = fv.ptr; auto length = cast(uint) realString.length;
auto l = cast(uint) fv.length;
// Clamp the precision and delete extra zeros after clamp. // Clamp the precision and delete extra zeros after clamp.
uint n = precision; uint n = precision;
if (l > cast(uint) precision) if (length > precision)
{ {
l = precision; length = precision;
} }
while ((l > 1) && (precision) && (sn[l - 1] == '0')) while ((length > 1)
&& (precision != 0)
&& (realString[length - 1] == '0'))
{ {
--precision; --precision;
--l; --length;
} }
// Should we use %e. if (negative)
{
result.insertBack('-');
}
if (decimalPos == special)
{
result.insertBack(realString);
goto ParamEnd;
}
// Should we use sceintific notation?
if ((decimalPos <= -4) || (decimalPos > cast(int) n)) if ((decimalPos <= -4) || (decimalPos > cast(int) n))
{ {
if (precision > cast(int) l) if (precision > length)
{ {
precision = l - 1; precision = length - 1;
} }
else if (precision) else if (precision != 0)
{ {
// When using %e, there is one digit before the decimal. // When using %e, there is one digit before the decimal.
--precision; --precision;
} }
goto doexpfromg;
}
// This is the insane action to get the pr to match %g sematics
// for %f
if (decimalPos > 0)
{
precision = (decimalPos < cast(int) l) ? l - decimalPos : 0;
}
else
{
if (precision > cast(int) l)
{
precision = -decimalPos + l;
}
else
{
precision = -decimalPos + precision;
}
}
goto dofloatfromg;
doexpfromg: s = buffer.ptr + 64;
leadSign(negative, lead);
if (decimalPos == special)
{
s = cast(char*) sn;
precision = 0;
goto scopy;
}
s = num.ptr + 64;
// Handle leading chars. // Handle leading chars.
*s++ = sn[0]; *s++ = realString[0];
if (precision) if (precision != 0)
{ {
*s++ = period; *s++ = period;
} }
// Handle after decimal. // Handle after decimal.
if ((l - 1) > cast(uint) precision) if ((length - 1) > precision)
{ {
l = precision + 1; length = precision + 1;
} }
for (n = 1; n < l; n++) for (n = 1; n < length; n++)
{ {
*s++ = sn[n]; *s++ = realString[n];
} }
// Trailing zeros.
tz = precision - (l - 1);
precision = 0; precision = 0;
// Dump the exponent. // Dump the exponent.
tail[1] = 'e'; tail[1] = 'e';
@ -662,7 +606,7 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
n = (decimalPos >= 100) ? 5 : 4; n = (decimalPos >= 100) ? 5 : 4;
tail[0] = cast(char) n; tail[0] = cast(char) n;
for (;;) while (true)
{ {
tail[n] = '0' + decimalPos % 10; tail[n] = '0' + decimalPos % 10;
if (n <= 3) if (n <= 3)
@ -672,34 +616,47 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
--n; --n;
decimalPos /= 10; decimalPos /= 10;
} }
goto flt_lead;
dofloatfromg:
leadSign(negative, lead);
if (decimalPos == special)
{
s = cast(char*) sn;
precision = 0;
goto scopy;
} }
s = num.ptr + 64; else
{
// This is the insane action to get the pr to match %g sematics
// for %f
if (decimalPos > 0)
{
precision = decimalPos < (cast(int) length)
? length - decimalPos
: 0;
}
else
{
if (precision > length)
{
precision = -decimalPos + length;
}
else
{
precision = -decimalPos + precision;
}
}
s = buffer.ptr + 64;
// Handle the three decimal varieties. // Handle the three decimal varieties.
if (decimalPos <= 0) if (decimalPos <= 0)
{ {
// Handle 0.000*000xxxx. // Handle 0.000*000xxxx.
*s++ = '0'; *s++ = '0';
if (precision) if (precision != 0)
{ {
*s++ = period; *s++ = period;
} }
n = -decimalPos; n = -decimalPos;
if (cast(int) n > precision) if (n > precision)
{ {
n = precision; n = precision;
} }
int i = n; uint i = n;
while (i) while (i > 0)
{ {
if (((cast(size_t) s) & 3) == 0) if (((cast(size_t) s) & 3) == 0)
{ {
@ -714,38 +671,33 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
s += 4; s += 4;
i -= 4; i -= 4;
} }
while (i) while (i > 0)
{ {
*s++ = '0'; *s++ = '0';
--i; --i;
} }
if (cast(int) (l + n) > precision) if ((length + n) > precision)
{ {
l = precision - n; length = precision - n;
} }
i = l; i = length;
while (i) while (i > 0)
{ {
*s++ = *sn++; *s++ = realString.front;
realString.popFront();
--i; --i;
} }
tz = precision - (n + l);
} }
else else if (cast(uint) decimalPos >= length)
{
if (cast(uint) decimalPos >= l)
{ {
// Handle xxxx000*000.0. // Handle xxxx000*000.0.
n = 0; n = 0;
for (;;) do
{ {
*s++ = sn[n]; *s++ = realString[n];
++n; ++n;
if (n >= l)
{
break;
}
} }
while (n < length);
if (n < cast(uint) decimalPos) if (n < cast(uint) decimalPos)
{ {
n = decimalPos - n; n = decimalPos - n;
@ -770,172 +722,44 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
--n; --n;
} }
} }
if (precision) if (precision != 0)
{ {
*s++ = period; *s++ = period;
tz = precision;
} }
} }
else else
{ {
// Handle xxxxx.xxxx000*000. // Handle xxxxx.xxxx000*000.
n = 0; n = 0;
for (;;) do
{ {
*s++ = sn[n]; *s++ = realString[n];
++n; ++n;
if (n >= cast(uint) decimalPos)
{
break;
} }
} while (n < cast(uint) decimalPos);
if (precision)
if (precision > 0)
{ {
*s++ = period; *s++ = period;
} }
if ((l - decimalPos) > cast(uint) precision) if ((length - decimalPos) > precision)
{ {
l = precision + decimalPos; length = precision + decimalPos;
} }
while (n < l) while (n < length)
{ {
*s++ = sn[n]; *s++ = realString[n];
++n; ++n;
} }
tz = precision - (l - decimalPos);
}
} }
precision = 0; precision = 0;
}
flt_lead:
// Get the length that we copied. // Get the length that we copied.
l = cast(uint) (s - (num.ptr + 64)); length = cast(uint) (s - (buffer.ptr + 64));
s = num.ptr + 64;
scopy: result.insertBack(buffer[64 .. 64 + length]); // Number.
// Get fw=leading/trailing space, precision=leading zeros. result.insertBack(tail[1 .. tail[0] + 1]); // Tail.
if (precision < cast(int) l)
{
precision = l;
}
n = precision + lead[0] + tail[0] + tz;
precision -= l;
// Copy the spaces and/or zeros.
if (precision)
{
int i;
// copy leader
sn = lead.ptr + 1;
while (lead[0])
{
i = lead[0];
lead[0] -= cast(char) i;
while (i)
{
*bf++ = *sn++;
--i;
}
}
// Copy leading zeros.
while (precision > 0)
{
i = precision;
precision -= i;
while (i)
{
if (((cast(size_t) bf) & 3) == 0)
{
break;
}
*bf++ = '0';
--i;
}
while (i >= 4)
{
*cast(uint*) bf = 0x30303030;
bf += 4;
i -= 4;
}
while (i)
{
*bf++ = '0';
--i;
}
}
}
// copy leader if there is still one
sn = lead.ptr + 1;
while (lead[0])
{
int i = lead[0];
lead[0] -= cast(char) i;
while (i)
{
*bf++ = *sn++;
--i;
}
}
// Copy the string.
n = l;
while (n)
{
int i = n;
n -= i;
while (i)
{
*bf++ = *s++;
--i;
}
}
// Copy trailing zeros.
while (tz)
{
int i = tz;
tz -= i;
while (i)
{
if (((cast(size_t) bf) & 3) == 0)
{
break;
}
*bf++ = '0';
--i;
}
while (i >= 4)
{
*cast(uint*) bf = 0x30303030;
bf += 4;
i -= 4;
}
while (i)
{
*bf++ = '0';
--i;
}
}
// copy tail if there is one
sn = tail.ptr + 1;
while (tail[0])
{
int i = tail[0];
tail[0] -= cast(char) i;
while (i)
{
*bf++ = *sn++;
--i;
}
}
*bf = 0;
result = String(buf[0 .. cast(int) (bf - buf.ptr)]);
} }
else static if (isPointer!(Args[0])) // Pointer else static if (isPointer!(Args[0])) // Pointer
{ {
@ -962,68 +786,67 @@ package(tanya) String format(string fmt, Args...)(char[] buf, Args args)
{ {
static assert(false); static assert(false);
} }
ParamEnd:
return result; return result;
} }
@nogc pure unittest @nogc pure unittest
{ {
char[318] buffer;
// Modifiers. // Modifiers.
assert(format!("{}")(buffer, 8.5) == "8.5"); assert(format!("{}")(8.5) == "8.5");
assert(format!("{}")(buffer, 8.6) == "8.6"); assert(format!("{}")(8.6) == "8.6");
assert(format!("{}")(buffer, 1000) == "1000"); assert(format!("{}")(1000) == "1000");
assert(format!("{}")(buffer, 1) == "1"); assert(format!("{}")(1) == "1");
assert(format!("{}")(buffer, 10.25) == "10.25"); assert(format!("{}")(10.25) == "10.25");
assert(format!("{}")(buffer, 1) == "1"); assert(format!("{}")(1) == "1");
assert(format!("{}")(buffer, 0.01) == "0.01"); assert(format!("{}")(0.01) == "0.01");
// Integer size. // Integer size.
assert(format!("{}")(buffer, 10) == "10"); assert(format!("{}")(10) == "10");
assert(format!("{}")(buffer, 10L) == "10"); assert(format!("{}")(10L) == "10");
// String printing. // String printing.
assert(format!("{}")(buffer, "Some weired string") == "Some weired string"); assert(format!("{}")("Some weired string") == "Some weired string");
assert(format!("{}")(buffer, cast(string) null) == "null"); assert(format!("{}")(cast(string) null) == "null");
assert(format!("{}")(buffer, 'c') == "c"); assert(format!("{}")('c') == "c");
// Integer conversions. // Integer conversions.
assert(format!("{}")(buffer, 8) == "8"); assert(format!("{}")(8) == "8");
assert(format!("{}")(buffer, 8) == "8"); assert(format!("{}")(8) == "8");
assert(format!("{}")(buffer, -8) == "-8"); assert(format!("{}")(-8) == "-8");
assert(format!("{}")(buffer, -8L) == "-8"); assert(format!("{}")(-8L) == "-8");
assert(format!("{}")(buffer, 8) == "8"); assert(format!("{}")(8) == "8");
assert(format!("{}")(buffer, 100000001) == "100000001"); assert(format!("{}")(100000001) == "100000001");
assert(format!("{}")(buffer, 99999999L) == "99999999"); assert(format!("{}")(99999999L) == "99999999");
// Floating point conversions. // Floating point conversions.
assert(format!("{}")(buffer, 0.1234) == "0.1234"); assert(format!("{}")(0.1234) == "0.1234");
assert(format!("{}")(buffer, 0.3) == "0.3"); assert(format!("{}")(0.3) == "0.3");
assert(format!("{}")(buffer, 0.333333333333) == "0.333333"); assert(format!("{}")(0.333333333333) == "0.333333");
assert(format!("{}")(buffer, 38234.1234) == "38234.1"); assert(format!("{}")(38234.1234) == "38234.1");
assert(format!("{}")(buffer, -0.3) == "-0.3"); assert(format!("{}")(-0.3) == "-0.3");
assert(format!("{}")(buffer, 0.000000000000000006) == "6e-18"); assert(format!("{}")(0.000000000000000006) == "6e-18");
assert(format!("{}")(buffer, 0.0) == "0"); assert(format!("{}")(0.0) == "0");
assert(format!("{}")(buffer, double.init) == "NaN"); assert(format!("{}")(double.init) == "NaN");
assert(format!("{}")(buffer, -double.init) == "-NaN"); assert(format!("{}")(-double.init) == "-NaN");
assert(format!("{}")(buffer, double.infinity) == "Inf"); assert(format!("{}")(double.infinity) == "Inf");
assert(format!("{}")(buffer, -double.infinity) == "-Inf"); assert(format!("{}")(-double.infinity) == "-Inf");
assert(format!("{}")(buffer, 0.000000000000000000000000003) == "3e-27"); assert(format!("{}")(0.000000000000000000000000003) == "3e-27");
assert(format!("{}")(buffer, 0.23432e304) == "2.3432e+303"); assert(format!("{}")(0.23432e304) == "2.3432e+303");
assert(format!("{}")(buffer, -0.23432e8) == "-2.3432e+07"); assert(format!("{}")(-0.23432e8) == "-2.3432e+07");
assert(format!("{}")(buffer, 1e-307) == "1e-307"); assert(format!("{}")(1e-307) == "1e-307");
assert(format!("{}")(buffer, 1e+8) == "1e+08"); assert(format!("{}")(1e+8) == "1e+08");
assert(format!("{}")(buffer, 111234.1) == "111234"); assert(format!("{}")(111234.1) == "111234");
assert(format!("{}")(buffer, 0.999) == "0.999"); assert(format!("{}")(0.999) == "0.999");
assert(format!("{}")(buffer, 0x1p-16382L) == "0"); assert(format!("{}")(0x1p-16382L) == "0");
assert(format!("{}")(buffer, 1e+3) == "1000"); assert(format!("{}")(1e+3) == "1000");
assert(format!("{}")(buffer, 38234.1234) == "38234.1"); assert(format!("{}")(38234.1234) == "38234.1");
// Pointer convesions. // Pointer convesions
assert(format!("{}")(buffer, cast(void*) 1) == "0x1"); assert(format!("{}")(cast(void*) 1) == "0x1");
assert(format!("{}")(buffer, cast(void*) 20) == "0x14"); assert(format!("{}")(cast(void*) 20) == "0x14");
assert(format!("{}")(buffer, cast(void*) null) == "0x0"); assert(format!("{}")(cast(void*) null) == "0x0");
} }
private struct FormatSpec private struct FormatSpec