www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Simple way to handle rvalues and templates.

reply Chris Piker <chris hoopjump.com> writes:
Hi D

I have bit of code that was tripping me up.  I need to parse 
small fields out of a big binary read, and it looks like some 
operations just can't be composed when it comes to
using templates.  So this works:
```d
import std.bitmanip, std.system;
ubyte[8192] data;

ubyte[] temp = data[4..6];
ushort us = temp.read!(ushort, Endian.bigEndian);
// intentionally provided the default byte order for readability
```
But this doesn't work:
```d
import std.bitmanip, std.system;
ubyte[8192] data;

ushort us = data[4..6].read!(ushort, Endian.bigEndian);
```
The reasons for this are probably old hat for seasoned D 
programmers by this is really confusing for newbies.

Is there a better way to handle this instead of making a bunch of 
temporary variables that I don't care about?  Matlab has this 
behavior too, statements that should be composable aren't, and it 
drives me crazy since Java and Python don't seem to suffer from 
this problem near a much.
Feb 26 2022
parent reply =?UTF-8?Q?Ali_=c3=87ehreli?= <acehreli yahoo.com> writes:
On 2/26/22 19:38, Chris Piker wrote:

 But this doesn't work:
 ```d
 import std.bitmanip, std.system;
 ubyte[8192] data;

 ushort us = data[4..6].read!(ushort, Endian.bigEndian);
 ```
 The reasons for this are probably old hat for seasoned D programmers by
 this is really confusing for newbies.
Agreed. read() is designed to advance the buffer that it is given. It is thought to be convenient for the next read() operation because the semantics would be "read a ushort and then read an int", etc. And the buffer would be consumed by read(). To play the way read() wants us to play, the first thing that comes to mind is to read original data into a storage and define a range (data below) for read() to consume. However, it requires skipping over bytes by e.g. dropExactly(), which is presumably a very fast operation for slices: void main() { import std.bitmanip, std.system; ubyte[8192] storage; auto data = storage[]; import std.range; data.dropExactly(4); ushort us = data.read!(ushort, Endian.bigEndian); // Here, data is ready for the next read. } Another option is to write a wrapper which takes your slice by copy so that read() is happy as it consumes a parameter instead of your rvalue: import std.system; // Adapting read()'s interface with one difference: 'ref' is removed: auto readFrom(T, Endian endianness = Endian.bigEndian, R)(R range) { import std.bitmanip; return range.read!(ushort, endianness); } void main() { import std.bitmanip, std.system; ubyte[8192] data; ushort us = data[4..6].readFrom!(ushort, Endian.bigEndian); } I don't like the name readFrom() yet but that works. :) Ali
Feb 26 2022
parent Salih Dincer <salihdb hotmail.com> writes:
On Sunday, 27 February 2022 at 06:11:28 UTC, Ali Çehreli wrote:
 I don't like the name readFrom() yet but that works. :)
It seems very delicious, can stay as read(): ```d auto read(T, Endian E = Endian.bigEndian, R) (R range) { import bop = std.bitmanip; return bop.read!(T, E)(range); } void main() { import std.system; ubyte[8] d = [ 0xFF, 0xFF, 0xFF, 0xFF, 0xAA, 0xAA, 0xFF, 0xFF ]; ushort us = d[4..6].read!ushort; assert(us == 0xAAAA); } ``` SDB79
Feb 27 2022