Discussion:
bitmanip bigEndianToNative using a buffer slice?
Lucas Burson via Digitalmars-d-learn
2014-10-22 00:45:17 UTC
Permalink
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
ketmar via Digitalmars-d-learn
2014-10-22 01:08:42 UTC
Permalink
On Wed, 22 Oct 2014 00:45:17 +0000
Lucas Burson via Digitalmars-d-learn
Post by Lucas Burson via Digitalmars-d-learn
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. ;-)
Lucas Burson via Digitalmars-d-learn
2014-10-22 01:30:48 UTC
Permalink
On Wednesday, 22 October 2014 at 01:08:52 UTC, ketmar via
Post by Lucas Burson via Digitalmars-d-learn
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...
ketmar via Digitalmars-d-learn
2014-10-22 01:37:05 UTC
Permalink
On Wed, 22 Oct 2014 01:30:48 +0000
Lucas Burson via Digitalmars-d-learn
Post by Lucas Burson via Digitalmars-d-learn
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. ;-)
Jonathan M Davis via Digitalmars-d-learn
2014-10-22 01:59:20 UTC
Permalink
On Wednesday, October 22, 2014 00:45:17 Lucas Burson via
Digitalmars-d-learn
Post by Lucas Burson via Digitalmars-d-learn
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;
}
./test.d(11): Error: template std.bitmanip.bigEndianToNative
does
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

Loading...