Make hex strings implicitly convert to integer arrays

This commit is contained in:
Dennis Korpel 2024-02-28 14:27:13 +01:00 committed by Iain Buclaw
parent 3e9bc4ee17
commit 4e3cc5c6c6
6 changed files with 34 additions and 38 deletions

View file

@ -1,27 +1,23 @@
Hex strings can now be cast to integer arrays Hex strings now convert to integer arrays
Hex strings are the most efficient way to embed binary data into source files. Hex strings are the most efficient way to embed binary data into source files.
However, they couldn't easily be used to initialize a `short[]`, `int[]` or `long[]` because re-interpret casting arrays is not allowed during CTFE. However, they couldn't easily be used to initialize a `short[]`, `int[]` or `long[]` because re-interpret casting arrays is not allowed during CTFE.
Now, hex strings can be cast to integer arrays with element types larger than `byte`. Now, hex strings implicitly convert to all integer arrays.
A big endian byte order is assumed, consistent with how integer literals are written. A big endian byte order is assumed, consistent with how integer literals are written.
--- ---
immutable uint[] data = cast(immutable uint[]) x"AABBCCDD"; immutable uint[] data = x"AABBCCDD";
static assert(data[0] == 0xAABBCCDD); static assert(data[0] == 0xAABBCCDD);
--- ---
Character postfixes can now also be used for integers of size 2 or 4, while an `L` postfix can be used for size 8: Character postfixes can now also be used to explicitly set an element size of 2 or 4.
--- ---
immutable ushort[] f = x"80 3F"w; immutable ushort[] f = x"80 3F"w;
static assert(f[0] == 0x803F); static assert(f[0] == 0x803F);
immutable int[] g = x"80 35 FF FD"d; immutable ubyte[] g = x"80 35"w; // error: size mismatch
static assert(g[0] == 0x803FFFFD);
auto h = x"0011 2233 4455 6677"L;
static assert(h[0] == 0x0011_2233_4455_6677);
static assert(is(typeof(h) == immutable ulong[]));
--- ---
Formerly, they would pad each byte with 1 or 3 zeros, which did not serve a purpose (See [Issue 24363](https://issues.dlang.org/show_bug.cgi?id=24363)). Formerly, they would pad each byte with 1 or 3 zeros, which did not serve a purpose (See [Issue 24363](https://issues.dlang.org/show_bug.cgi?id=24363)).

View file

@ -703,6 +703,11 @@ MATCH implicitConvTo(Expression e, Type t)
return MATCH.nomatch; return MATCH.nomatch;
m = MATCH.constant; m = MATCH.constant;
} }
if (e.hexString && tn.isintegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0)))
{
m = MATCH.convert;
return m;
}
if (!e.committed) if (!e.committed)
{ {
switch (tn.ty) switch (tn.ty)
@ -719,9 +724,6 @@ MATCH implicitConvTo(Expression e, Type t)
if (e.postfix != 'd') if (e.postfix != 'd')
m = MATCH.convert; m = MATCH.convert;
return m; return m;
case Tint8:
case Tuns8:
break;
case Tenum: case Tenum:
if (tn.isTypeEnum().sym.isSpecial()) if (tn.isTypeEnum().sym.isSpecial())
{ {
@ -735,14 +737,6 @@ MATCH implicitConvTo(Expression e, Type t)
break; break;
} }
} }
if (e.hexString)
{
if (tn.isintegral && tn.size == e.sz)
{
m = MATCH.convert;
return m;
}
}
break; break;
default: default:
@ -1884,6 +1878,19 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
Type tb = t.toBasetype(); Type tb = t.toBasetype();
Type typeb = e.type.toBasetype(); Type typeb = e.type.toBasetype();
if (e.hexString && !e.committed)
{
const szx = cast(ubyte) tb.nextOf().size();
if (szx != se.sz && (e.len % szx) == 0)
{
import dmd.utils: arrayCastBigEndian;
const data = cast(const ubyte[]) e.peekString();
se.setData(arrayCastBigEndian(data, szx).ptr, data.length / szx, szx);
se.type = t;
return se;
}
}
//printf("\ttype = %s\n", e.type.toChars()); //printf("\ttype = %s\n", e.type.toChars());
if (tb.ty == Tdelegate && typeb.ty != Tdelegate) if (tb.ty == Tdelegate && typeb.ty != Tdelegate)
{ {

View file

@ -4245,22 +4245,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
if (e.hexString) if (e.hexString)
{ {
const data = cast(const ubyte[]) e.peekString(); const data = cast(const ubyte[]) e.peekString(); // peek before size is set to something larger than 1
switch (e.postfix) switch (e.postfix)
{ {
case 'L':
e.sz = 8;
e.type = Type.tuns64.immutableOf().arrayOf();
break;
case 'd': case 'd':
e.committed = true;
e.sz = 4; e.sz = 4;
e.type = Type.tdstring; e.type = Type.tdstring;
break; break;
case 'w': case 'w':
e.committed = true;
e.sz = 2; e.sz = 2;
e.type = Type.twstring; e.type = Type.twstring;
break; break;
case 'c': case 'c':
e.committed = true;
goto default;
default: default:
e.type = Type.tstring; e.type = Type.tstring;
e.sz = 1; e.sz = 1;
@ -4271,7 +4271,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
e.type.toChars(), e.sz, cast(int) e.len); e.type.toChars(), e.sz, cast(int) e.len);
e.setData(arrayCastBigEndian(data, e.sz).ptr, e.len / e.sz, e.sz); e.setData(arrayCastBigEndian(data, e.sz).ptr, e.len / e.sz, e.sz);
e.committed = true;
} }
else switch (e.postfix) else switch (e.postfix)
{ {

View file

@ -1569,12 +1569,6 @@ class Lexer
} }
t.setString(stringbuffer); t.setString(stringbuffer);
stringPostfix(t); stringPostfix(t);
if (*p == 'L')
{
t.postfix = 'L';
p++;
}
return TOK.hexadecimalString; return TOK.hexadecimalString;
default: default:
if (c >= '0' && c <= '9') if (c >= '0' && c <= '9')

View file

@ -13,10 +13,10 @@ fail_compilation/hexstring.d(39): Error: array cast from `string` to `immutable(
fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string fail_compilation/hexstring.d(39): perhaps remove postfix `c` from hex string
fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5 fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5
fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"44332211"d` of type `dstring` to `immutable(float[])` fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"44332211"d` of type `dstring` to `immutable(float[])`
fail_compilation/hexstring.d(42): Error: cannot implicitly convert expression `x"2211"w` of type `wstring` to `immutable(ubyte[])`
fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]` fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]`
--- ---
*/ */
immutable ubyte[] s0 = x"123F"; immutable ubyte[] s0 = x"123F";
static assert(s0[0] == 0x12); static assert(s0[0] == 0x12);
static assert(s0[1] == 0x3F); static assert(s0[1] == 0x3F);
@ -39,3 +39,4 @@ immutable ushort[] f10 = cast(immutable ushort[]) (x"1122" ~ "");
immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c; immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c;
immutable uint[] f12 = x"1122334455"d; immutable uint[] f12 = x"1122334455"d;
immutable float[] f13 = x"11223344"d; immutable float[] f13 = x"11223344"d;
immutable ubyte[] f14 = x"1122"w;

View file

@ -247,14 +247,13 @@ void testHexstring()
static assert(x[0] == 0xFFAADDEE); static assert(x[0] == 0xFFAADDEE);
assert(x[0] == 0xFFAADDEE); assert(x[0] == 0xFFAADDEE);
static assert(is(typeof(x""L) == immutable(ulong)[])); static immutable ulong[] y = x"1122334455667788AABBCCDDEEFF0099";
static immutable ulong[] y = x"1122334455667788AABBCCDDEEFF0099"L;
static assert(y[0] == 0x1122334455667788); static assert(y[0] == 0x1122334455667788);
static assert(y[1] == 0xAABBCCDDEEFF0099); static assert(y[1] == 0xAABBCCDDEEFF0099);
assert(y[0] == 0x1122334455667788); assert(y[0] == 0x1122334455667788);
assert(y[1] == 0xAABBCCDDEEFF0099); assert(y[1] == 0xAABBCCDDEEFF0099);
immutable long[] c = x"1122334455667788AABBCCDDEEFF0099"L; immutable long[] c = x"1122334455667788AABBCCDDEEFF0099";
assert(c[0] == 0x1122334455667788); assert(c[0] == 0x1122334455667788);
assert(c[1] == 0xAABBCCDDEEFF0099); assert(c[1] == 0xAABBCCDDEEFF0099);
@ -264,7 +263,7 @@ void testHexstring()
// Test printing StringExp with size 8 // Test printing StringExp with size 8
enum toStr(immutable ulong[] v) = v.stringof; enum toStr(immutable ulong[] v) = v.stringof;
static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"L`); static assert(toStr!y == `x"88776655443322119900FFEEDDCCBBAA"`);
// Hex string postfixes // Hex string postfixes
// https://issues.dlang.org/show_bug.cgi?id=24363 // https://issues.dlang.org/show_bug.cgi?id=24363