Optimize integer-to-symbol conversion for keycodes and scancodes
I believe there is opportunity to optimize the conversion of keycodes and scancodes from integer to symbol. Currently these conversions use a hash table, but I think it could be more efficient by using a Scheme vector and a C switch
statement.
(Going in the other direction, from symbol to integer, currently uses a Scheme case
expression, which is already pretty fast. Besides, speed is not as important going in that direction, because it happens less often.)
My proposal is to create a new variant of define-enum-mappings
which does 3 things:
- Defines a (private) Scheme vector of all the symbols in the enum group.
- Defines a (private) C function (using
foreign-lambda*
) which takes an enum integer value, uses a Cswitch
statement to look up the enum, and returns the index of the corresponding symbol in the vector. - Defines a conversion procedure which takes an enum integer value, passes it to the C function to get the vector index, then performs the vector lookup and returns the symbol.
Here is an abbreviated example of what the macro would expand into:
(define %keycode-symbols-vector
'#(unknown return escape backspace tab space ... sleep))
(define %lookup-keycode-index
(foreign-lambda*
int ((SDL_Keycode keycode))
"switch(keycode) {"
" case SDLK_UNKNOWN: { C_return( 0 ); }"
" case SDLK_RETURN: { C_return( 1 ); }"
" case SDLK_ESCAPE: { C_return( 2 ); }"
" case SDLK_BACKSPACE: { C_return( 3 ); }"
" case SDLK_TAB: { C_return( 4 ); }"
" case SDLK_SPACE: { C_return( 5 ); }"
...
" case SDLK_SLEEP: { C_return( 235 ); }"
" default: { C_return( -1 ); }"
"};"))
(define (keycode->symbol keycode)
(let ((index (%lookup-keycode-index keycode)))
(if (= -1 index)
(error "Invalid enum value" keycode)
(vector-ref %keycode-symbols-vector index))))
It would be tedious and error-prone to write out hundreds of cases by hand, but a macro could easily and reliably generate the code for us.
(One might ask, why not directly use the enum integer value as the vector index? That could work for scancodes, which have 241 values ranging from 0 to 284. But it would not work for keycodes, which have 236 values ranging from 0 to 1073742106. We would need a vector with over 1 trillion slots, merely to hold 236 symbols.)
The downside of using the method proposed above instead of a hash table, is that new members cannot be added after compilation. That is okay for keycodes and scancodes, but it means that we could not use this method for user event types, which is the other enum conversion currently using hash tables.