On Thursday, 3 February 2022 at 05:50:24 UTC, Walter Bright wrote:
> On 2/2/2022 6:25 PM, Siarhei Siamashka wrote:
> On Thursday, 3 February 2022 at 01:05:15 UTC, Walter Bright wrote:
> I find it works well. For example,
int i;
byte b = i & 0xFF;
passes without complaint with VRP.
No, it's doesn't pass: Error: cannot implicitly convert expression i & 255 of type int to byte
.
My mistake. b should have been declared as ubyte.
Regarding your original example with the byte
type. Maybe the use of the following code can be encouraged as a good idiomatic overflow-safe way to do it in D language?
int i;
byte b = i.to!byte;
i = -129;
b = i.to!byte; // std.conv.ConvOverflowException
This is 2 characters shorter and IMHO nicer looking than byte b = cast(byte)i;
. An overflow check is done at runtime to catch bugs, but good optimizing compilers are actually smart enough to eliminate it when the range of possible values of i
is known at compile time. For example:
void foobar(byte[] a)
{
foreach (i ; 0 .. a.length)
a[i] = (i % 37).to!byte;
}
Gets compiled into:
$ gdc-12.0.1 -O3 -fno-weak-templates -c test.d && objdump -d test.o
0000000000000000 <_D4test6foobarFAgZv>:
0: 48 85 ff test %rdi,%rdi
3: 74 37 je 3c <_D4test6foobarFAgZv+0x3c>
5: 49 b8 8b 7c d6 0d a6 movabs $0xdd67c8a60dd67c8b,%r8
c: c8 67 dd
f: 31 c9 xor %ecx,%ecx
11: 0f 1f 80 00 00 00 00 nopl 0x0(%rax)
18: 48 89 c8 mov %rcx,%rax
1b: 49 f7 e0 mul %r8
1e: 48 c1 ea 05 shr $0x5,%rdx
22: 48 8d 04 d2 lea (%rdx,%rdx,8),%rax
26: 48 8d 14 82 lea (%rdx,%rax,4),%rdx
2a: 48 89 c8 mov %rcx,%rax
2d: 48 29 d0 sub %rdx,%rax
30: 88 04 0e mov %al,(%rsi,%rcx,1)
33: 48 83 c1 01 add $0x1,%rcx
37: 48 39 cf cmp %rcx,%rdi
3a: 75 dc jne 18 <_D4test6foobarFAgZv+0x18>
3c: c3 retq
Slow division is replaced by multiplication and shifts, conditional branches are only done to compare i
with the array length. The .to!byte
part doesn't have any overhead at all and bytes are just directly written to the destination array via mov %al,(%rsi,%rcx,1)
instruction.