Thread overview
bitmanip bigEndianToNative using a buffer slice?
Oct 22, 2014
Lucas Burson
Oct 22, 2014
ketmar
Oct 22, 2014
Lucas Burson
Oct 22, 2014
ketmar
Oct 22, 2014
Jonathan M Davis
October 22, 2014
I'm trying to create a primitive type given a specific buffer slice. I can place the uint into a sliced buffer but I'm getting compiler errors when using a slice to create the uint. Still new to Dlang and unfamiliar with the template system.

How do I get this working?

import std.bitmanip;
int main()
{
   size_t offset = 3;
   ubyte[10] buffer;
   buffer[offset..offset+4] = nativeToBigEndian!uint(cast(uint) 104387);

   // compiler error
   uint fromBuf = bigEndianToNative!uint(buffer[offset..offset+4]);
   return 0;
}

The compiler error:
./test.d(11): Error: template std.bitmanip.bigEndianToNative does not match any function template declaration. Candidates are:
/usr/include/dmd/phobos/std/bitmanip.d(1689):        std.bitmanip.bigEndianToNative(T, ulong n)(ubyte[n] val) if (canSwapEndianness!(T) && n == T.sizeof)
./test.d(11): Error: template std.bitmanip.bigEndianToNative(T, ulong n)(ubyte[n] val) if (canSwapEndianness!(T) && n == T.sizeof) cannot deduce template function from argument types !(uint)(ubyte[])
./test.d(11): Error: template instance bigEndianToNative!(uint) errors instantiating template
October 22, 2014
On Wed, 22 Oct 2014 00:45:17 +0000
Lucas Burson via Digitalmars-d-learn
<digitalmars-d-learn@puremagic.com> wrote:

> I'm trying to create a primitive type given a specific buffer slice. I can place the uint into a sliced buffer but I'm getting compiler errors when using a slice to create the uint. Still new to Dlang and unfamiliar with the template system.
> 
> How do I get this working?
the short answer:

 uint fromBuf =
 bigEndianToNative!uint(cast(ubyte[4])buffer[offset..offset+4]);

the long answer: you are passing dynamic array, and function is expecting static array. slices are always dynamic by nature, so they must be casted to static arrays before passing to bigEndianToNative.

'ubyte[4]' is not a "recomendation", it means "only static arrays will do".

dynamic arrays are pointer to hidden "array structure" generated by
compiler, which looks like this: `struct { size_t length; void*
ptr; }`. but static arrays are just direct pointers to data, there is
no need to keep separate length, as it is known in compile time.

by casting dynamic array/slice to static array you are telling the compiler "i know the length of the data right now, so you can use direct pointer".

sorry if my explanations appears complex and hard to understand -- that's 'cause i'm not very good in teaching. but at least i tried and gave the short answer too. ;-)


October 22, 2014
On Wednesday, 22 October 2014 at 01:08:52 UTC, ketmar via Digitalmars-d-learn wrote:
> the short answer:
>
>  uint fromBuf =
>  bigEndianToNative!uint(cast(ubyte[4])buffer[offset..offset+4]);
>

ketmar, we meet again! Your explanation is great and that solved my problem. Thank you. Maybe I'll try out templates next...
October 22, 2014
On Wed, 22 Oct 2014 01:30:48 +0000
Lucas Burson via Digitalmars-d-learn
<digitalmars-d-learn@puremagic.com> wrote:

> ketmar, we meet again! Your explanation is great and that solved my problem. Thank you. Maybe I'll try out templates next...
yep, i remember. i was glad to help you. ;-)


October 22, 2014
On Wednesday, October 22, 2014 00:45:17 Lucas Burson via Digitalmars-d-learn
wrote:
> I'm trying to create a primitive type given a specific buffer
> slice. I can place the uint into a sliced buffer but I'm getting
> compiler errors when using a slice to create the uint. Still new
> to Dlang and unfamiliar with the template system.
>
> How do I get this working?
>
> import std.bitmanip;
> int main()
> {
>     size_t offset = 3;
>     ubyte[10] buffer;
>     buffer[offset..offset+4] = nativeToBigEndian!uint(cast(uint)
> 104387);
>
>     // compiler error
>     uint fromBuf =
> bigEndianToNative!uint(buffer[offset..offset+4]);
>     return 0;
> }
>
> The compiler error:
> ./test.d(11): Error: template std.bitmanip.bigEndianToNative does
> not match any function template declaration. Candidates are:
> /usr/include/dmd/phobos/std/bitmanip.d(1689):
> std.bitmanip.bigEndianToNative(T, ulong n)(ubyte[n] val) if
> (canSwapEndianness!(T) && n == T.sizeof)
> ./test.d(11): Error: template std.bitmanip.bigEndianToNative(T,
> ulong n)(ubyte[n] val) if (canSwapEndianness!(T) && n ==
> T.sizeof) cannot deduce template function from argument types
> !(uint)(ubyte[])
> ./test.d(11): Error: template instance bigEndianToNative!(uint)
> errors instantiating template

You can't just use a dynamic array as a static array, because they're distinct
types. Slicing a static array gives you a dynamic one which refers to the
static array's memory, but to convert a dynamic array to a static one, you
have to cast it (which will do a copy). So, your code becomes something like

import std.bitmanip;
void main()
{
    size_t offset = 3;
    ubyte[10] buffer;
    buffer[offset..offset+4] = nativeToBigEndian!uint(104387);

    // compiler error
    auto fromBuf =
bigEndianToNative!uint(cast(ubyte[4])buffer[offset..offset+4]);
}

However, in this case, you should probably just not use a dynamic array. It
buys you nothing. You might as well just do.

import std.bitmanip;
void main()
{
    auto buffer = nativeToBigEndian!uint(104387);

    // compiler error
    auto fromBuf = bigEndianToNative!uint(buffer);
}

though obviously, your actual code may be doing something more complicated
that actually makes using the dynamic array reasonable. Regardless, dynamic
arrays must be cast to static arrays if you want to use a dynamic array where
a static array is required.

- Jonathan M Davis