Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to declare native array of fixed size in Perl 6?

I'm am trying to declare the following C struct in Perl 6:

struct myStruct
{
    int A[2]; //<---NEED to declare this
    int B;
    int C;
};

My problem is that I don't know how to declare the int A[2]; part using the built in NativeCall api.

So for what I have is:

class myStruct is repr('CStruct') {
    has CArray[int32] $.A;
    has int32 $.B;
    has int32 $.C;
};

However, I know that the has CArray[int32] $.A; part is wrong as it does not declare a part in my struct that takes up ONLY 2 int32 sizes.

like image 576
annoying_squid Avatar asked Jun 06 '18 14:06

annoying_squid


3 Answers

Update 2: It turned out that this didn't work at the time I first posted this answer, hence the comments. I still haven't tested it but it must surely work per Tobias's answer to Passing an inlined CArray in a CStruct to a shared library using NativeCall. \o/


I haven't tested this, but this should work when using Rakudo compiler release 2018.05:

use NativeCall;
class myStruct is repr('CStruct') {
    HAS int32 @.A[2] is CArray;
    has int32 $.B;
    has int32 $.C;
}
  • HAS instead of has causes the attribute to be inline rather than a pointer;

  • int32 instead of int is because the Perl 6 int type isn't the same as C's int type but is instead platform specific (and usually 64 bit);

  • @ instead of $ marks the attribute as being Positional ("supports looking up values by index") instead of scalar (which gets treated as a single thing);

  • [2] "shapes" the Positional data to have 2 elements;

  • is CArray binds a CArray as the Positional data's container logic;

  • This commit from April this year wired up the is repr('CStruct') to use the declared attribute information to appropriately allocate memory.

Fwiw I found out about this feature from a search of the #perl6 logs for CArray and found out it had landed in master and 2018.05 from a search of Rakudo commits for the commit message title.

like image 62
raiph Avatar answered Nov 03 '22 12:11

raiph


See Declaring an array inside a Perl 6 NativeCall CStruct

There are other ways, but the easiest is instead of an array, just declare each individual item.

class myStruct is repr('CStruct') {
    has int32 $.A0;
    has int32 $.A1;
    ... as many items as you need for your array ...
    has int32 $.B;
    has int32 $.C;
};
like image 42
Curt Tilmes Avatar answered Nov 03 '22 13:11

Curt Tilmes


So I've done some experimentation on this and taken a look at the docs and it looks like the CArray type doesn't handle shaping the same way as Perl6 Arrays.

The closest thing you've got it the allocate constructor that preallocates space in the array but it doesn't enforce the size so you can add more things.

Your class definition is fine but you'd want to allocate the array in the BUILD submethod.

https://docs.raku.org/language/nativecall#Arrays

(Further thought)

You could have two objects. One internal and one for the struct.

The Struct has a CArray[int32] array. The internal data object has a shaped int32 cast array my int3 @a[2]. Then you just need to copy between the two.

The getters and setter live on the main object and you use the struct object just when you want to talk to the lib?

like image 3
Scimon Proctor Avatar answered Nov 03 '22 14:11

Scimon Proctor