native union struct
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
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
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
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
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
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
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