mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 14:40:30 +03:00
Reduce template bloat in IntegralTypeOf-overload of formatValueImpl
This commit is contained in:
parent
e2279cac12
commit
4b5785c4e3
1 changed files with 66 additions and 36 deletions
|
@ -160,8 +160,6 @@ if (is(immutable T == immutable typeof(null)) && !is(T == enum) && !hasToString!
|
|||
void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj, scope const ref FormatSpec!Char f)
|
||||
if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
|
||||
{
|
||||
import std.range.primitives : put;
|
||||
|
||||
alias U = IntegralTypeOf!T;
|
||||
U val = obj; // Extracting alias this may be impure/system/may-throw
|
||||
|
||||
|
@ -171,56 +169,46 @@ if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
|
|||
auto raw = (ref val) @trusted {
|
||||
return (cast(const char*) &val)[0 .. val.sizeof];
|
||||
}(val);
|
||||
|
||||
import std.range.primitives : put;
|
||||
if (needToSwapEndianess(f))
|
||||
{
|
||||
foreach_reverse (c; raw)
|
||||
put(w, c);
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (c; raw)
|
||||
put(w, c);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
immutable uint base =
|
||||
f.spec == 'x' || f.spec == 'X' || f.spec == 'a' || f.spec == 'A' ? 16 :
|
||||
f.spec == 'o' ? 8 :
|
||||
f.spec == 'b' ? 2 :
|
||||
f.spec == 's' || f.spec == 'd' || f.spec == 'u'
|
||||
|| f.spec == 'e' || f.spec == 'E' || f.spec == 'f' || f.spec == 'F'
|
||||
|| f.spec == 'g' || f.spec == 'G' ? 10 :
|
||||
0;
|
||||
|
||||
import std.format : enforceFmt;
|
||||
enforceFmt(base > 0,
|
||||
"incompatible format character for integral argument: %" ~ f.spec);
|
||||
|
||||
import std.math.algebraic : abs;
|
||||
|
||||
bool negative = false;
|
||||
ulong arg = val;
|
||||
static if (isSigned!U)
|
||||
{
|
||||
if (f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u')
|
||||
{
|
||||
if (val < 0)
|
||||
{
|
||||
negative = true;
|
||||
arg = cast(ulong) abs(val);
|
||||
}
|
||||
}
|
||||
const negative = val < 0 && f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u';
|
||||
ulong arg = negative ? -cast(ulong) val : val;
|
||||
}
|
||||
else
|
||||
{
|
||||
const negative = false;
|
||||
ulong arg = val;
|
||||
}
|
||||
|
||||
arg &= Unsigned!U.max;
|
||||
|
||||
formatValueImplUlong!(Writer, Char)(w, arg, negative, f);
|
||||
}
|
||||
|
||||
// Helper function for `formatValueImpl` that avoids template bloat
|
||||
private void formatValueImplUlong(Writer, Char)(auto ref Writer w, ulong arg, in bool negative,
|
||||
scope const ref FormatSpec!Char f)
|
||||
{
|
||||
immutable uint base = baseOfSpec(f.spec);
|
||||
|
||||
const bool zero = arg == 0;
|
||||
char[64] digits = void;
|
||||
size_t pos = digits.length - 1;
|
||||
do
|
||||
{
|
||||
digits[pos--] = '0' + arg % base;
|
||||
/* `cast(char)` is needed because value range propagation (VRP) cannot
|
||||
* analyze `base` because it’s computed in a separate function
|
||||
* (`baseOfSpec`). */
|
||||
digits[pos--] = cast(char) ('0' + arg % base);
|
||||
if (base > 10 && digits[pos + 1] > '9')
|
||||
digits[pos + 1] += ((f.spec == 'x' || f.spec == 'a') ? 'a' : 'A') - '0' - 10;
|
||||
arg /= base;
|
||||
|
@ -245,12 +233,12 @@ if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
|
|||
if (f.spec == 'x' || f.spec == 'X' || f.spec == 'b' || f.spec == 'o' || f.spec == 'u'
|
||||
|| f.spec == 'd' || f.spec == 's')
|
||||
{
|
||||
if (f.flHash && (base == 16) && obj != 0)
|
||||
if (f.flHash && (base == 16) && !zero)
|
||||
{
|
||||
prefix[--left] = f.spec;
|
||||
prefix[--left] = '0';
|
||||
}
|
||||
if (f.flHash && (base == 8) && obj != 0
|
||||
if (f.flHash && (base == 8) && !zero
|
||||
&& (digits.length - (pos + 1) >= f.precision || f.precision == f.UNSPECIFIED))
|
||||
prefix[--left] = '0';
|
||||
|
||||
|
@ -358,6 +346,48 @@ if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
|
|||
(f.spec == 'g' || f.spec == 'G') ? PrecisionType.allDigits : PrecisionType.fractionalDigits);
|
||||
}
|
||||
|
||||
private uint baseOfSpec(in char spec) @safe pure
|
||||
{
|
||||
typeof(return) base =
|
||||
spec == 'x' || spec == 'X' || spec == 'a' || spec == 'A' ? 16 :
|
||||
spec == 'o' ? 8 :
|
||||
spec == 'b' ? 2 :
|
||||
spec == 's' || spec == 'd' || spec == 'u'
|
||||
|| spec == 'e' || spec == 'E' || spec == 'f' || spec == 'F'
|
||||
|| spec == 'g' || spec == 'G' ? 10 :
|
||||
0;
|
||||
|
||||
import std.format : enforceFmt;
|
||||
enforceFmt(base > 0,
|
||||
"incompatible format character for integral argument: %" ~ spec);
|
||||
|
||||
return base;
|
||||
}
|
||||
|
||||
@safe pure unittest
|
||||
{
|
||||
assertCTFEable!(
|
||||
{
|
||||
formatTest(byte.min, "-128");
|
||||
formatTest(byte.max, "127");
|
||||
formatTest(short.min, "-32768");
|
||||
formatTest(short.max, "32767");
|
||||
formatTest(int.min, "-2147483648");
|
||||
formatTest(int.max, "2147483647");
|
||||
formatTest(long.min, "-9223372036854775808");
|
||||
formatTest(long.max, "9223372036854775807");
|
||||
|
||||
formatTest(ubyte.min, "0");
|
||||
formatTest(ubyte.max, "255");
|
||||
formatTest(ushort.min, "0");
|
||||
formatTest(ushort.max, "65535");
|
||||
formatTest(uint.min, "0");
|
||||
formatTest(uint.max, "4294967295");
|
||||
formatTest(ulong.min, "0");
|
||||
formatTest(ulong.max, "18446744073709551615");
|
||||
});
|
||||
}
|
||||
|
||||
// https://issues.dlang.org/show_bug.cgi?id=18838
|
||||
@safe pure unittest
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue