[m-users.] Dealing with lists of enums as bitflags in C

Julien Fischer jfischer at opturion.com
Tue Jul 9 12:23:53 AEST 2019


Hi,

On Mon, 8 Jul 2019, emacstheviking wrote:

> I have been hacking a good hour or two and not really made much
> progress for something that I thought would have been simpler, but.
> Ignorance!!
> In my SDL2 wrapper I have a list of types that correspond to the
> various window creation flags, I am passing them as a list as that's
> the nicest way of doing it I think,
> 
> sdl_createwindow("Test", 100, 100, 640, 480, [resizable, shown], !IO)
> 
> The types are declared as foreign enums in the usual way :-
> :- type window_flag
>     ---> fullscreen ; opengl ; shown ; resizable ..... (elided)
> 
> :- pragma foreign_enum("C", window_flag/0, [
>     fullscreen          - "SDL_WINDOW_FULLSCREEN",
>     opengl              - "SDL_WINDOW_OPENGL",
>     shown               - "SDL_WINDOW_SHOWN",
>     resizable           - "SDL_WINDOW_RESIZABLE",
>    :...(elided)
> ]).
> 
> By using the --make-target option to poke at the generated code I can
> see that it comes into the C code as MR_Word, not MR_Word*thought and
> then I tracked down the definitions of the MR_is_list_empty macros etc
> and realised pretty quickly that there is no "MR_get_next" as it
> should be as simple as pointer arithmetic but so far it has escaped my
> best efforts. I have seen that the array is composed as a static array
> of values from the MR_TAG_COMMON but I lost the trail at that point.

If you haven't done so already, have a look at
<http://mercurylang.org/information/doc-latest/mercury_ref/C-data-passing-conventions.html#C-data-passing-conventions>
since it lists all of the list manipulation macros.

> Here is my code:
> 
> :- pred sdl_createwindow(string::in, int::in, int::in, int::in, int::in, list(window_flag)::in, io::di, io::uo) is det.
> :- pragma foreign_proc("C",
>     sdl_createwindow(Title::in, X::in, Y::in, W::in, H::in, Flags::in, _IO0::di, _IO::uo),
>     [promise_pure,will_not_call_mercury,does_not_affect_liveness],
> "
> Uint32 flags = 0;
> if (Flags) {
>     MR_Word* flagPtr = &Flags;
>     while(!MR_list_is_empty(*flagPtr)) {
>         Uint32 f = MR_list_head(*flagPtr);
>         flags |= f;
>         printf(""FLAGS: %u\\n"", flags);
>         flagPtr++;
>     }
> }
> SDL_Window* wnd = SDL_CreateWindow(Title, X, Y, W, H, flags);
> ").
> 
> I just want to iterate the list of types and OR together the final bit
> flag uint32 value and get on with creating the window. This is
> something that is going to crop up again and again in various parts of
> the library. I am pretty sure I will figure out immediately hitting
> send.....

I started writing an SDL binding many years ago and as the above kind of
thing occurs in a number of places I defined the following utility
function in C to handle the conversion of lists of of flags:

     :- pragma foreign_code("C", "

       Uint32
       MSDL_list_to_flags(MR_Word list)
       {
         Uint32  flags = 0;

         while (!MR_list_is_empty(list)) {
             flags |= (Uint32) MR_list_head(list);
             list = MR_list_tail(list);
         }
         return flags;
      }
    ").

Julien.


More information about the users mailing list