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

*爱你&永不变心* 提交于 2019-12-23 07:31:09

问题


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.


回答1:


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.




回答2:


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;
};



回答3:


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?




回答4:


This does not really declare an array of fixed size, but puts a constraint on the size of its value: You can try and use where to constraint the size of the array. CArray is not a positional (and thus cannot be declared with the @ sigil) but it does have the elems method.

use NativeCall; 
my CArray[int32] $A where .elems < 2

That is, at least, syntactically correct. Whether that breaks the program in some other place remains to be seen. Can you try that?



来源:https://stackoverflow.com/questions/50723156/how-to-declare-native-array-of-fixed-size-in-perl-6

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!