www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - bitmanip : read does not accept my array slice

reply Dennis <dkorpel gmail.com> writes:
I was trying to translate this kind of C code to D:

void calc(unsigned char *buf) {
   (...)
   res = read_u32_be(&buf[i]);
}

So I tried this:

import std.bitmanip : read, Endian;
void calc(ubyte[] buf) {
   (...)
   res = read!(uint, Endian.bigEndian)(buf[i..$]);
}

But then I get this error:
template std.bitmanip.read cannot deduce function from argument 
types !(uint, cast(Endian)0)(ubyte[])

The weird thing is that the following does compile, despite 
having the same types:

ubyte[] tmp = buf[i..$];
res = read!(uint, Endian.bigEndian)(tmp);

Why does this happen?
Dec 26 2017
parent reply WebFreak001 <d.forum webfreak.org> writes:
On Tuesday, 26 December 2017 at 21:45:29 UTC, Dennis wrote:
 I was trying to translate this kind of C code to D:

 void calc(unsigned char *buf) {
   (...)
   res = read_u32_be(&buf[i]);
 }

 So I tried this:

 import std.bitmanip : read, Endian;
 void calc(ubyte[] buf) {
   (...)
   res = read!(uint, Endian.bigEndian)(buf[i..$]);
 }

 But then I get this error:
 template std.bitmanip.read cannot deduce function from argument 
 types !(uint, cast(Endian)0)(ubyte[])

 The weird thing is that the following does compile, despite 
 having the same types:

 ubyte[] tmp = buf[i..$];
 res = read!(uint, Endian.bigEndian)(tmp);

 Why does this happen?
read takes a ref argument so it can change the value of it (like it tries to assign buf[i..$] = something then) which doesn't work for slices via ref arguments. Instead what you would want to use is peek: void calc(ubyte[] buf) { size_t i = 0; (...) res = buf.peek!uint(&i); } BigEndian is default btw, you don't need to specify that but you can if you want. What peek does now is first dereferencing your pointer there to get the current value of i to look where to read and then increment the value by T.sizeof (uint.sizeof here, which is 4). With this you can read multiple successing values without doing anything with i. You can also pass a normal int value instead of a pointer which will just peek without advancing the value
Dec 26 2017
parent Dennis <dkorpel gmail.com> writes:
Ah, so it's about lvalues an rvalues, not the type of the range. 
Makes sense now.

On Tuesday, 26 December 2017 at 22:33:54 UTC, WebFreak001 wrote:
 BigEndian is default btw, you don't need to specify that but 
 you can if you want.
Dealing with Endianness bugs has been such a pain, I like to be explicit about it ;) On Tuesday, 26 December 2017 at 22:33:54 UTC, WebFreak001 wrote:
 What peek does now is first dereferencing your pointer there to 
 get the current value of i to look where to read and then 
 increment the value by T.sizeof (uint.sizeof here, which is 4). 
 With this you can read multiple successing values without doing 
 anything with i. You can also pass a normal int value instead 
 of a pointer which will just peek without advancing the value
That function is more applicable here, thanks!
Dec 26 2017