Search code examples
arraysracketffi

Racket FFI -- example of C array (_array) usage?


I'm wrapping a C function that takes a pointer as an argument and treats it either as an int pointer, a float pointer, or an array of ints or floats, depending on another argument. The function is part of renderer in a game, and is called many (60+) times per second.

So with that said, I know I can use _list to pass array type argument, but

  • it fragments the heap? If I understand it correctly, racket calls malloc before each invocation, and free right after

  • it needs a specific type, so I would then have to create 2 functions (one for _int, one for _float), which wouldn't be ideal

I stumbled across https://docs.racket-lang.org/foreign/C_Array_Types.html , and it seems exactly what I want -- both more efficient ("The array is not copied; the Racket representation is backed by the underlying C representation") and also suitable for more than one type ("it can have a different element type as long as that type matches the layout of the expected type").

Problem is, I can't seem find a way how to construct it from Racket side? These all statements return #f, and I'm out of ideas

#lang racket

(require ffi/unsafe)

(displayln (array? (make-array-type _float 5)))
(displayln (array? (_array _float 5)))
(displayln (array? (malloc (_array _float 5))))
(displayln (array? (malloc (make-array-type _float 5))))

Solution

  • The make-array-type and _array functions create C types, which are plain Racket run-time values that describe how to convert kinds of values to and from C-level representations: for example, _unt8 is a C type. The predicate array? recognizes actual values that are represented with an _array-based C type, not the C type itself.

    As far as constructing an array value, the docs say:

    Since an array is treated like a struct, casting a pointer type to an array type does not work. Instead, use ptr-ref with a pointer, an array type constructed with _array, and index 0 to convert a pointer to a Racket representation that works with array-ref and array-set!.

    Here's how that works in practice—the docs could use an example:

    #lang racket
    
    (require ffi/unsafe
             rackunit)
    
    (define 5floats (_array _float 5))
    
    (check-true
     (array? (ptr-ref (malloc 5floats) 5floats)))
    

    For future reference, the Racket community is much more active on the racket-users mailing list and Slack than on Stack Overflow.