native union struct

2021-06-01 Thread jm

Hi,

I wanted to make a union to map some type to a byte array and back again 
so I started off like so;


# example class I want to map to a byte array
class N-GtkTargetEntry is repr('CStruct') is export {
  has Str $.target;
  has guint $.flags;
  has guint $.info;

  submethod BUILD ( Str :$target, Int :$!flags, Int :$!info ) {
    $!target := $target;
  }
}


# mapper class/union
class TargetEntryBytes is repr('CUnion') {
  HAS N-GtkTargetEntry $.target-entry;
  HAS CArray[uint8] $.target-bytes;

  multi submethod BUILD ( N-GtkTargetEntry :$target-entry! ) {
    $!target-entry := $target-entry;
  }

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    $!target-bytes := $target-bytes;
  }
}


The first build method of classTargetEntryBytesis doing well and when 
setting the $!target-entry I can retrieve the bytes from $!target-bytes.


Now, the second build method gives problems. I get nonsense values for 
the fields of $!target-entry when I want to set the $!target-bytes.


The next try did not improve matters

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    $!target-bytes := CArray[uint8].new;
    my Int $array-size = nativesizeof(N-GtkTargetEntry);
    for ^$array-size -> $i {
  $!target-bytes[$i] = $target-bytes[$i];
    }
  }

What I think is happening is that only an address is stored there 
pointing to an array elsewhere which does not map to the other union 
member. In this situation, the creation of the array does not take the 
'HAS' (uppercased!) attribute declaration into account.



I get a good result when the line '$!target-bytes := CArray[uint8].new;' 
is changed to '$!target-entry := N-GtkTargetEntry.new( :target(''), 
:flags(0), :info(0));' making space by setting a dummy $target-entry 
first and then overwrite the data by writing in $target-bytes.


The question: is it a bug or is this known behavior?
Anyways, it might be a good thing to know about,

Regards,
Marcel


native union structure

2021-06-01 Thread Marcel Timmerman

Hi,

(I reposted this because I did not saw it appear on the mailing list and 
added some new info)


I wanted to make a union to map some type to a byte array and back again 
so I started off like so;


# example class I want to map to a byte array
class N-GtkTargetEntry is repr('CStruct') is export {
  has Str $.target;
  has guint $.flags;
  has guint $.info;

  submethod BUILD ( Str :$target, Int :$!flags, Int :$!info ) {
    $!target := $target;
  }
}


# mapper class/union
class TargetEntryBytes is repr('CUnion') {
  HAS N-GtkTargetEntry $.target-entry;
  HAS CArray[uint8] $.target-bytes;

  multi submethod BUILD ( N-GtkTargetEntry :$target-entry! ) {
    $!target-entry := $target-entry;
  }

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    $!target-bytes := $target-bytes;
  }
}


The first build method of class N-TargetEntryBytes is doing well and 
when setting the $!target-entry I can retrieve the bytes from 
$!target-bytes.


Now, the second build method gives problems. I get nonsense values for 
the fields of $!target-entry when I set the $!target-bytes.


Then, the next attempt for the BUILD did not improve matters

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    $!target-bytes := CArray[uint8].new;
    my Int $array-size = nativesizeof(N-GtkTargetEntry);
    for ^$array-size -> $i {
  $!target-bytes[$i] = $target-bytes[$i];
    }
  }

What I think is happening here is that only an address is stored, 
pointing to an array elsewhere which does not map to the other union 
member. In this situation, the creation of the array does not take the 
'HAS' (uppercased!) attribute declaration into account.



I get a better result when the line '$!target-bytes := 
CArray[uint8].new;' is replaced by  '$!target-entry := 
N-GtkTargetEntry.new( :target(''), :flags(0), :info(0));' making space 
by setting a dummy $!target-entry first and then overwrite the data by 
writing in $!target-bytes.


Still not correct, the target value in the N-GtkTargetEntry keeps the 
string value I set, i.e. the empty string ''. Flags and info are now ok.


Final changes shown below give the proper outcome, i.e. the target 
string, flags and info  in the N-GtkTargetEntryclassare now set to the 
correct values! (Change is that the init of N-GtkTargetEntry in the 2nd 
BUILD is called without the :target argument)



