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
|
* of the decimal point in decimalPos. +/-Inf and NaN are specified by special
|
||||||
* values returned in the decimalPos parameter.
|
* values returned in the decimalPos parameter.
|
||||||
* fracDigits is absolute normally, but if you want from first significant
|
* 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,
|
private int real2String(ref const(char)* start,
|
||||||
ref uint len,
|
ref uint len,
|
||||||
@ -425,24 +425,17 @@ private int real2String(ref const(char)* start,
|
|||||||
return ng;
|
return ng;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void leadSign(uint fl, char* sign)
|
private void leadSign(bool negative, ref char[8] sign)
|
||||||
pure nothrow @nogc
|
pure nothrow @nogc
|
||||||
{
|
{
|
||||||
sign[0] = 0;
|
sign[0] = 0;
|
||||||
if (fl & Modifier.negative)
|
if (negative)
|
||||||
{
|
{
|
||||||
sign[0] = 1;
|
sign[0] = 1;
|
||||||
sign[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).
|
// Copies d to bits w/ strict aliasing (this compiles to nothing on /Ox).
|
||||||
private void copyFp(T, U)(ref T dest, ref U src)
|
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;
|
ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
private char[] vsprintf(string fmt, Args...)(return char[] buf, va_list va)
|
||||||
* 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)
|
|
||||||
pure nothrow @nogc
|
pure nothrow @nogc
|
||||||
{
|
{
|
||||||
char* bf = buf.ptr;
|
char* bf = buf.ptr;
|
||||||
string f = fmt;
|
|
||||||
int tlen;
|
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.
|
// Ok, we have a percent, read the modifiers first.
|
||||||
int fw = 0;
|
|
||||||
int precision = -1;
|
int precision = -1;
|
||||||
int tz = 0;
|
int tz = 0;
|
||||||
uint fl = 0;
|
bool negative;
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handle each replacement.
|
// Handle each replacement.
|
||||||
enum NUMSZ = 512; // Big enough for e308 (with commas) or e-307.
|
char[512] num; // Big enough for e308 (with commas) or e-307.
|
||||||
char[NUMSZ] num;
|
|
||||||
char[8] lead;
|
char[8] lead;
|
||||||
char[8] tail;
|
char[8] tail;
|
||||||
char *s;
|
char *s;
|
||||||
@ -610,9 +488,8 @@ pure nothrow @nogc
|
|||||||
int decimalPos;
|
int decimalPos;
|
||||||
const(char)* sn;
|
const(char)* sn;
|
||||||
|
|
||||||
switch (f[0])
|
static if (fmt[0] == 's') // String
|
||||||
{
|
{
|
||||||
case 's':
|
|
||||||
// Get the string.
|
// Get the string.
|
||||||
s = va_arg!(char[])(va).ptr;
|
s = va_arg!(char[])(va).ptr;
|
||||||
if (s is null)
|
if (s is null)
|
||||||
@ -635,15 +512,6 @@ pure nothrow @nogc
|
|||||||
++sn;
|
++sn;
|
||||||
}
|
}
|
||||||
n = 0xffffffff;
|
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)
|
while (n)
|
||||||
{
|
{
|
||||||
uint v = *cast(uint*) sn;
|
uint v = *cast(uint*) sn;
|
||||||
@ -655,33 +523,29 @@ pure nothrow @nogc
|
|||||||
--n;
|
--n;
|
||||||
}
|
}
|
||||||
goto lchk;
|
goto lchk;
|
||||||
ld:
|
|
||||||
|
|
||||||
|
ld:
|
||||||
l = cast(uint) (sn - s);
|
l = cast(uint) (sn - s);
|
||||||
// Clamp to precision.
|
|
||||||
if (l > cast(uint) precision)
|
|
||||||
{
|
|
||||||
l = precision;
|
|
||||||
}
|
|
||||||
lead[0] = 0;
|
lead[0] = 0;
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
precision = 0;
|
precision = 0;
|
||||||
decimalPos = 0;
|
decimalPos = 0;
|
||||||
// Copy the string in.
|
// Copy the string in.
|
||||||
goto scopy;
|
}
|
||||||
|
else static if (fmt[0] == 'c') // Char
|
||||||
case 'c': // Char.
|
{
|
||||||
// Get the character.
|
// Get the character.
|
||||||
s = num.ptr + NUMSZ - 1;
|
s = num.ptr + num.length - 1;
|
||||||
*s = cast(char) va_arg!int(va);
|
*s = cast(char) va_arg!int(va);
|
||||||
l = 1;
|
l = 1;
|
||||||
lead[0] = 0;
|
lead[0] = 0;
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
precision = 0;
|
precision = 0;
|
||||||
decimalPos = 0;
|
decimalPos = 0;
|
||||||
goto scopy;
|
}
|
||||||
|
else static if (fmt[0] == 'g') // Float
|
||||||
case 'g': // Float.
|
{
|
||||||
fv = va_arg!double(va);
|
fv = va_arg!double(va);
|
||||||
if (precision == -1)
|
if (precision == -1)
|
||||||
{
|
{
|
||||||
@ -699,7 +563,7 @@ pure nothrow @nogc
|
|||||||
fv,
|
fv,
|
||||||
(precision - 1) | 0x80000000))
|
(precision - 1) | 0x80000000))
|
||||||
{
|
{
|
||||||
fl |= Modifier.negative;
|
negative = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clamp the precision and delete extra zeros after clamp.
|
// Clamp the precision and delete extra zeros after clamp.
|
||||||
@ -747,25 +611,9 @@ pure nothrow @nogc
|
|||||||
}
|
}
|
||||||
goto dofloatfromg;
|
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:
|
doexpfromg:
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
leadSign(fl, lead.ptr);
|
leadSign(negative, lead);
|
||||||
if (decimalPos == special)
|
if (decimalPos == special)
|
||||||
{
|
{
|
||||||
s = cast(char*) sn;
|
s = cast(char*) sn;
|
||||||
@ -821,21 +669,9 @@ pure nothrow @nogc
|
|||||||
}
|
}
|
||||||
goto flt_lead;
|
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:
|
dofloatfromg:
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
leadSign(fl, lead.ptr);
|
leadSign(negative, lead);
|
||||||
if (decimalPos == special)
|
if (decimalPos == special)
|
||||||
{
|
{
|
||||||
s = cast(char*) sn;
|
s = cast(char*) sn;
|
||||||
@ -971,21 +807,16 @@ pure nothrow @nogc
|
|||||||
// Get the length that we copied.
|
// Get the length that we copied.
|
||||||
l = cast(uint) (s - (num.ptr + 64));
|
l = cast(uint) (s - (num.ptr + 64));
|
||||||
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);
|
l = (4 << 4) | (4 << 8);
|
||||||
lead[0] = 2;
|
lead[0] = 2;
|
||||||
lead[1] = '0';
|
lead[1] = '0';
|
||||||
lead[2] = 'x';
|
lead[2] = 'x';
|
||||||
radixnum:
|
|
||||||
// Get the number.
|
// Get the number.
|
||||||
if (fl & Modifier.intMax)
|
static if (size_t.sizeof == 8)
|
||||||
{
|
{
|
||||||
n64 = va_arg!ulong(va);
|
n64 = va_arg!ulong(va);
|
||||||
}
|
}
|
||||||
@ -994,60 +825,53 @@ pure nothrow @nogc
|
|||||||
n64 = va_arg!uint(va);
|
n64 = va_arg!uint(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
s = num.ptr + NUMSZ;
|
s = num.ptr + num.length;
|
||||||
decimalPos = 0;
|
decimalPos = 0;
|
||||||
// Clear tail, and clear leading if value is zero.
|
// Clear tail, and clear leading if value is zero.
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
if (n64 == 0)
|
if (n64 == 0)
|
||||||
{
|
{
|
||||||
lead[0] = 0;
|
lead[0] = 0;
|
||||||
if (precision == 0)
|
|
||||||
{
|
|
||||||
l = 0;
|
|
||||||
goto scopy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Convert to string.
|
// Convert to string.
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
*--s = hex[cast(size_t) (n64 & ((1 << (l >> 8)) - 1))];
|
*--s = hex[cast(size_t) (n64 & ((1 << (l >> 8)) - 1))];
|
||||||
n64 >>= (l >> 8);
|
n64 >>= l >> 8;
|
||||||
if (!((n64) || (cast(int) ((num.ptr + NUMSZ) - s) < precision)))
|
if (n64 == 0)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Get the length that we copied.
|
// Get the length that we copied.
|
||||||
l = cast(uint)((num.ptr + NUMSZ) - s);
|
l = cast(uint)((num.ptr + num.length) - s);
|
||||||
// Copy it.
|
}
|
||||||
goto scopy;
|
else static if (fmt[0] == 'u' || fmt[0] == 'i' || fmt[0] == 'l') // Integer
|
||||||
|
{
|
||||||
case 'u': // Unsigned.
|
|
||||||
case 'i': // Signed.
|
|
||||||
// Get the integer and abs it.
|
// Get the integer and abs it.
|
||||||
if (fl & Modifier.intMax)
|
if (fmt[0] == 'l')
|
||||||
{
|
{
|
||||||
long i64 = va_arg!long(va);
|
long i64 = va_arg!long(va);
|
||||||
n64 = cast(ulong) i64;
|
n64 = cast(ulong) i64;
|
||||||
if ((f[0] != 'u') && (i64 < 0))
|
if ((fmt[0] != 'u') && (i64 < 0))
|
||||||
{
|
{
|
||||||
n64 = cast(ulong) -i64;
|
n64 = cast(ulong) -i64;
|
||||||
fl |= Modifier.negative;
|
negative = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
int i = va_arg!int(va);
|
int i = va_arg!int(va);
|
||||||
n64 = cast(uint) i;
|
n64 = cast(uint) i;
|
||||||
if ((f[0] != 'u') && (i < 0))
|
if ((fmt[0] != 'u') && (i < 0))
|
||||||
{
|
{
|
||||||
n64 = cast(uint) -i;
|
n64 = cast(uint) -i;
|
||||||
fl |= Modifier.negative;
|
negative = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to string.
|
// Convert to string.
|
||||||
s = num.ptr + NUMSZ;
|
s = num.ptr + num.length;
|
||||||
l = 0;
|
l = 0;
|
||||||
|
|
||||||
for (;;)
|
for (;;)
|
||||||
@ -1078,7 +902,7 @@ pure nothrow @nogc
|
|||||||
}
|
}
|
||||||
if (n64 == 0)
|
if (n64 == 0)
|
||||||
{
|
{
|
||||||
if ((s[0] == '0') && (s != (num.ptr + NUMSZ)))
|
if ((s[0] == '0') && (s != (num.ptr + num.length)))
|
||||||
{
|
{
|
||||||
++s;
|
++s;
|
||||||
}
|
}
|
||||||
@ -1091,10 +915,10 @@ pure nothrow @nogc
|
|||||||
}
|
}
|
||||||
|
|
||||||
tail[0] = 0;
|
tail[0] = 0;
|
||||||
leadSign(fl, lead.ptr);
|
leadSign(negative, lead);
|
||||||
|
|
||||||
// Get the length that we copied.
|
// Get the length that we copied.
|
||||||
l = cast(uint) ((num.ptr + NUMSZ) - s);
|
l = cast(uint) ((num.ptr + num.length) - s);
|
||||||
if (l == 0)
|
if (l == 0)
|
||||||
{
|
{
|
||||||
*--s = '0';
|
*--s = '0';
|
||||||
@ -1104,6 +928,11 @@ pure nothrow @nogc
|
|||||||
{
|
{
|
||||||
precision = 0;
|
precision = 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
static assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
scopy:
|
scopy:
|
||||||
// Get fw=leading/trailing space, precision=leading zeros.
|
// Get fw=leading/trailing space, precision=leading zeros.
|
||||||
@ -1112,45 +941,13 @@ pure nothrow @nogc
|
|||||||
precision = l;
|
precision = l;
|
||||||
}
|
}
|
||||||
n = precision + lead[0] + tail[0] + tz;
|
n = precision + lead[0] + tail[0] + tz;
|
||||||
if (fw < cast(int) n)
|
|
||||||
{
|
|
||||||
fw = n;
|
|
||||||
}
|
|
||||||
fw -= n;
|
|
||||||
precision -= l;
|
precision -= l;
|
||||||
|
|
||||||
// Copy the spaces and/or zeros.
|
// Copy the spaces and/or zeros.
|
||||||
if (fw + precision)
|
if (precision)
|
||||||
{
|
{
|
||||||
int i;
|
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
|
// copy leader
|
||||||
sn = lead.ptr + 1;
|
sn = lead.ptr + 1;
|
||||||
while (lead[0])
|
while (lead[0])
|
||||||
@ -1258,32 +1055,17 @@ pure nothrow @nogc
|
|||||||
--i;
|
--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;
|
*bf = 0;
|
||||||
return buf[0 .. tlen + cast(int) (bf - buf.ptr)];
|
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
|
nothrow
|
||||||
{
|
{
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, buf);
|
va_start(va, buf);
|
||||||
auto result = vsprintf!fmt(buf, va);
|
auto result = vsprintf!(fmt, Args)(buf, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1292,75 +1074,59 @@ nothrow unittest
|
|||||||
{
|
{
|
||||||
char[318] buffer;
|
char[318] buffer;
|
||||||
|
|
||||||
// Format without arguments.
|
|
||||||
assert(format!""(buffer) == "");
|
|
||||||
assert(format!"asdfqweryxcvz"(buffer) == "asdfqweryxcvz");
|
|
||||||
|
|
||||||
// Modifiers.
|
// Modifiers.
|
||||||
assert(format!"%g"(buffer, 8.5) == "8.5");
|
assert(format!("g", double)(buffer, 8.5) == "8.5");
|
||||||
assert(format!"%5g"(buffer, 8.6) == " 8.6");
|
assert(format!("g", double)(buffer, 8.6) == "8.6");
|
||||||
assert(format!"%i"(buffer, 1000) == "1000");
|
assert(format!("i", int)(buffer, 1000) == "1000");
|
||||||
assert(format!"%*i"(buffer, 5, 1) == " 1");
|
assert(format!("i", int)(buffer, 1) == "1");
|
||||||
assert(format!"%.1f"(buffer, 10.25) == "10.3");
|
assert(format!("g", double)(buffer, 10.25) == "10.25");
|
||||||
assert(format!"%.*f"(buffer, 1, 10.25) == "10.3");
|
assert(format!("i", int)(buffer, 1) == "1");
|
||||||
assert(format!"%i"(buffer, 1) == "1");
|
assert(format!("g", double)(buffer, 0.01) == "0.01");
|
||||||
assert(format!"%7.3g"(buffer, 0.01) == " 0.01");
|
|
||||||
|
|
||||||
// Integer size.
|
// Integer size.
|
||||||
assert(format!"%hi"(buffer, 10) == "10");
|
assert(format!("i", short)(buffer, 10) == "10");
|
||||||
assert(format!"%li"(buffer, 10) == "10");
|
assert(format!("l", long)(buffer, 10L) == "10");
|
||||||
assert(format!"%li"(buffer, 10L) == "10");
|
|
||||||
|
|
||||||
// String printing.
|
// String printing.
|
||||||
assert(format!"%s"(buffer, "Some weired string") == "Some weired string");
|
assert(format!("s", string)(buffer, "Some weired string") == "Some weired string");
|
||||||
assert(format!"%s"(buffer, cast(string) null) == "null");
|
assert(format!("s", string)(buffer, cast(string) null) == "null");
|
||||||
assert(format!"%.4s"(buffer, "Some weired string") == "Some");
|
assert(format!("c", char)(buffer, 'c') == "c");
|
||||||
assert(format!"%c"(buffer, 'c') == "c");
|
|
||||||
|
|
||||||
// Integer conversions.
|
// Integer conversions.
|
||||||
assert(format!"%i"(buffer, 8) == "8");
|
assert(format!("i", int)(buffer, 8) == "8");
|
||||||
assert(format!"%i"(buffer, 8) == "8");
|
assert(format!("i", int)(buffer, 8) == "8");
|
||||||
assert(format!"%i"(buffer, -8) == "-8");
|
assert(format!("i", int)(buffer, -8) == "-8");
|
||||||
assert(format!"%li"(buffer, -8L) == "-8");
|
assert(format!("l", long)(buffer, -8L) == "-8");
|
||||||
assert(format!"%u"(buffer, 8) == "8");
|
assert(format!("u", uint)(buffer, 8) == "8");
|
||||||
assert(format!"%i"(buffer, 100000001) == "100000001");
|
assert(format!("i", int)(buffer, 100000001) == "100000001");
|
||||||
assert(format!"%.12i"(buffer, 99999999L) == "000099999999");
|
assert(format!("i", int)(buffer, 99999999L) == "99999999");
|
||||||
assert(format!"%i"(buffer, 100000001) == "100000001");
|
|
||||||
|
|
||||||
// Floating point conversions.
|
// Floating point conversions.
|
||||||
assert(format!"%g"(buffer, 0.1234) == "0.1234");
|
assert(format!("g", double)(buffer, 0.1234) == "0.1234");
|
||||||
assert(format!"%g"(buffer, 0.3) == "0.3");
|
assert(format!("g", double)(buffer, 0.3) == "0.3");
|
||||||
assert(format!"%g"(buffer, 0.333333333333) == "0.333333");
|
assert(format!("g", double)(buffer, 0.333333333333) == "0.333333");
|
||||||
assert(format!"%g"(buffer, 38234.1234) == "38234.1");
|
assert(format!("g", double)(buffer, 38234.1234) == "38234.1");
|
||||||
assert(format!"%g"(buffer, -0.3) == "-0.3");
|
assert(format!("g", double)(buffer, -0.3) == "-0.3");
|
||||||
assert(format!"%g"(buffer, 0.000000000000000006) == "6e-18");
|
assert(format!("g", double)(buffer, 0.000000000000000006) == "6e-18");
|
||||||
assert(format!"%g"(buffer, 0.0) == "0");
|
assert(format!("g", double)(buffer, 0.0) == "0");
|
||||||
assert(format!"%f"(buffer, 0.0) == "0.000000");
|
assert(format!("g", double)(buffer, double.init) == "NaN");
|
||||||
assert(format!"%f"(buffer, double.init) == "NaN");
|
assert(format!("g", double)(buffer, -double.init) == "-NaN");
|
||||||
assert(format!"%f"(buffer, double.infinity) == "Inf");
|
assert(format!("g", double)(buffer, double.infinity) == "Inf");
|
||||||
assert(format!"%.0g"(buffer, 0.0) == "0");
|
assert(format!("g", double)(buffer, -double.infinity) == "-Inf");
|
||||||
assert(format!"%f"(buffer, 0.000000000000000000000000003) == "0.000000");
|
assert(format!("g", double)(buffer, 0.000000000000000000000000003) == "3e-27");
|
||||||
assert(format!"%g"(buffer, 0.23432e304) == "2.3432e+303");
|
assert(format!("g", double)(buffer, 0.23432e304) == "2.3432e+303");
|
||||||
assert(format!"%f"(buffer, -0.23432e8) == "-23432000.000000");
|
assert(format!("g", double)(buffer, -0.23432e8) == "-2.3432e+07");
|
||||||
assert(format!"%e"(buffer, double.init) == "NaN");
|
assert(format!("g", double)(buffer, 1e-307) == "1e-307");
|
||||||
assert(format!"%f"(buffer, 1e-307) == "0.000000");
|
assert(format!("g", double)(buffer, 1e+8) == "1e+08");
|
||||||
assert(format!"%f"(buffer, 1e+8) == "100000000.000000");
|
assert(format!("g", double)(buffer, 111234.1) == "111234");
|
||||||
assert(format!"%05g"(buffer, 111234.1) == "111234");
|
assert(format!("g", double)(buffer, 0.999) == "0.999");
|
||||||
assert(format!"%.2g"(buffer, double.init) == "Na");
|
assert(format!("g", double)(buffer, 0x1p-16382L)); // "6.95336e-310"
|
||||||
assert(format!"%.1e"(buffer, 0.999) == "1.0e+00");
|
assert(format!("g", double)(buffer, 1e+3) == "1000");
|
||||||
assert(format!"%.0f"(buffer, 0.999) == "1");
|
assert(format!("g", double)(buffer, 38234.1234) == "38234.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");
|
|
||||||
|
|
||||||
// Pointer conversions.
|
// Pointer convesions.
|
||||||
assert(format!"%p"(buffer, cast(void*) 1) == "0x1");
|
assert(format!("p", void*)(buffer, cast(void*) 1) == "0x1");
|
||||||
assert(format!"%p"(buffer, cast(void*) 20) == "0x14");
|
assert(format!("p", void*)(buffer, cast(void*) 20) == "0x14");
|
||||||
|
|
||||||
// Unknown specifier.
|
|
||||||
assert(format!"%k"(buffer) == "k");
|
|
||||||
assert(format!"%%k"(buffer) == "%k");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private struct FormatSpec
|
private struct FormatSpec
|
||||||
|
Loading…
Reference in New Issue
Block a user