Efficient arrays of colors, events, points, and rects
There are several functions in SDL2 that accept or return a C array of colors, events, points, or rects. For example:
Currently the bindings to such functions accept either a Scheme list or vector of instances of the type. The bindings allocate a C array of the appropriate size, then copy the data from each instance into the array. They then pass this C array to the function, and deallocate the array before returning.
Similarly, SDL_Palette holds an array of colors, so palette-colors
does the process in reverse: it allocates a Scheme vector of color instances, then copies the data from the C array.
These processes are not very efficient. They involve a lot of temporary allocation, copying, and freeing of memory, which are performed every time the list or array is passed to a function.
I propose that color-array
, event-array
, point-array
, and rect-array
types, which wrap a pointer to a C array of each struct type. Procedures would be available to perform the following operations for each type:
- Allocate an managed or unmanaged array of a certain size, filled with an initial element. (Similar to Scheme's
make-vector
.) - Free an array.
- Create an array by copying from a Scheme list or vector, and vice versa. (E.g.
list->color-array
,vector->event-array
,point-array->list
,rect-array->vector
.) - Get the length (number of items) of the array.
- Get an individual item by index, as a record or a raw pointer (without copying).
- Set an individual item by index, by copying from a record or a raw pointer.
For safety, the array types would remember their own length, and signal an error if the user tries to access an index out of bounds.
An important idea is that when you get an item from the array, it does not return a copy. Instead, it returns a struct record instance that wraps pointer to a location within the C array. The instance can be used the same as any other instance, except that it cannot be freed individually. The advantage is that the array as a whole can be passed to an SDL function with no allocation or copying necessary.
Struct record instances that are stored in an array would need a flag to mark the fact that the memory should not be freed if the user tries to manually free them, e.g. with free-rect!
.
If it is possible and safe to do so, managed arrays should be allocated as blobs on the CHICKEN stack. Getting an individual instance from the array should create a locative with a byte offset, e.g. (make-locative the-blob 4)
. I think this would allow the locative to remain valid even if the array blob is moved in memory by the GC. (This needs to be confirmed.)
Bindings that accept a list or vector of colors, events, points, or rects would be updated to also allow an array of the appropriate type. Bindings that return a list or vector of those items, should be updated to instead return an array. Unfortunately, this will break backwards compatibility, but it will be worth it in the long term.