Check format specifier at compile time
This commit is contained in:
parent
72d5760589
commit
f334e6a1a0
@ -225,7 +225,7 @@ private void raise2Power10(double* ohi,
|
||||
* of the decimal point in decimalPos. +/-Inf and NaN are specified by special
|
||||
* values returned in the decimalPos parameter.
|
||||
* fracDigits is absolute normally, but if you want from first significant
|
||||
* digits (got %g and %e), or in 0x80000000
|
||||
* digits (got %g), or in 0x80000000
|
||||
*/
|
||||
private int real2String(ref const(char)* start,
|
||||
ref uint len,
|
||||
@ -425,24 +425,17 @@ private int real2String(ref const(char)* start,
|
||||
return ng;
|
||||
}
|
||||
|
||||
private void leadSign(uint fl, char* sign)
|
||||
private void leadSign(bool negative, ref char[8] sign)
|
||||
pure nothrow @nogc
|
||||
{
|
||||
sign[0] = 0;
|
||||
if (fl & Modifier.negative)
|
||||
if (negative)
|
||||
{
|
||||
sign[0] = 1;
|
||||
sign[1] = '-';
|
||||
}
|
||||
}
|
||||
|
||||
private enum Modifier : uint
|
||||
{
|
||||
intMax = 32,
|
||||
negative = 128,
|
||||
halfWidth = 512,
|
||||
}
|
||||
|
||||
// Copies d to bits w/ strict aliasing (this compiles to nothing on /Ox).
|
||||
private void copyFp(T, U)(ref T dest, ref U src)
|
||||
{
|
||||
@ -471,134 +464,19 @@ private void ddmulthi(ref double oh,
|
||||
ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get float info.
|
||||
*
|
||||
* Returns: Sign bit.
|
||||
*/
|
||||
private int real2Parts(long* bits, out int exponent, const double value)
|
||||
pure nothrow @nogc
|
||||
{
|
||||
long b;
|
||||
|
||||
// Load value and round at the fracDigits.
|
||||
double d = value;
|
||||
|
||||
copyFp(b, d);
|
||||
|
||||
*bits = b & (((cast(ulong) 1) << 52) - 1);
|
||||
// 1023 is the exponent bias, calculated as 2^(k - 1) - 1, where k is the
|
||||
// number of bits used to represent the exponent, 11 bit for double.
|
||||
exponent = cast(int) (((b >> 52) & 0x7ff) - 1023);
|
||||
|
||||
return cast(int) (b >> 63);
|
||||
}
|
||||
|
||||
private char[] vsprintf(string fmt)(return char[] buf, va_list va)
|
||||
private char[] vsprintf(string fmt, Args...)(return char[] buf, va_list va)
|
||||
pure nothrow @nogc
|
||||
{
|
||||
char* bf = buf.ptr;
|
||||
string f = fmt;
|
||||
int tlen;
|
||||
|
||||
FmtLoop: while (true)
|
||||
{
|
||||
// Fast copy everything up to the next % (or end of string).
|
||||
while ((cast(size_t) f.ptr) & 3)
|
||||
{
|
||||
schk:
|
||||
if (f.length == 0)
|
||||
{
|
||||
break FmtLoop;
|
||||
}
|
||||
if (f[0] == '%')
|
||||
{
|
||||
goto scandd;
|
||||
}
|
||||
|
||||
*bf++ = f[0];
|
||||
f.popFront();
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
// Check if the next 4 bytes contain %(0x25) or end of string.
|
||||
// Using the 'hasless' trick:
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
|
||||
uint v = *cast(uint*) f;
|
||||
uint c = (~v) & 0x80808080;
|
||||
if ((((v ^ 0x25252525) - 0x01010101) & c) || f.length <= 3)
|
||||
{
|
||||
goto schk;
|
||||
}
|
||||
|
||||
*cast(uint*) bf = v;
|
||||
bf += 4;
|
||||
f = f[4 .. $];
|
||||
}
|
||||
scandd:
|
||||
|
||||
f.popFront();
|
||||
|
||||
// Ok, we have a percent, read the modifiers first.
|
||||
int fw = 0;
|
||||
int precision = -1;
|
||||
int tz = 0;
|
||||
uint fl = 0;
|
||||
|
||||
// Get the field width.
|
||||
if (f[0] == '*')
|
||||
{
|
||||
fw = va_arg!uint(va);
|
||||
f.popFront();
|
||||
}
|
||||
else
|
||||
{
|
||||
while ((f[0] >= '0') && (f[0] <= '9'))
|
||||
{
|
||||
fw = fw * 10 + f[0] - '0';
|
||||
f.popFront();
|
||||
}
|
||||
}
|
||||
// Get the precision.
|
||||
if (f[0] == '.')
|
||||
{
|
||||
f.popFront();
|
||||
if (f[0] == '*')
|
||||
{
|
||||
precision = va_arg!uint(va);
|
||||
f.popFront();
|
||||
}
|
||||
else
|
||||
{
|
||||
precision = 0;
|
||||
while ((f[0] >= '0') && (f[0] <= '9'))
|
||||
{
|
||||
precision = precision * 10 + f[0] - '0';
|
||||
f.popFront();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle integer size overrides.
|
||||
switch (f[0])
|
||||
{
|
||||
// are we halfwidth?
|
||||
case 'h':
|
||||
fl |= Modifier.halfWidth;
|
||||
f.popFront();
|
||||
break;
|
||||
// are we 64-bit?
|
||||
case 'l':
|
||||
fl |= Modifier.intMax;
|
||||
f.popFront();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
bool negative;
|
||||
|
||||
// Handle each replacement.
|
||||
enum NUMSZ = 512; // Big enough for e308 (with commas) or e-307.
|
||||
char[NUMSZ] num;
|
||||
char[512] num; // Big enough for e308 (with commas) or e-307.
|
||||
char[8] lead;
|
||||
char[8] tail;
|
||||
char *s;
|
||||
@ -610,9 +488,8 @@ pure nothrow @nogc
|
||||
int decimalPos;
|
||||
const(char)* sn;
|
||||
|
||||
switch (f[0])
|
||||
static if (fmt[0] == 's') // String
|
||||
{
|
||||
case 's':
|
||||
// Get the string.
|
||||
s = va_arg!(char[])(va).ptr;
|
||||
if (s is null)
|
||||
@ -635,15 +512,6 @@ pure nothrow @nogc
|
||||
++sn;
|
||||
}
|
||||
n = 0xffffffff;
|
||||
if (precision >= 0)
|
||||
{
|
||||
n = cast(uint) (sn - s);
|
||||
if (n >= cast(uint) precision)
|
||||
{
|
||||
goto ld;
|
||||
}
|
||||
n = (cast(uint) (precision - n)) >> 2;
|
||||
}
|
||||
while (n)
|
||||
{
|
||||
uint v = *cast(uint*) sn;
|
||||
@ -655,33 +523,29 @@ pure nothrow @nogc
|
||||
--n;
|
||||
}
|
||||
goto lchk;
|
||||
ld:
|
||||
|
||||
ld:
|
||||
l = cast(uint) (sn - s);
|
||||
// Clamp to precision.
|
||||
if (l > cast(uint) precision)
|
||||
{
|
||||
l = precision;
|
||||
}
|
||||
|
||||
lead[0] = 0;
|
||||
tail[0] = 0;
|
||||
precision = 0;
|
||||
decimalPos = 0;
|
||||
// Copy the string in.
|
||||
goto scopy;
|
||||
|
||||
case 'c': // Char.
|
||||
}
|
||||
else static if (fmt[0] == 'c') // Char
|
||||
{
|
||||
// Get the character.
|
||||
s = num.ptr + NUMSZ - 1;
|
||||
s = num.ptr + num.length - 1;
|
||||
*s = cast(char) va_arg!int(va);
|
||||
l = 1;
|
||||
lead[0] = 0;
|
||||
tail[0] = 0;
|
||||
precision = 0;
|
||||
decimalPos = 0;
|
||||
goto scopy;
|
||||
|
||||
case 'g': // Float.
|
||||
}
|
||||
else static if (fmt[0] == 'g') // Float
|
||||
{
|
||||
fv = va_arg!double(va);
|
||||
if (precision == -1)
|
||||
{
|
||||
@ -699,7 +563,7 @@ pure nothrow @nogc
|
||||
fv,
|
||||
(precision - 1) | 0x80000000))
|
||||
{
|
||||
fl |= Modifier.negative;
|
||||
negative = true;
|
||||
}
|
||||
|
||||
// Clamp the precision and delete extra zeros after clamp.
|
||||
@ -747,25 +611,9 @@ pure nothrow @nogc
|
||||
}
|
||||
goto dofloatfromg;
|
||||
|
||||
case 'e': // Float.
|
||||
fv = va_arg!double(va);
|
||||
if (precision == -1)
|
||||
{
|
||||
precision = 6; // Default is 6.
|
||||
}
|
||||
// read the double into a string
|
||||
if (real2String(sn,
|
||||
l,
|
||||
num.ptr,
|
||||
decimalPos,
|
||||
fv,
|
||||
precision | 0x80000000))
|
||||
{
|
||||
fl |= Modifier.negative;
|
||||
}
|
||||
doexpfromg:
|
||||
tail[0] = 0;
|
||||
leadSign(fl, lead.ptr);
|
||||
leadSign(negative, lead);
|
||||
if (decimalPos == special)
|
||||
{
|
||||
s = cast(char*) sn;
|
||||
@ -821,21 +669,9 @@ pure nothrow @nogc
|
||||
}
|
||||
goto flt_lead;
|
||||
|
||||
case 'f': // Float.
|
||||
fv = va_arg!double(va);
|
||||
doafloat:
|
||||
if (precision == -1)
|
||||
{
|
||||
precision = 6; // Default is 6.
|
||||
}
|
||||
// Read the double into a string.
|
||||
if (real2String(sn, l, num.ptr, decimalPos, fv, precision))
|
||||
{
|
||||
fl |= Modifier.negative;
|
||||
}
|
||||
dofloatfromg:
|
||||
tail[0] = 0;
|
||||
leadSign(fl, lead.ptr);
|
||||
leadSign(negative, lead);
|
||||
if (decimalPos == special)
|
||||
{
|
||||
s = cast(char*) sn;
|
||||
@ -971,21 +807,16 @@ pure nothrow @nogc
|
||||
// Get the length that we copied.
|
||||
l = cast(uint) (s - (num.ptr + 64));
|
||||
s = num.ptr + 64;
|
||||
goto scopy;
|
||||
|
||||
case 'p': // Pointer
|
||||
static if (size_t.sizeof == 8)
|
||||
{
|
||||
fl |= Modifier.intMax;
|
||||
}
|
||||
|
||||
else static if (fmt[0] == 'p') // Pointer
|
||||
{
|
||||
l = (4 << 4) | (4 << 8);
|
||||
lead[0] = 2;
|
||||
lead[1] = '0';
|
||||
lead[2] = 'x';
|
||||
radixnum:
|
||||
|
||||
// Get the number.
|
||||
if (fl & Modifier.intMax)
|
||||
static if (size_t.sizeof == 8)
|
||||
{
|
||||
n64 = va_arg!ulong(va);
|
||||
}
|
||||
@ -994,60 +825,53 @@ pure nothrow @nogc
|
||||
n64 = va_arg!uint(va);
|
||||
}
|
||||
|
||||
s = num.ptr + NUMSZ;
|
||||
s = num.ptr + num.length;
|
||||
decimalPos = 0;
|
||||
// Clear tail, and clear leading if value is zero.
|
||||
tail[0] = 0;
|
||||
if (n64 == 0)
|
||||
{
|
||||
lead[0] = 0;
|
||||
if (precision == 0)
|
||||
{
|
||||
l = 0;
|
||||
goto scopy;
|
||||
}
|
||||
}
|
||||
// Convert to string.
|
||||
for (;;)
|
||||
{
|
||||
*--s = hex[cast(size_t) (n64 & ((1 << (l >> 8)) - 1))];
|
||||
n64 >>= (l >> 8);
|
||||
if (!((n64) || (cast(int) ((num.ptr + NUMSZ) - s) < precision)))
|
||||
n64 >>= l >> 8;
|
||||
if (n64 == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Get the length that we copied.
|
||||
l = cast(uint)((num.ptr + NUMSZ) - s);
|
||||
// Copy it.
|
||||
goto scopy;
|
||||
|
||||
case 'u': // Unsigned.
|
||||
case 'i': // Signed.
|
||||
l = cast(uint)((num.ptr + num.length) - s);
|
||||
}
|
||||
else static if (fmt[0] == 'u' || fmt[0] == 'i' || fmt[0] == 'l') // Integer
|
||||
{
|
||||
// Get the integer and abs it.
|
||||
if (fl & Modifier.intMax)
|
||||
if (fmt[0] == 'l')
|
||||
{
|
||||
long i64 = va_arg!long(va);
|
||||
n64 = cast(ulong) i64;
|
||||
if ((f[0] != 'u') && (i64 < 0))
|
||||
if ((fmt[0] != 'u') && (i64 < 0))
|
||||
{
|
||||
n64 = cast(ulong) -i64;
|
||||
fl |= Modifier.negative;
|
||||
negative = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int i = va_arg!int(va);
|
||||
n64 = cast(uint) i;
|
||||
if ((f[0] != 'u') && (i < 0))
|
||||
if ((fmt[0] != 'u') && (i < 0))
|
||||
{
|
||||
n64 = cast(uint) -i;
|
||||
fl |= Modifier.negative;
|
||||
negative = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert to string.
|
||||
s = num.ptr + NUMSZ;
|
||||
s = num.ptr + num.length;
|
||||
l = 0;
|
||||
|
||||
for (;;)
|
||||
@ -1078,7 +902,7 @@ pure nothrow @nogc
|
||||
}
|
||||
if (n64 == 0)
|
||||
{
|
||||
if ((s[0] == '0') && (s != (num.ptr + NUMSZ)))
|
||||
if ((s[0] == '0') && (s != (num.ptr + num.length)))
|
||||
{
|
||||
++s;
|
||||
}
|
||||
@ -1091,10 +915,10 @@ pure nothrow @nogc
|
||||
}
|
||||
|
||||
tail[0] = 0;
|
||||
leadSign(fl, lead.ptr);
|
||||
leadSign(negative, lead);
|
||||
|
||||
// Get the length that we copied.
|
||||
l = cast(uint) ((num.ptr + NUMSZ) - s);
|
||||
l = cast(uint) ((num.ptr + num.length) - s);
|
||||
if (l == 0)
|
||||
{
|
||||
*--s = '0';
|
||||
@ -1104,6 +928,11 @@ pure nothrow @nogc
|
||||
{
|
||||
precision = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert(false);
|
||||
}
|
||||
|
||||
scopy:
|
||||
// Get fw=leading/trailing space, precision=leading zeros.
|
||||
@ -1112,45 +941,13 @@ pure nothrow @nogc
|
||||
precision = l;
|
||||
}
|
||||
n = precision + lead[0] + tail[0] + tz;
|
||||
if (fw < cast(int) n)
|
||||
{
|
||||
fw = n;
|
||||
}
|
||||
fw -= n;
|
||||
precision -= l;
|
||||
|
||||
// Copy the spaces and/or zeros.
|
||||
if (fw + precision)
|
||||
if (precision)
|
||||
{
|
||||
int i;
|
||||
|
||||
// copy leading spaces (or when doing %8.4d stuff)
|
||||
while (fw > 0)
|
||||
{
|
||||
i = fw;
|
||||
fw -= i;
|
||||
while (i)
|
||||
{
|
||||
if (((cast(size_t) bf) & 3) == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
*bf++ = ' ';
|
||||
--i;
|
||||
}
|
||||
while (i >= 4)
|
||||
{
|
||||
*cast(uint*) bf = 0x20202020;
|
||||
bf += 4;
|
||||
i -= 4;
|
||||
}
|
||||
while (i)
|
||||
{
|
||||
*bf++ = ' ';
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
// copy leader
|
||||
sn = lead.ptr + 1;
|
||||
while (lead[0])
|
||||
@ -1258,32 +1055,17 @@ pure nothrow @nogc
|
||||
--i;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default: // Unknown, just copy code.
|
||||
s = num.ptr + NUMSZ - 1;
|
||||
*s = f[0];
|
||||
l = 1;
|
||||
fw = precision = fl = 0;
|
||||
lead[0] = 0;
|
||||
tail[0] = 0;
|
||||
precision = 0;
|
||||
decimalPos = 0;
|
||||
goto scopy;
|
||||
}
|
||||
f.popFront();
|
||||
}
|
||||
|
||||
*bf = 0;
|
||||
return buf[0 .. tlen + cast(int) (bf - buf.ptr)];
|
||||
}
|
||||
|
||||
char[] format(string fmt)(return char[] buf, ...)
|
||||
char[] format(string fmt, Args...)(return char[] buf, ...)
|
||||
nothrow
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, buf);
|
||||
auto result = vsprintf!fmt(buf, va);
|
||||
auto result = vsprintf!(fmt, Args)(buf, va);
|
||||
va_end(va);
|
||||
return result;
|
||||
}
|
||||
@ -1292,75 +1074,59 @@ nothrow unittest
|
||||
{
|
||||
char[318] buffer;
|
||||
|
||||
// Format without arguments.
|
||||
assert(format!""(buffer) == "");
|
||||
assert(format!"asdfqweryxcvz"(buffer) == "asdfqweryxcvz");
|
||||
|
||||
// Modifiers.
|
||||
assert(format!"%g"(buffer, 8.5) == "8.5");
|
||||
assert(format!"%5g"(buffer, 8.6) == " 8.6");
|
||||
assert(format!"%i"(buffer, 1000) == "1000");
|
||||
assert(format!"%*i"(buffer, 5, 1) == " 1");
|
||||
assert(format!"%.1f"(buffer, 10.25) == "10.3");
|
||||
assert(format!"%.*f"(buffer, 1, 10.25) == "10.3");
|
||||
assert(format!"%i"(buffer, 1) == "1");
|
||||
assert(format!"%7.3g"(buffer, 0.01) == " 0.01");
|
||||
assert(format!("g", double)(buffer, 8.5) == "8.5");
|
||||
assert(format!("g", double)(buffer, 8.6) == "8.6");
|
||||
assert(format!("i", int)(buffer, 1000) == "1000");
|
||||
assert(format!("i", int)(buffer, 1) == "1");
|
||||
assert(format!("g", double)(buffer, 10.25) == "10.25");
|
||||
assert(format!("i", int)(buffer, 1) == "1");
|
||||
assert(format!("g", double)(buffer, 0.01) == "0.01");
|
||||
|
||||
// Integer size.
|
||||
assert(format!"%hi"(buffer, 10) == "10");
|
||||
assert(format!"%li"(buffer, 10) == "10");
|
||||
assert(format!"%li"(buffer, 10L) == "10");
|
||||
assert(format!("i", short)(buffer, 10) == "10");
|
||||
assert(format!("l", long)(buffer, 10L) == "10");
|
||||
|
||||
// String printing.
|
||||
assert(format!"%s"(buffer, "Some weired string") == "Some weired string");
|
||||
assert(format!"%s"(buffer, cast(string) null) == "null");
|
||||
assert(format!"%.4s"(buffer, "Some weired string") == "Some");
|
||||
assert(format!"%c"(buffer, 'c') == "c");
|
||||
assert(format!("s", string)(buffer, "Some weired string") == "Some weired string");
|
||||
assert(format!("s", string)(buffer, cast(string) null) == "null");
|
||||
assert(format!("c", char)(buffer, 'c') == "c");
|
||||
|
||||
// Integer conversions.
|
||||
assert(format!"%i"(buffer, 8) == "8");
|
||||
assert(format!"%i"(buffer, 8) == "8");
|
||||
assert(format!"%i"(buffer, -8) == "-8");
|
||||
assert(format!"%li"(buffer, -8L) == "-8");
|
||||
assert(format!"%u"(buffer, 8) == "8");
|
||||
assert(format!"%i"(buffer, 100000001) == "100000001");
|
||||
assert(format!"%.12i"(buffer, 99999999L) == "000099999999");
|
||||
assert(format!"%i"(buffer, 100000001) == "100000001");
|
||||
assert(format!("i", int)(buffer, 8) == "8");
|
||||
assert(format!("i", int)(buffer, 8) == "8");
|
||||
assert(format!("i", int)(buffer, -8) == "-8");
|
||||
assert(format!("l", long)(buffer, -8L) == "-8");
|
||||
assert(format!("u", uint)(buffer, 8) == "8");
|
||||
assert(format!("i", int)(buffer, 100000001) == "100000001");
|
||||
assert(format!("i", int)(buffer, 99999999L) == "99999999");
|
||||
|
||||
// Floating point conversions.
|
||||
assert(format!"%g"(buffer, 0.1234) == "0.1234");
|
||||
assert(format!"%g"(buffer, 0.3) == "0.3");
|
||||
assert(format!"%g"(buffer, 0.333333333333) == "0.333333");
|
||||
assert(format!"%g"(buffer, 38234.1234) == "38234.1");
|
||||
assert(format!"%g"(buffer, -0.3) == "-0.3");
|
||||
assert(format!"%g"(buffer, 0.000000000000000006) == "6e-18");
|
||||
assert(format!"%g"(buffer, 0.0) == "0");
|
||||
assert(format!"%f"(buffer, 0.0) == "0.000000");
|
||||
assert(format!"%f"(buffer, double.init) == "NaN");
|
||||
assert(format!"%f"(buffer, double.infinity) == "Inf");
|
||||
assert(format!"%.0g"(buffer, 0.0) == "0");
|
||||
assert(format!"%f"(buffer, 0.000000000000000000000000003) == "0.000000");
|
||||
assert(format!"%g"(buffer, 0.23432e304) == "2.3432e+303");
|
||||
assert(format!"%f"(buffer, -0.23432e8) == "-23432000.000000");
|
||||
assert(format!"%e"(buffer, double.init) == "NaN");
|
||||
assert(format!"%f"(buffer, 1e-307) == "0.000000");
|
||||
assert(format!"%f"(buffer, 1e+8) == "100000000.000000");
|
||||
assert(format!"%05g"(buffer, 111234.1) == "111234");
|
||||
assert(format!"%.2g"(buffer, double.init) == "Na");
|
||||
assert(format!"%.1e"(buffer, 0.999) == "1.0e+00");
|
||||
assert(format!"%.0f"(buffer, 0.999) == "1");
|
||||
assert(format!"%.9f"(buffer, 1e-307) == "0.000000000");
|
||||
assert(format!"%g"(buffer, 0x1p-16382L)); // "6.95336e-310"
|
||||
assert(format!"%f"(buffer, 1e+3) == "1000.000000");
|
||||
assert(format!"%g"(buffer, 38234.1234) == "38234.1");
|
||||
assert(format!("g", double)(buffer, 0.1234) == "0.1234");
|
||||
assert(format!("g", double)(buffer, 0.3) == "0.3");
|
||||
assert(format!("g", double)(buffer, 0.333333333333) == "0.333333");
|
||||
assert(format!("g", double)(buffer, 38234.1234) == "38234.1");
|
||||
assert(format!("g", double)(buffer, -0.3) == "-0.3");
|
||||
assert(format!("g", double)(buffer, 0.000000000000000006) == "6e-18");
|
||||
assert(format!("g", double)(buffer, 0.0) == "0");
|
||||
assert(format!("g", double)(buffer, double.init) == "NaN");
|
||||
assert(format!("g", double)(buffer, -double.init) == "-NaN");
|
||||
assert(format!("g", double)(buffer, double.infinity) == "Inf");
|
||||
assert(format!("g", double)(buffer, -double.infinity) == "-Inf");
|
||||
assert(format!("g", double)(buffer, 0.000000000000000000000000003) == "3e-27");
|
||||
assert(format!("g", double)(buffer, 0.23432e304) == "2.3432e+303");
|
||||
assert(format!("g", double)(buffer, -0.23432e8) == "-2.3432e+07");
|
||||
assert(format!("g", double)(buffer, 1e-307) == "1e-307");
|
||||
assert(format!("g", double)(buffer, 1e+8) == "1e+08");
|
||||
assert(format!("g", double)(buffer, 111234.1) == "111234");
|
||||
assert(format!("g", double)(buffer, 0.999) == "0.999");
|
||||
assert(format!("g", double)(buffer, 0x1p-16382L)); // "6.95336e-310"
|
||||
assert(format!("g", double)(buffer, 1e+3) == "1000");
|
||||
assert(format!("g", double)(buffer, 38234.1234) == "38234.1");
|
||||
|
||||
// Pointer conversions.
|
||||
assert(format!"%p"(buffer, cast(void*) 1) == "0x1");
|
||||
assert(format!"%p"(buffer, cast(void*) 20) == "0x14");
|
||||
|
||||
// Unknown specifier.
|
||||
assert(format!"%k"(buffer) == "k");
|
||||
assert(format!"%%k"(buffer) == "%k");
|
||||
// Pointer convesions.
|
||||
assert(format!("p", void*)(buffer, cast(void*) 1) == "0x1");
|
||||
assert(format!("p", void*)(buffer, cast(void*) 20) == "0x14");
|
||||
}
|
||||
|
||||
private struct FormatSpec
|
||||
|
Loading…
Reference in New Issue
Block a user