class N-GtkTargetEntry is repr('CStruct') is export {
  has Str $.target;
  has guint $.flags;
  has guint $.info;

  submethod BUILD ( Str :$target?, Int :$!flags = 0, Int :$!info = 0 ) {
    $!target := $target if $target.defined;
  }
}

class TargetEntryBytes is repr('CUnion') {
  HAS N-GtkTargetEntry $.target-entry;
  HAS CArray[uint8] $.target-bytes;

  multi submethod BUILD ( N-GtkTargetEntry :$target-entry! ) {
    $!target-entry := $target-entry;
  }

  multi submethod BUILD ( CArray[uint8] :$target-bytes! ) {
    # need to make dummy to create proper space
    $!target-entry := N-GtkTargetEntry.new;

    my Int $array-size = nativesizeof(N-GtkTargetEntry);

    for ^$array-size -> $i {
  $!target-bytes[$i] = $target-bytes[$i];
    }
  }
}



The question: is there an explanation for this behavior because I do not 
understand it completely why it should be written like this ? It feels 
that there are some quirks where you need to program around it and 
afraid that it might change later without warning?



Regards,
Marcel



Re: Union

2016-04-12 Thread David Warring
Hi Marcel,
Not that I know of.
With regard to your original question. NativeCall has nativecast (as above)
for casting and a CUnion representation for unions. There are some tests in
https://github.com/rakudo/rakudo/blob/nom/t/04-nativecall/13-union.t for
this.

NativeCall is letting you get pretty close to the metal. Should be fast,
but the same dangers and caveats apply, to doing this directly in C.
- David


On Tue, Apr 12, 2016 at 6:51 PM, JuhiMarcel LangbroekTimmerman <
mt195...@gmail.com> wrote:

> Hi David,
>
> Thanks very much for your code, I will try it when I get home at the end
> of the week although I only have little endian Intell chips. I will have to
> look around for others. Btw, are there still chips storing big endian
> paired in two bytes? So your example number would become 0x23, 0x01, 0x67,
> 0x45 ?
>
> Thanks again,
> Marcel
>
> On April 11, 2016 9:45:13 PM David Warring 
> wrote:
>
>> Hi Marcel,
>> With regard to checking for endianess. I don't think there's anything
>> built in NativeCall that directly determines this, but hopefuly the
>> following should do it, without resorting to a C compiler.
>>
>> use NativeCall;
>> sub little-endian returns Bool {
>> my $i = CArray[uint32].new: 0x01234567;
>> my $j = nativecast(CArray[uint8], $i);
>> say sprintf("j[0]:%x j[3]:%x", $j[0], $j[3]);
>> $j[0] == 0x67;
>> }
>>
>> say "little-endian:" ~ little-endian;
>>
>> I've only tested this on a little endian architecture.
>>
>> Source: I ported the 'C' answer to this SO question:
>> http://stackoverflow.com/questions/12791864/c-program-to-check-little-vs-big-endian
>>
>>
>>
>> On Tue, Apr 12, 2016 at 6:30 AM, Marcel Timmerman 
>> wrote:
>>
>>> Hi
>>>
>>> Thanks for your answer. I was thinking in perl6, I should have been more
>>> explicit. At the moment I am converting Num to a float representation in
>>> my
>>> BSON module and was wondering if there where easier ways and maybe
>>> faster too.
>>>
>>> Regards,
>>> Marcel
>>>
>>>
>>>
>>>
>>>
>>>
>>> --- Forwarded message ---
>>> From: Marcel Timmerman 
>>> Date: April 11, 2016 8:28:22 PM
>>> Subject: Re: Union
>>> To: Parrot Raiser <1parr...@gmail.com>
>>>
>>> Hi
>>> Thanks for your answer. I was thinking in perl6, I should have been more
>>> explicit. At the moment I am converting Num to a float representation in
>>> my
>>> BSON module and was wondering if there where easier ways and maybe
>>> faster too.
>>>
>>> Regards,
>>> Marcel
>>>
>>>
>>>
>>>
>>>
>>


Re: Union

2016-04-11 Thread JuhiMarcel LangbroekTimmerman

Hi David,

Thanks very much for your code, I will try it when I get home at the end of 
the week although I only have little endian Intell chips. I will have to 
look around for others. Btw, are there still chips storing big endian 
paired in two bytes? So your example number would become 0x23, 0x01, 0x67, 
0x45 ?


