mirror of
https://github.com/dlang/phobos.git
synced 2025-04-29 22:50:38 +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)
|
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))
|
if (is(IntegralTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
|
||||||
{
|
{
|
||||||
import std.range.primitives : put;
|
|
||||||
|
|
||||||
alias U = IntegralTypeOf!T;
|
alias U = IntegralTypeOf!T;
|
||||||
U val = obj; // Extracting alias this may be impure/system/may-throw
|
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 {
|
auto raw = (ref val) @trusted {
|
||||||
return (cast(const char*) &val)[0 .. val.sizeof];
|
return (cast(const char*) &val)[0 .. val.sizeof];
|
||||||
}(val);
|
}(val);
|
||||||
|
import std.range.primitives : put;
|
||||||
if (needToSwapEndianess(f))
|
if (needToSwapEndianess(f))
|
||||||
{
|
|
||||||
foreach_reverse (c; raw)
|
foreach_reverse (c; raw)
|
||||||
put(w, c);
|
put(w, c);
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
|
||||||
foreach (c; raw)
|
foreach (c; raw)
|
||||||
put(w, c);
|
put(w, c);
|
||||||
}
|
|
||||||
return;
|
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)
|
static if (isSigned!U)
|
||||||
{
|
{
|
||||||
if (f.spec != 'x' && f.spec != 'X' && f.spec != 'b' && f.spec != 'o' && f.spec != 'u')
|
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;
|
||||||
if (val < 0)
|
}
|
||||||
{
|
else
|
||||||
negative = true;
|
{
|
||||||
arg = cast(ulong) abs(val);
|
const negative = false;
|
||||||
}
|
ulong arg = val;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
arg &= Unsigned!U.max;
|
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;
|
char[64] digits = void;
|
||||||
size_t pos = digits.length - 1;
|
size_t pos = digits.length - 1;
|
||||||
do
|
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')
|
if (base > 10 && digits[pos + 1] > '9')
|
||||||
digits[pos + 1] += ((f.spec == 'x' || f.spec == 'a') ? 'a' : 'A') - '0' - 10;
|
digits[pos + 1] += ((f.spec == 'x' || f.spec == 'a') ? 'a' : 'A') - '0' - 10;
|
||||||
arg /= base;
|
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'
|
if (f.spec == 'x' || f.spec == 'X' || f.spec == 'b' || f.spec == 'o' || f.spec == 'u'
|
||||||
|| f.spec == 'd' || f.spec == 's')
|
|| 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] = f.spec;
|
||||||
prefix[--left] = '0';
|
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))
|
&& (digits.length - (pos + 1) >= f.precision || f.precision == f.UNSPECIFIED))
|
||||||
prefix[--left] = '0';
|
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);
|
(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
|
// https://issues.dlang.org/show_bug.cgi?id=18838
|
||||||
@safe pure unittest
|
@safe pure unittest
|
||||||
{
|
{
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue