Simple way to handle rvalues and templates.

Ali Çehreli acehreli at yahoo.com
Sun Feb 27 06:11:28 UTC 2022


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



More information about the Digitalmars-d-learn mailing list