Thanks again,
Marcel



On April 11, 2016 9:45:13 PM David Warring  wrote:


Hi Marcel,
With regard to checking for endianess. I don't think there's anything built
in NativeCall that directly determines this, but hopefuly the following
should do it, without resorting to a C compiler.

use NativeCall;
sub little-endian returns Bool {
my $i = CArray[uint32].new: 0x01234567;
my $j = nativecast(CArray[uint8], $i);
say sprintf("j[0]:%x j[3]:%x", $j[0], $j[3]);
$j[0] == 0x67;
}

say "little-endian:" ~ little-endian;

I've only tested this on a little endian architecture.

Source: I ported the 'C' answer to this SO question:
http://stackoverflow.com/questions/12791864/c-program-to-check-little-vs-big-endian



On Tue, Apr 12, 2016 at 6:30 AM, Marcel Timmerman  wrote:


Hi

Thanks for your answer. I was thinking in perl6, I should have been more
explicit. At the moment I am converting Num to a float representation in
my
BSON module and was wondering if there where easier ways and maybe faster
too.

Regards,
Marcel






--- Forwarded message ---
From: Marcel Timmerman 
Date: April 11, 2016 8:28:22 PM
Subject: Re: Union
To: Parrot Raiser <1parr...@gmail.com>

Hi
Thanks for your answer. I was thinking in perl6, I should have been more
explicit. At the moment I am converting Num to a float representation in my
BSON module and was wondering if there where easier ways and maybe faster
too.

Regards,
Marcel







Re: Union

2016-04-11 Thread David Warring
Hi Marcel,
With regard to checking for endianess. I don't think there's anything built
in NativeCall that directly determines this, but hopefuly the following
should do it, without resorting to a C compiler.

use NativeCall;
sub little-endian returns Bool {
my $i = CArray[uint32].new: 0x01234567;
my $j = nativecast(CArray[uint8], $i);
say sprintf("j[0]:%x j[3]:%x", $j[0], $j[3]);
$j[0] == 0x67;
}

say "little-endian:" ~ little-endian;

I've only tested this on a little endian architecture.

Source: I ported the 'C' answer to this SO question:
http://stackoverflow.com/questions/12791864/c-program-to-check-little-vs-big-endian



On Tue, Apr 12, 2016 at 6:30 AM, Marcel Timmerman  wrote:

> Hi
>
> Thanks for your answer. I was thinking in perl6, I should have been more
> explicit. At the moment I am converting Num to a float representation in
> my
> BSON module and was wondering if there where easier ways and maybe faster
> too.
>
> Regards,
> Marcel
>
>
>
>
>
>
> --- Forwarded message ---
> From: Marcel Timmerman 
> Date: April 11, 2016 8:28:22 PM
> Subject: Re: Union
> To: Parrot Raiser <1parr...@gmail.com>
>
> Hi
> Thanks for your answer. I was thinking in perl6, I should have been more
> explicit. At the moment I am converting Num to a float representation in my
> BSON module and was wondering if there where easier ways and maybe faster
> too.
>
> Regards,
> Marcel
>
>
>
>
>


Re: Union

2016-04-11 Thread Marcel Timmerman

Hi

Thanks for your answer. I was thinking in perl6, I should have been more 
explicit. At the moment I am converting Num to a float representation in my 
BSON module and was wondering if there where easier ways and maybe faster too.

Regards,
Marcel






--- Forwarded message ---
From: Marcel Timmerman 
Date: April 11, 2016 8:28:22 PM
Subject: Re: Union
To: Parrot Raiser <1parr...@gmail.com>

Hi
Thanks for your answer. I was thinking in perl6, I should have been more
explicit. At the moment I am converting Num to a float representation in my
BSON module and was wondering if there where easier ways and maybe faster too.

Regards,
Marcel






Union

2016-04-11 Thread Marcel Timmerman

Hi,

While the perl language already offers so much I have a question not found 
in perl


Is there anything like the C union to do an easy mapping from some native 
variable to a buf of the same number of bytes? This is a nice helper for 
pack/unpack for native values. It is important to know about little/big 
endian in such cases.


Greetings
Marcel