December 13, 2006
novice2 kirjoitti:
> == Quote from Alexander Panek (a.panek@brainsware.org)'s article
>> ubyte [] toByteArray (T) (T t) {
>> 	return (cast(ubyte *)&t)[0..T.sizeof].dup
>> }
> 
>> auto b = toByteArray!(Foo)(f); // Yay!
> 
> why we need two parameters?
> compiler don't know type of f?


This works:

auto b = toByteArray(f); // Yay!
December 13, 2006

Luís Marques wrote:
> Hello,
> 
> Converting a structure to ubyte[] or similar is something that I have been doing frequently while converting C to D code.
> 
> Can we have a "cast(type[])" working for structures, please?
> 
> I suppose that type should include at least ubyte, byte and char, if not all the basic data types.

Be careful with char: D char type is not a byte, it's a UTF-8 code unit. Don't try to use char[] for storing raw data.
December 13, 2006
Endea wrote:
> novice2 kirjoitti:
>> == Quote from Alexander Panek (a.panek@brainsware.org)'s article
>>> ubyte [] toByteArray (T) (T t) {
>>>     return (cast(ubyte *)&t)[0..T.sizeof].dup
>>> }
>>
>>> auto b = toByteArray!(Foo)(f); // Yay!
>>
>> why we need two parameters?
>> compiler don't know type of f?
> 
> 
> This works:
> 
> auto b = toByteArray(f); // Yay!

Huzzah for IFTI!

-- Chris Nicholson-Sauls
December 13, 2006
>> This works:
>>
>> auto b = toByteArray(f); // Yay!
> 
> Huzzah for IFTI!

Huuh. :o

Didn't know that'd work, actually.
December 13, 2006
On Wed, 13 Dec 2006 14:22:32 -0600, Chris Nicholson-Sauls wrote:

> Endea wrote:
>> novice2 kirjoitti:
>>> == Quote from Alexander Panek (a.panek@brainsware.org)'s article
>>>> ubyte [] toByteArray (T) (T t) {
>>>>     return (cast(ubyte *)&t)[0..T.sizeof].dup
>>>> }
>>>
>>>> auto b = toByteArray!(Foo)(f); // Yay!
>>>
>>> why we need two parameters?
>>> compiler don't know type of f?
>> 
>> This works:
>> 
>> auto b = toByteArray(f); // Yay!
> 
> Huzzah for IFTI!

Yes, but unfortunately the actual function is faulty. Here is what I had to do to get it to work ...

ubyte [] toByteArray (T) (inout T t)
{
    union ubyte_abi
    {
        ubyte[] x;
        struct
        {
           uint  xl; // length
           void* xp; // ptr
        }
    }
    ubyte_abi res;
    res.xp = cast(void*)&t;
    res.xl = T.sizeof;
    return res.x;
}

unittest
{
   struct Foo_uni
   {
      int a;
      real b;
      char[4] c;
      dchar[] d;
   }
   Foo_uni f;
   ubyte[] b;

   b = toByteArray(f);

   assert(b.length == f.sizeof);
   assert(cast(void*)(b.ptr) == cast(void *)&f);

   real c;
   b = toByteArray(c);
   assert(b.length == c.sizeof);
   assert(cast(void*)(b.ptr) == cast(void *)&c);

   class Bar_uni
   {
      int a;
      real b;
      char[4] c;
      dchar[] d;
   }
   Bar_uni g = new Bar_uni;

   b = toByteArray(g.d);
   assert(b.length == g.d.sizeof);
   assert(cast(void*)(b.ptr) == cast(void *)&g.d);

}


-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
14/12/2006 10:45:46 AM
December 14, 2006
Derek Parnell wrote:
> 
> 
> Yes, but unfortunately the actual function is faulty. Here is what I had to
> do to get it to work ...
> 
> ubyte [] toByteArray (T) (inout T t)
> {
>     union ubyte_abi
>     {
>         ubyte[] x;
>         struct
>         {
>            uint  xl; // length
>            void* xp; // ptr
>         }
>     }
>     ubyte_abi res;
>     res.xp = cast(void*)&t;
>     res.xl = T.sizeof;
>     return res.x;
> }
> 

What didn't work???
Unless arrays are broken, that should be the same.;
December 14, 2006
On Wed, 13 Dec 2006 20:48:43 -0800, BCS wrote:

> Derek Parnell wrote:
>> 
>> Yes, but unfortunately the actual function is faulty. Here is what I had to do to get it to work ...
>> 
>> ubyte [] toByteArray (T) (inout T t)
>> {
>>     union ubyte_abi
>>     {
>>         ubyte[] x;
>>         struct
>>         {
>>            uint  xl; // length
>>            void* xp; // ptr
>>         }
>>     }
>>     ubyte_abi res;
>>     res.xp = cast(void*)&t;
>>     res.xl = T.sizeof;
>>     return res.x;
>> }
>> 
> 
> What didn't work???
> Unless arrays are broken, that should be the same.;

