summaryrefslogtreecommitdiff
path: root/source
diff options
context:
space:
mode:
authorEugene Wissner <belka@caraus.de>2017-09-19 15:10:24 +0200
committerEugene Wissner <belka@caraus.de>2017-09-19 15:10:24 +0200
commit3df6c833761cdeed7b9baf7bb149a452d63f9a06 (patch)
treea31be57e6778a3deea702de0a50ba83ac7897f0a /source
parent7445d42ad49f19b3251687f29330b38d670627af (diff)
downloadtanya-3df6c833761cdeed7b9baf7bb149a452d63f9a06.tar.gz
Move formatting development to the io branch
Diffstat (limited to 'source')
-rw-r--r--source/tanya/format/package.d1742
1 files changed, 1 insertions, 1741 deletions
diff --git a/source/tanya/format/package.d b/source/tanya/format/package.d
index 6add63e..152321b 100644
--- a/source/tanya/format/package.d
+++ b/source/tanya/format/package.d
@@ -14,1744 +14,4 @@
*/
module tanya.format;
-import core.stdc.stdarg;
-public import tanya.format.conv;
-import tanya.memory.op;
-import tanya.range.array;
-
-private enum special = 0x7000;
-private enum char comma = ',';
-private enum char period = '.';
-
-private static const ulong[20] powersOf10 = [
- 1,
- 10,
- 100,
- 1000,
- 10000,
- 100000,
- 1000000,
- 10000000,
- 100000000,
- 1000000000,
- 10000000000UL,
- 100000000000UL,
- 1000000000000UL,
- 10000000000000UL,
- 100000000000000UL,
- 1000000000000000UL,
- 10000000000000000UL,
- 100000000000000000UL,
- 1000000000000000000UL,
- 10000000000000000000UL,
-];
-
-private static const char[201] digitpair =
- "0001020304050607080910111213141516171819202122232425262728293031323334353"
- ~ "6373839404142434445464748495051525354555657585960616263646566676869707172"
- ~ "737475767778798081828384858687888990919293949596979899";
-
-private static const double[23] bottom = [
- 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008,
- 1e+009, 1e+010, 1e+011, 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017,
- 1e+018, 1e+019, 1e+020, 1e+021, 1e+022,
-];
-
-private static const double[22] negativeBottom = [
- 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009,
- 1e-010, 1e-011, 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018,
- 1e-019, 1e-020, 1e-021, 1e-022,
-];
-
-private static const double[13] top = [
- 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207,
- 1e+230, 1e+253, 1e+276, 1e+299,
-];
-
-private static const double[13] negativeTop = [
- 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207,
- 1e-230, 1e-253, 1e-276, 1e-299,
-];
-
-private static const double[13] topError = [
- 8388608, 6.8601809640529717e+028, -7.253143638152921e+052,
- -4.3377296974619174e+075, -1.5559416129466825e+098,
- -3.2841562489204913e+121, -3.7745893248228135e+144,
- -1.7356668416969134e+167, -3.8893577551088374e+190,
- -9.9566444326005119e+213, 6.3641293062232429e+236,
- -5.2069140800249813e+259, -5.2504760255204387e+282,
-];
-
-private static const double[22] negativeBottomError = [
- -5.551115123125783e-018, -2.0816681711721684e-019,
- -2.0816681711721686e-020, -4.7921736023859299e-021,
- -8.1803053914031305e-022, 4.5251888174113741e-023,
- 4.5251888174113739e-024, -2.0922560830128471e-025,
- -6.2281591457779853e-026, -3.6432197315497743e-027,
- 6.0503030718060191e-028, 2.0113352370744385e-029, -3.0373745563400371e-030,
- 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033,
- -7.1542424054621921e-034, -7.1542424054621926e-035,
- 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038,
- -4.8596774326570872e-039,
-];
-
-private static const double[13] negativeTopError = [
- 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086,
- 1.1875228833981544e-109, -5.0644902316928607e-132,
- -6.7156837247865426e-155, -2.812077463003139e-178,
- -5.7778912386589953e-201, 7.4997100559334532e-224,
- -4.6439668915134491e-247, -6.3691100762962136e-270,
- -9.436808465446358e-293, // 8.0970921678014997e-317,
-];
-
-private enum ulong tenTo19th = 1000000000000000000UL;
-
-private void ddmultlo(A, B, C, D, E, F)(ref A oh,
- ref B ol,
- ref C xh,
- ref D xl,
- ref E yh,
- ref F yl)
-{
- ol = ol + (xh * yl + xl * yh);
-}
-
-private void ddmultlos(A, B, C, D)(ref A oh, ref B ol, ref C xh, ref D yl)
-{
- ol = ol + (xh * yl);
-}
-
-private void ddrenorm(T, U)(ref T oh, ref U ol)
-{
- double s;
- s = oh + ol;
- ol = ol - (s - oh);
- oh = s;
-}
-
-// Power can be -323 to +350.
-private void raise2Power10(double* ohi,
- double* olo,
- double d,
- int power) pure nothrow @nogc
-{
- double ph, pl;
- if ((power >= 0) && (power <= 22))
- {
- ddmulthi(ph, pl, d, bottom[power]);
- }
- else
- {
- int e, et, eb;
- double p2h, p2l;
-
- e = power;
- if (power < 0)
- {
- e = -e;
- }
- et = (e * 0x2c9) >> 14; /* %23 */
- if (et > 13)
- {
- et = 13;
- }
- eb = e - (et * 23);
-
- ph = d;
- pl = 0.0;
- if (power < 0)
- {
- if (eb)
- {
- --eb;
- ddmulthi(ph, pl, d, negativeBottom[eb]);
- ddmultlos(ph, pl, d, negativeBottomError[eb]);
- }
- if (et)
- {
- ddrenorm(ph, pl);
- --et;
- ddmulthi(p2h, p2l, ph, negativeTop[et]);
- ddmultlo(p2h,
- p2l,
- ph,
- pl,
- negativeTop[et],
- negativeTopError[et]);
- ph = p2h;
- pl = p2l;
- }
- }
- else
- {
- if (eb)
- {
- e = eb;
- if (eb > 22)
- {
- eb = 22;
- }
- e -= eb;
- ddmulthi(ph, pl, d, bottom[eb]);
- if (e)
- {
- ddrenorm(ph, pl);
- ddmulthi(p2h, p2l, ph, bottom[e]);
- ddmultlos(p2h, p2l, bottom[e], pl);
- ph = p2h;
- pl = p2l;
- }
- }
- if (et)
- {
- ddrenorm(ph, pl);
- --et;
- ddmulthi(p2h, p2l, ph, top[et]);
- ddmultlo(p2h, p2l, ph, pl, top[et], topError[et]);
- ph = p2h;
- pl = p2l;
- }
- }
- }
- ddrenorm(ph, pl);
- *ohi = ph;
- *olo = pl;
-}
-
-/*
- * Given a float value, returns the significant bits in bits, and the position
- * 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
- */
-private int real2String(ref const(char)* start,
- ref uint len,
- char* out_,
- out int decimalPos,
- double value,
- uint fracDigits) pure nothrow @nogc
-{
- long bits = 0;
- int e, tens;
-
- double d = value;
- copyFp(bits, d);
- auto exponent = cast(int) ((bits >> 52) & 2047);
- auto ng = cast(int) (bits >> 63);
- if (ng)
- {
- d = -d;
- }
-
- if (exponent == 2047) // Is NaN or inf?
- {
- start = (bits & (((cast(ulong) 1) << 52) - 1)) ? "NaN" : "Inf";
- decimalPos = special;
- len = 3;
- return ng;
- }
-
- if (exponent == 0) // Is zero or denormal?
- {
- if ((bits << 1) == 0) // Do zero.
- {
- decimalPos = 1;
- start = out_;
- out_[0] = '0';
- len = 1;
- return ng;
- }
- // Find the right exponent for denormals.
- {
- long v = (cast(ulong) 1) << 51;
- while ((bits & v) == 0)
- {
- --exponent;
- v >>= 1;
- }
- }
- }
-
- // Find the decimal exponent as well as the decimal bits of the value.
- {
- double ph, pl;
-
- // log10 estimate - very specifically tweaked to hit or undershoot by
- // no more than 1 of log10 of all exponents 1..2046.
- tens = exponent - 1023;
- if (tens < 0)
- {
- tens = (tens * 617) / 2048;
- }
- else
- {
- tens = ((tens * 1233) / 4096) + 1;
- }
-
- // Move the significant bits into position and stick them into an int.
- raise2Power10(&ph, &pl, d, 18 - tens);
-
- // Get full as much precision from double-double as possible.
- bits = cast(long) ph;
- double vh = cast(double) bits;
- double ahi = (ph - vh);
- double t = (ahi - ph);
- double alo = (ph - (ahi - t)) - (vh + t);
- bits += cast(long) (ahi + alo + pl);
-
- // Check if we undershot.
- if ((cast(ulong) bits) >= tenTo19th)
- {
- ++tens;
- }
- }
-
- // Now do the rounding in integer land.
- if (fracDigits & 0x80000000)
- {
- fracDigits = (fracDigits & 0x7ffffff) + 1;
- }
- else
- {
- fracDigits = tens + fracDigits;
- }
- if ((fracDigits < 24))
- {
- uint dg = 1;
- if (cast(ulong) bits >= powersOf10[9])
- {
- dg = 10;
- }
- while (cast(ulong) bits >= powersOf10[dg])
- {
- ++dg;
- if (dg == 20)
- {
- goto noround;
- }
- }
- if (fracDigits < dg)
- {
- // Add 0.5 at the right position and round.
- e = dg - fracDigits;
- if (cast(uint) e >= 24)
- {
- goto noround;
- }
- ulong r = powersOf10[e];
- bits = bits + (r / 2);
- if (cast(ulong) bits >= powersOf10[dg])
- {
- ++tens;
- }
- bits /= r;
- }
- noround:
- }
-
- // Kill long trailing runs of zeros.
- if (bits)
- {
- uint n;
- for (;;)
- {
- if (bits <= 0xffffffff)
- {
- break;
- }
- if (bits % 1000)
- {
- goto donez;
- }
- bits /= 1000;
- }
- n = cast(uint) bits;
- while ((n % 1000) == 0)
- {
- n /= 1000;
- }
- bits = n;
- donez:
- }
-
- // Convert to string.
- out_ += 64;
- e = 0;
- for (;;)
- {
- uint n;
- char *o = out_ - 8;
- // Do the conversion in chunks of U32s (avoid most 64-bit divides,
- // worth it, constant denomiators be damned).
- if (bits >= 100000000)
- {
- n = cast(uint) (bits % 100000000);
- bits /= 100000000;
- }
- else
- {
- n = cast(uint) bits;
- bits = 0;
- }
- while (n)
- {
- out_ -= 2;
- *cast(ushort*) out_ = *cast(ushort*) &digitpair[(n % 100) * 2];
- n /= 100;
- e += 2;
- }
- if (bits == 0)
- {
- if ((e) && (out_[0] == '0'))
- {
- ++out_;
- --e;
- }
- break;
- }
- while (out_ != o)
- {
- *--out_ = '0';
- ++e;
- }
- }
-
- decimalPos = tens;
- start = out_;
- len = e;
- return ng;
-}
-
-private void leadSign(uint fl, char* sign)
-pure nothrow @nogc
-{
- sign[0] = 0;
- if (fl & Modifier.negative)
- {
- sign[0] = 1;
- sign[1] = '-';
- }
- else if (fl & Modifier.leadingSpace)
- {
- sign[0] = 1;
- sign[1] = ' ';
- }
- else if (fl & Modifier.leadingPlus)
- {
- sign[0] = 1;
- sign[1] = '+';
- }
-}
-
-private enum Modifier : uint
-{
- leftJust = 1,
- leadingPlus = 2,
- leadingSpace = 4,
- leading0x = 8,
- leadingZero = 16,
- intMax = 32,
- tripletComma = 64,
- 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)
-{
- for (int count = 0; count < 8; ++count)
- {
- (cast(char*) &dest)[count] = (cast(char*) &src)[count];
- }
-}
-
-private void ddmulthi(ref double oh,
- ref double ol,
- ref double xh,
- const ref double yh) pure nothrow @nogc
-{
- double ahi, bhi;
- long bt;
- oh = xh * yh;
- copyFp(bt, xh);
- bt &= ((~cast(ulong) 0) << 27);
- copyFp(ahi, bt);
- double alo = xh - ahi;
- copyFp(bt, yh);
- bt &= ((~cast(ulong) 0) << 27);
- copyFp(bhi, bt);
- double blo = yh - bhi;
- 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)
-pure nothrow @nogc
-{
- static const string hex = "0123456789abcdefxp";
- static const string hexu = "0123456789ABCDEFXP";
- char* bf = buf.ptr;
- string f = fmt;
- int tlen = 0;
-
- 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;
-
- // Flags.
- for (;;)
- {
- switch (f[0])
- {
- // If we have left justify.
- case '-':
- fl |= Modifier.leftJust;
- f.popFront();
- continue;
- // If we have leading plus.
- case '+':
- fl |= Modifier.leadingPlus;
- f.popFront();
- continue;
- // If we have leading space.
- case ' ':
- fl |= Modifier.leadingSpace;
- f.popFront();
- continue;
- // If we have leading 0x.
- case '#':
- fl |= Modifier.leading0x;
- f.popFront();
- continue;
- // If we have thousand commas.
- case '\'':
- fl |= Modifier.tripletComma;
- f.popFront();
- continue;
- // If we have leading zero.
- case '0':
- fl |= Modifier.leadingZero;
- f.popFront();
- goto flags_done;
- default:
- goto flags_done;
- }
- }
- flags_done:
-
- // 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 (unix style)
- case 'l':
- f.popFront();
- if (f[0] == 'l')
- {
- fl |= Modifier.intMax;
- f.popFront();
- }
- break;
- // are we 64-bit on intmax? (c99)
- case 'j':
- fl |= Modifier.intMax;
- f.popFront();
- break;
- // are we 64-bit on size_t or ptrdiff_t? (c99)
- case 'z':
- case 't':
- static if (size_t.sizeof == 8)
- {
- fl |= Modifier.intMax;
- }
- f.popFront();
- break;
- default:
- break;
- }
-
- // Handle each replacement.
- enum NUMSZ = 512; // Big enough for e308 (with commas) or e-307.
- char[NUMSZ] num;
- char[8] lead;
- char[8] tail;
- char *s;
- const(char)* h;
- uint l, n, cs;
- ulong n64;
-
- double fv;
-
- int decimalPos;
- const(char)* sn;
-
- switch (f[0])
- {
- case 's':
- // Get the string.
- s = va_arg!(char[])(va).ptr;
- if (s is null)
- {
- s = cast(char*) "null";
- }
- // Get the length.
- sn = s;
- for (;;)
- {
- if (((cast(size_t) sn) & 3) == 0)
- {
- break;
- }
- lchk:
- if (sn[0] == 0)
- {
- goto ld;
- }
- ++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;
- if ((v - 0x01010101) & (~v) & 0x80808080UL)
- {
- goto lchk;
- }
- sn += 4;
- --n;
- }
- goto lchk;
- 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;
- cs = 0;
- // Copy the string in.
- goto scopy;
-
- case 'c': // Char.
- // Get the character.
- s = num.ptr + NUMSZ - 1;
- *s = cast(char) va_arg!int(va);
- l = 1;
- lead[0] = 0;
- tail[0] = 0;
- precision = 0;
- decimalPos = 0;
- cs = 0;
- goto scopy;
-
- case 'n': // Weird write-bytes specifier.
- {
- int* d = va_arg!(int*)(va);
- *d = tlen + cast(int) (bf - buf.ptr);
- }
- break;
-
- case 'A': // Hex float.
- case 'a': // Hex float.
- h = (f[0] == 'A') ? hexu.ptr : hex.ptr;
- fv = va_arg!double(va);
- if (precision == -1)
- {
- precision = 6; // Default is 6.
- }
- // Read the double into a string.
- if (real2Parts(cast(long*) &n64, decimalPos, fv))
- {
- fl |= Modifier.negative;
- }
- s = num.ptr + 64;
-
- leadSign(fl, lead.ptr);
-
- if (decimalPos == -1023)
- {
- decimalPos = n64 ? -1022 : 0;
- }
- else
- {
- n64 |= (cast(ulong) 1) << 52;
- }
- n64 <<= (64 - 56);
- if (precision < 15)
- {
- n64 += (((cast(ulong) 8) << 56) >> (precision * 4));
- }
- // add leading chars
-
- lead[1 + lead[0]] = '0';
- lead[2 + lead[0]] = 'x';
- lead[0] += 2;
-
- *s++ = h[(n64 >> 60) & 15];
- n64 <<= 4;
- if (precision)
- {
- *s++ = period;
- }
- sn = s;
-
- // Print the bits.
- n = precision;
- if (n > 13)
- {
- n = 13;
- }
- if (precision > cast(int) n)
- {
- tz = precision - n;
- }
- precision = 0;
- while (n--)
- {
- *s++ = h[(n64 >> 60) & 15];
- n64 <<= 4;
- }
-
- // Print the exponent.
- tail[1] = h[17];
- if (decimalPos < 0)
- {
- tail[2] = '-';
- decimalPos = -decimalPos;
- }
- else
- {
- tail[2] = '+';
- }
- n = (decimalPos>= 1000) ? 6 : ((decimalPos >= 100) ? 5 : ((decimalPos >= 10) ? 4 : 3));
- tail[0] = cast(char) n;
- for (;;)
- {
- tail[n] = '0' + decimalPos % 10;
- if (n <= 3)
- {
- break;
- }
- --n;
- decimalPos /= 10;
- }
-
- decimalPos = cast(int) (s - sn);
- l = cast(int) (s - (num.ptr + 64));
- s = num.ptr + 64;
- cs = 1 + (3 << 24);
- goto scopy;
-
- case 'G': // Float.
- case 'g': // Float.
- h = (f[0] == 'G') ? hexu.ptr : hex.ptr;
- fv = va_arg!double(va);
- if (precision == -1)
- {
- precision = 6;
- }
- else if (precision == 0)
- {
- precision = 1; // Default is 6.
- }
- // Read the double into a string.
- if (real2String(sn,
- l,
- num.ptr,
- decimalPos,
- fv,
- (precision - 1) | 0x80000000))
- {
- fl |= Modifier.negative;
- }
-
- // Clamp the precision and delete extra zeros after clamp.
- n = precision;
- if (l > cast(uint) precision)
- {
- l = precision;
- }
- while ((l > 1) && (precision) && (sn[l - 1] == '0'))
- {
- --precision;
- --l;
- }
-
- // Should we use %e.
- if ((decimalPos <= -4) || (decimalPos > cast(int) n))
- {
- if (precision > cast(int) l)
- {
- precision = l - 1;
- }
- else if (precision)
- {
- // When using %e, there is one digit before the decimal.
- --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;
-
- case 'E': // Float.
- case 'e': // Float.
- h = (f[0] == 'E') ? hexu.ptr : hex.ptr;
- 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);
- if (decimalPos == special)
- {
- s = cast(char*) sn;
- cs = 0;
- precision = 0;
- goto scopy;
- }
- s = num.ptr + 64;
- // Handle leading chars.
- *s++ = sn[0];
-
- if (precision)
- {
- *s++ = period;
- }
-
- // Handle after decimal.
- if ((l - 1) > cast(uint) precision)
- {
- l = precision + 1;
- }
- for (n = 1; n < l; n++)
- {
- *s++ = sn[n];
- }
- // Trailing zeros.
- tz = precision - (l - 1);
- precision = 0;
- // Dump the exponent.
- tail[1] = h[0xe];
- decimalPos -= 1;
- if (decimalPos < 0)
- {
- tail[2] = '-';
- decimalPos = -decimalPos;
- }
- else
- {
- tail[2] = '+';
- }
-
- n = (decimalPos >= 100) ? 5 : 4;
-
- tail[0] = cast(char) n;
- for (;;)
- {
- tail[n] = '0' + decimalPos % 10;
- if (n <= 3)
- {
- break;
- }
- --n;
- decimalPos /= 10;
- }
- cs = 1 + (3 << 24); // How many tens.
- 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);
- if (decimalPos == special)
- {
- s = cast(char*) sn;
- cs = 0;
- precision = 0;
- goto scopy;
- }
- s = num.ptr + 64;
-
- // Handle the three decimal varieties.
- if (decimalPos <= 0)
- {
- // Handle 0.000*000xxxx.
- *s++ = '0';
- if (precision)
- {
- *s++ = period;
- }
- n = -decimalPos;
- if (cast(int) n > precision)
- {
- n = precision;
- }
- int i = n;
- while (i)
- {
- if (((cast(size_t) s) & 3) == 0)
- {
- break;
- }
- *s++ = '0';
- --i;
- }
- while (i >= 4)
- {
- *cast(uint*) s = 0x30303030;
- s += 4;
- i -= 4;
- }
- while (i)
- {
- *s++ = '0';
- --i;
- }
- if (cast(int) (l + n) > precision)
- {
- l = precision - n;
- }
- i = l;
- while (i)
- {
- *s++ = *sn++;
- --i;
- }
- tz = precision - (n + l);
- // How many tens did we write (for commas below).
- cs = 1 + (3 << 24);
- }
- else
- {
- cs = (fl & Modifier.tripletComma) ? ((600 - cast(uint) decimalPos) % 3) : 0;
- if (cast(uint) decimalPos>= l)
- {
- // Handle xxxx000*000.0.
- n = 0;
- for (;;)
- {
- if ((fl & Modifier.tripletComma) && (++cs == 4))
- {
- cs = 0;
- *s++ = comma;
- }
- else
- {
- *s++ = sn[n];
- ++n;
- if (n >= l)
- {
- break;
- }
- }
- }
- if (n < cast(uint) decimalPos)
- {
- n = decimalPos - n;
- if ((fl & Modifier.tripletComma) == 0)
- {
- while (n)
- {
- if (((cast(size_t) s) & 3) == 0)
- {
- break;
- }
- *s++ = '0';
- --n;
- }
- while (n >= 4)
- {
- *cast(uint*) s = 0x30303030;
- s += 4;
- n -= 4;
- }
- }
- while (n)
- {
- if ((fl & Modifier.tripletComma) && (++cs == 4))
- {
- cs = 0;
- *s++ = comma;
- }
- else
- {
- *s++ = '0';
- --n;
- }
- }
- }
- // cs is how many tens.
- cs = cast(int) (s - (num.ptr + 64)) + (3 << 24);
- if (precision)
- {
- *s++ = period;
- tz = precision;
- }
- }
- else
- {
- // Handle xxxxx.xxxx000*000.
- n = 0;
- for (;;)
- {
- if ((fl & Modifier.tripletComma) && (++cs == 4))
- {
- cs = 0;
- *s++ = comma;
- }
- else
- {
- *s++ = sn[n];
- ++n;
- if (n >= cast(uint) decimalPos)
- {
- break;
- }
- }
- }
- // cs is how many tens.
- cs = cast(int) (s - (num.ptr + 64)) + (3 << 24);
- if (precision)
- {
- *s++ = period;
- }
- if ((l - decimalPos) > cast(uint) precision)
- {
- l = precision + decimalPos;
- }
- while (n < l)
- {
- *s++ = sn[n];
- ++n;
- }
- tz = precision - (l - decimalPos);
- }
- }
- precision = 0;
-
- flt_lead:
- // Get the length that we copied.
- l = cast(uint) (s - (num.ptr + 64));
- s = num.ptr + 64;
- goto scopy;
-
- case 'B': // Upper binary.
- case 'b': // Lower binary.
- h = (f[0] == 'B') ? hexu.ptr : hex.ptr;
- lead[0] = 0;
- if (fl & Modifier.leading0x)
- {
- lead[0] = 2;
- lead[1] = '0';
- lead[2] = h[0xb];
- }
- l = (8 << 4) | (1 << 8);
- {
- goto radixnum;
- }
-
- case 'o': // octal
- h = hexu.ptr;
- lead[0] = 0;
- if (fl & Modifier.leading0x)
- {
- lead[0] = 1;
- lead[1] = '0';
- }
- l = (3 << 4) | (3 << 8);
- goto radixnum;
-
- case 'p': // pointer
- static if (size_t.sizeof == 8)
- {
- fl |= Modifier.intMax;
- }
- precision = (void*).sizeof * 2;
- // 'p' only prints the pointer with zeros.
- fl &= ~Modifier.leadingZero;
- goto case;
- case 'X': // Upper hex.
- case 'x': // Lower hex.
- h = (f[0] == 'X') ? hexu.ptr : hex.ptr;
- l = (4 << 4) | (4 << 8);
- lead[0] = 0;
- if (fl & Modifier.leading0x)
- {
- lead[0] = 2;
- lead[1] = '0';
- lead[2] = h[16];
- }
- radixnum:
- // Get the number.
- if (fl & Modifier.intMax)
- {
- n64 = va_arg!ulong(va);
- }
- else
- {
- n64 = va_arg!uint(va);
- }
-
- s = num.ptr + NUMSZ;
- 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;
- cs = (((l >> 4) & 15)) << 24;
- goto scopy;
- }
- }
- // Convert to string.
- for (;;)
- {
- *--s = h[cast(size_t) (n64 & ((1 << (l >> 8)) - 1))];
- n64 >>= (l >> 8);
- if (!((n64) || (cast(int) ((num.ptr + NUMSZ) - s) < precision)))
- {
- break;
- }
- if (fl & Modifier.tripletComma)
- {
- ++l;
- if ((l & 15) == ((l >> 4) & 15))
- {
- l &= ~15;
- *--s = comma;
- }
- }
- }
- // Get the tens and the comma position.
- cs = cast(uint) ((num.ptr + NUMSZ) - s) + ((((l >> 4) & 15)) << 24);
- // Get the length that we copied.
- l = cast(uint)((num.ptr + NUMSZ) - s);
- // Copy it.
- goto scopy;
-
- case 'u': // Unsigned.
- case 'i':
- case 'd': // Integer.
- // Get the integer and abs it.
- if (fl & Modifier.intMax)
- {
- long i64 = va_arg!long(va);
- n64 = cast(ulong) i64;
- if ((f[0] != 'u') && (i64 < 0))
- {
- n64 = cast(ulong) -i64;
- fl |= Modifier.negative;
- }
- }
- else
- {
- int i = va_arg!int(va);
- n64 = cast(uint) i;
- if ((f[0] != 'u') && (i < 0))
- {
- n64 = cast(uint) -i;
- fl |= Modifier.negative;
- }
- }
-
- // Convert to string.
- s = num.ptr + NUMSZ;
- l = 0;
-
- for (;;)
- {
- // Do in 32-bit chunks (avoid lots of 64-bit divides even
- // with constant denominators).
- char *o = s - 8;
- if (n64 >= 100000000)
- {
- n = cast(uint) (n64 % 100000000);
- n64 /= 100000000;
- }
- else
- {
- n = cast(uint) n64;
- n64 = 0;
- }
- if ((fl & Modifier.tripletComma) == 0)
- {
- while (n)
- {
- s -= 2;
- *cast(ushort*) s = *cast(ushort*) &digitpair[(n % 100) * 2];
- n /= 100;
- }
- }
- while (n)
- {
- if ((fl & Modifier.tripletComma) && (l++ == 3))
- {
- l = 0;
- *--s = comma;
- --o;
- }
- else
- {
- *--s = cast(char) (n % 10) + '0';
- n /= 10;
- }
- }
- if (n64 == 0)
- {
- if ((s[0] == '0') && (s != (num.ptr + NUMSZ)))
- {
- ++s;
- }
- break;
- }
- while (s != o)
- {
- if ((fl & Modifier.tripletComma) && (l++ == 3))
- {
- l = 0;
- *--s = comma;
- --o;
- }
- else
- {
- *--s = '0';
- }
- }
- }
-
- tail[0] = 0;
- leadSign(fl, lead.ptr);
-
- // Get the length that we copied.
- l = cast(uint) ((num.ptr + NUMSZ) - s);
- if (l == 0)
- {
- *--s = '0';
- l = 1;
- }
- cs = l + (3 << 24);
- if (precision < 0)
- {
- precision = 0;
- }
-
- scopy:
- // Get fw=leading/trailing space, precision=leading zeros.
- if (precision < cast(int) l)
- {
- precision = l;
- }
- n = precision + lead[0] + tail[0] + tz;
- if (fw < cast(int) n)
- {
- fw = n;
- }
- fw -= n;
- precision -= l;
-
- // Handle right justify and leading zeros.
- if ((fl & Modifier.leftJust) == 0)
- {
- // If leading zeros, everything is in precision.
- if (fl & Modifier.leadingZero)
- {
- precision = (fw > precision) ? fw : precision;
- fw = 0;
- }
- else
- {
- fl &= ~Modifier.tripletComma; // if no leading zeros, then no commas
- }
- }
-
- // Copy the spaces and/or zeros.
- if (fw + precision)
- {
- int i;
-
- // copy leading spaces (or when doing %8.4d stuff)
- if ((fl & Modifier.leftJust) == 0)
- {
- 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])
- {
- i = lead[0];
- lead[0] -= cast(char) i;
- while (i)
- {
- *bf++ = *sn++;
- --i;
- }
- }
-
- // Copy leading zeros.
- uint c = cs >> 24;
- cs &= 0xffffff;
- if (fl & Modifier.tripletComma)
- {
- cs = cast(uint) (c - ((precision + cs) % (c + 1)));
- }
- else
- {
- cs = 0;
- }
- while (precision > 0)
- {
- i = precision;
- precision -= i;
- if ((fl & Modifier.tripletComma) == 0)
- {
- 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)
- {
- if ((fl & Modifier.tripletComma) && (cs++ == c))
- {
- cs = 0;
- *bf++ = comma;
- }
- else
- {
- *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;
- }
- }
-
- // handle the left justify
- if (fl & Modifier.leftJust && fw > 0)
- {
- while (fw)
- {
- int 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++ = ' ';
- }
- }
- }
- 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;
- cs = 0;
- goto scopy;
- }
- f.popFront();
- }
-
- *bf = 0;
- return buf[0 .. tlen + cast(int) (bf - buf.ptr)];
-}
-
-package(tanya) char[] format(string fmt)(return char[] buf, ...)
-nothrow
-{
- va_list va;
- va_start(va, buf);
- auto result = vsprintf!fmt(buf, va);
- va_end(va);
- return result;
-}
-
-private nothrow unittest
-{
- char[318] buffer;
-
- // Format without arguments.
- assert(format!""(buffer) == "");
- assert(format!"asdfqweryxcvz"(buffer) == "asdfqweryxcvz");
-
- // Modifiers.
- assert(format!"%-5g"(buffer, 8.5) == "8.5 ");
- assert(format!"%05g"(buffer, 8.6) == "008.6");
- assert(format!"% 5g"(buffer, 8.6) == " 8.6");
- assert(format!"%+d"(buffer, 8) == "+8");
- assert(format!"%#x"(buffer, 20) == "0x14");
- assert(format!"%#o"(buffer, 8) == "010");
- assert(format!"%#b"(buffer, 3) == "0b11");
- assert(format!"%'d"(buffer, 1000) == "1,000");
- assert(format!"%*d"(buffer, 5, 1) == " 1");
- assert(format!"%.1f"(buffer, 10.25) == "10.3");
- assert(format!"%.*f"(buffer, 1, 10.25) == "10.3");
- assert(format!"%-9i"(buffer, 1) == "1 ");
- assert(format!"%'07.3g"(buffer, 0.01) == ",000.01");
-
- // Integer size.
- assert(format!"%hd"(buffer, 10) == "10");
- assert(format!"%ld"(buffer, 10) == "10");
- assert(format!"%lld"(buffer, 10L) == "10");
- assert(format!"%jd"(buffer, 10L) == "10");
- assert(format!"%zd"(buffer, 10) == "10");
- assert(format!"%td"(buffer, 10) == "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");
-
- // Integer conversions.
- assert(format!"%d"(buffer, 8) == "8");
- assert(format!"%i"(buffer, 8) == "8");
- assert(format!"%i"(buffer, -8) == "-8");
- assert(format!"%lli"(buffer, -8L) == "-8");
- assert(format!"%u"(buffer, 8) == "8");
- assert(format!"%o"(buffer, 8) == "10");
- assert(format!"%b"(buffer, 3) == "11");
- assert(format!"%B"(buffer, 3) == "11");
- assert(format!"%.0x"(buffer, 0) == "");
- assert(format!"%'x"(buffer, 11111111) == "a9,8ac7");
- assert(format!"%d"(buffer, 100000001) == "100000001");
- assert(format!"%.12d"(buffer, 99999999L) == "000099999999");
- assert(format!"%'d"(buffer, 100000001) == "100,000,001");
-
- // Count of bytes written so far.
- {
- int written;
- format!"asd%nf"(buffer, &written);
- assert(written == 3);
- }
-
- // 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!"%f"(buffer, -0.3) == "-0.300000");
- 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!"%e"(buffer, 0.3) == "3.000000e-01");
- assert(format!"%E"(buffer, 0.3) == "3.000000E-01");
- assert(format!"%e"(buffer, -0.3) == "-3.000000e-01");
- assert(format!"%a"(buffer, 3.5) == "0x1.c00000p+1");
- assert(format!"%A"(buffer, 3.5) == "0x1.C00000P+1");
- assert(format!"%a"(buffer, -3.5) == "-0x1.c00000p+1");
- assert(format!"%.14a"(buffer, -3.5) == "-0x1.c0000000000000p+1");
- assert(format!"%a"(buffer, 0.0) == "0x0.000000p+0");
- assert(format!"%a"(buffer, 1e-300) == "0x1.56e1fcp-997");
- 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) == "111,234");
- 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) == "1,000.000000");
- assert(format!"%'g"(buffer, 38234.1234) == "38,234.1");
-
- // Pointer conversions.
- {
- auto p = format!"%p"(buffer, cast(void*) 1);
- assert(p[$ - 1] == '1');
- foreach (e; p[0 .. $ - 1])
- {
- assert(e == '0');
- }
- }
-
- // Unknown specifier.
- assert(format!"%k"(buffer) == "k");
- assert(format!"%%k"(buffer) == "%k");
-}
+public import tanya.format.conv; \ No newline at end of file