Request for changing auto-generated accessors of FFI aliases

Previous Topic Next Topic
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view

Request for changing auto-generated accessors of FFI aliases

Nicolas Cellier
the title is a bit complex, but I'll try to explain what I am after.

I need to pass a pointer to an atomic data because it is an output of a function.
But this atomic data is a named type (a typedef), and I want to preserve the name for several reasons:
- the typedef might evolve in another version of the library
- the typedef might be machine dependent (like size_t or unsigned long)

In VW, it's simple enough, i define the typedef directly, then use malloc and free like this:

    | lsb msb |
    [lsb := API H5T_pad_t malloc.
    msb := API H5T_pad_t malloc.
    API H5Tget_pad: handle with: lsb with: msb.
    lsbPadCache := lsb contents.
    msbPadCache := msb contents]
                [lsb isNil ifFalse: [lsb free].
                msb isNil ifFalse: [msb free]]

    <C: typedef enum __H5T_pad_t H5T_pad_t>

H5Interface>>H5Tget_pad: type_id with: lsb with: msb
    <C: herr_t H5Tget_pad(hid_t type_id, H5T_pad_t * lsb, H5T_pad_t * msb)>
    ^self externalAccessFailedWith: _errorCode

In Squeak, I have used this feature of ExternalStructure so as to alias another type (and have a sort of typedef):

So I create the class:

ExternalStructure subclass: #'H5T_pad_t'
    instanceVariableNames: ''
    classVariableNames: ''
    poolDictionaries: ''
    category: 'FFI-Tests'
Since it is an enum, I can use methods for accessing enum values

H5T_pad_t class>>H5T_PAD_ERROR ^-1
H5T_pad_t class>>H5T_PAD_ZERO  ^0
H5T_pad_t class>>H5T_PAD_ONE   ^1
H5T_pad_t class>>H5T_PAD_BACKGROUND ^2
H5T_pad_t class>>H5T_NPAD      ^3

And I can define the fields with the knowledge that most C implementation will use an int to store the enum:

H5T_pad_t class>>fields ^#( value 'long')

Then I can generate #value and #value: via H5T_pad_t defineFields and write:

    | lsb msb |
    lsb := H5T_pad_t new.
    msb := H5T_pad_t new.
    API H5Tget_pad: handle with: lsb with: msb.
    lsbPadCache := lsb value.
    msbPadCache := msb value

H5Interface>>H5Tget_pad: type_id with: lsb with: msb
    <cdecl: Herr_t 'H5Tget_pad'( Hid_t H5T_pad_t * H5T_pad_t * )>
    ^self externalCallFailed

H5T_pad_t new does the right thing: it allocates memory in a ByteArray, and store it in handle inst. var., something like handle := ByteArray new: 4

But then, the generated accessors not so: they consider that a non pointer atomic type does not require an intermediate memory buffer, because FFI can transform directly a Smalltalk atomic object (Integer/Boolean/Character/Float).

    value  ^handle
    value: anObject handle := anObject

They return the buffer instead of the content.

This is completely missing the point: the only reason I have to create an instance of such atomic type is to pass a reference (pointer) to the data, else, I can just use one of the enum accessors and pass the integer value directly:

    API H5Tset_pad: handle with: H5T_pad_t H5T_PAD_ZERO with: H5T_pad_t H5T_PAD_ZERO

H5Interface>>H5Tset_pad: type_id with: lsb with: msb
    <cdecl: Herr_t 'H5Tset_pad'( Hid_t H5T_pad_t H5T_pad_t )>
    ^self externalCallFailed

what I want is this:

    value ^handle longAt: 1
    value: anObject  handle longAt: 1 put: anObject

It's very simple to change because such generation already exists for accessing structure fields.

It's very logical to change, because consistent with the behavior of new and possible intentions of allocating an instance of such type as I showed above.

However, I absolutely don't know the impact of such change on existing code base.

1) the alias feature is not documented, has no test and no example (with accessors)
2) I don't know an easy way to scan the existing code base
   (SqueakSource, ss3, SmalltalkHub, HPI, etc...)

Has anyone got a better idea, or knows a library that would be broken, or have a strong opinion against this change for whatever reason?

I'll understand the absence of answer as a "carte blanche" to proceed.