The original function was

  ubyte [] toByteArray (T) (T t)
  {
     return (cast(ubyte *)&t)[0..T.sizeof].dup
  }

With this, the '&t' phrase takes the address of the data as passed-by-value. Which means that when passing a struct or basic type, you get the address of the copy of the data which of course is not in scope when you return from the function. The '.dup' takes another copy of the data (this time on the heap) and you return the ubyte[] reference to the second copy. So you end up with a ubyte[] array that references a copy of the struct/data you supplied to the function and doesn't reference the initial data at all. Of course, that might be what you are trying to do ;-) I just thought that what was being attempted was to have a ubyte[] to access the data in the original struct instance and not a copy of it.


My function avoids taking copies of the data and returns a ubyte[] reference to the actual struct/data instance passed to the function.

Both are invoked with identical syntax thanks to IFTI and D's handling of inout parameters.

-- 
Derek
(skype: derek.j.parnell)
Melbourne, Australia
"Down with mediocrity!"
14/12/2006 4:42:50 PM
December 14, 2006

Derek Parnell wrote:
> On Wed, 13 Dec 2006 20:48:43 -0800, BCS wrote:
> 
>> Derek Parnell wrote:
>>> Yes, but unfortunately the actual function is faulty. Here is what I had to
>>> do to get it to work ...
>>>
>>> ubyte [] toByteArray (T) (inout T t)
>>> {
>>>     union ubyte_abi
>>>     {
>>>         ubyte[] x;
>>>         struct
>>>         {
>>>            uint  xl; // length
>>>            void* xp; // ptr
>>>         }
>>>     }
>>>     ubyte_abi res;
>>>     res.xp = cast(void*)&t;
>>>     res.xl = T.sizeof;
>>>     return res.x;
>>> }
>>>
>> What didn't work???
>> Unless arrays are broken, that should be the same.;
> 
> The original function was 
> 
>   ubyte [] toByteArray (T) (T t)   {
>      return (cast(ubyte *)&t)[0..T.sizeof].dup
>   }
> 
> With this, the '&t' phrase takes the address of the data as
> passed-by-value. Which means that when passing a struct or basic type, you
> get the address of the copy of the data which of course is not in scope
> when you return from the function. The '.dup' takes another copy of the
> data (this time on the heap) and you return the ubyte[] reference to the
> second copy. So you end up with a ubyte[] array that references a copy of
> the struct/data you supplied to the function and doesn't reference the
> initial data at all. Of course, that might be what you are trying to do ;-)
> I just thought that what was being attempted was to have a ubyte[] to
> access the data in the original struct instance and not a copy of it.
> 
> 
> My function avoids taking copies of the data and returns a ubyte[]
> reference to the actual struct/data instance passed to the function.
> 
> Both are invoked with identical syntax thanks to IFTI and D's handling of
> inout parameters.
> 

But why did you need the union/struct trick?

And with this, isn't the compiler free to rearrangre struct fields??

    union ubyte_abi
    {
        ubyte[] x;
        struct	//isn't the compiler free to rearrangre struct fields??
        {
           uint  xl; // length
           void* xp; // ptr
        }
    }
December 14, 2006
Hasan Aljudy wrote:
> 

> And with this, isn't the compiler free to rearrangre struct fields??

Nope.  See http://www.digitalmars.com/d/class.html under "Fields":
  "Explicit control of field layout is provided by struct/union types, not classes."

--bb
December 14, 2006
Derek Parnell wrote:
> Yes, but unfortunately the actual function is faulty. Here is what I had to
> do to get it to work ...
> 
> ubyte [] toByteArray (T) (inout T t)
> {
>     union ubyte_abi
>     {
>         ubyte[] x;
>         struct
>         {
>            uint  xl; // length
>            void* xp; // ptr
>         }
>     }
>     ubyte_abi res;
>     res.xp = cast(void*)&t;
>     res.xl = T.sizeof;
>     return res.x;
> }
> 
> unittest
> {
>    struct Foo_uni
>    {
>       int a;
>       real b;
>       char[4] c;
>       dchar[] d;
>    }
>    Foo_uni f;
>    ubyte[] b;
> 
>    b = toByteArray(f);
> 
>    assert(b.length == f.sizeof);
>    assert(cast(void*)(b.ptr) == cast(void *)&f);
> 
>    real c;
>    b = toByteArray(c);
>    assert(b.length == c.sizeof);
>    assert(cast(void*)(b.ptr) == cast(void *)&c);
> 
>    class Bar_uni
>    {
>       int a;
>       real b;
>       char[4] c;
>       dchar[] d;
>    }
>    Bar_uni g = new Bar_uni;
> 
>    b = toByteArray(g.d);
>    assert(b.length == g.d.sizeof);
>    assert(cast(void*)(b.ptr) == cast(void *)&g.d);
> 
> }

Amazing. Thanks.

Yet, by this time, don't you think it would be best if the compiler worked out the cast to ubyte[] on its own?