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

Julian Fondren jfondren at minimaltype.com
Tue Jul 9 09:20:02 AEST 2019


On 2019-07-08 17:46, 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)
> ]).

How's this?

Summary: process the list in Mercury; or the flags in C.

:- module orz.
:- interface.
:- import_module io.
:- pred main(io::di, io::uo) is det.
:- implementation.
:- import_module string, list.

:- type test
     --->    test(string, int, int).

main(!IO) :-
     foldl((pred(test(T, R, E)::in, !.IO::di, !:IO::uo) is det :-
         io.format("flags_to_int(%s) = %d (expected %d)\n",
             [s(T), i(R), i(E)], !IO)), Tests, !IO),
     Tests = [
         test("[]", flags_to_int([]), 0),
         test("[fullscreen, opengl]", flags_to_int([fullscreen, opengl]), 
3),
         test("[...everything...]", flags_to_int(Everything), 15)
     ],
     Everything = [fullscreen, opengl, shown, resizable].

% we want to define these
:- func flags_to_int(list(window_flag)) = int.
:- func or(window_flag, int) = int.

% pretend these constants exist
:- pragma foreign_decl("C", "
#define SDL_WINDOW_FULLSCREEN 1
#define SDL_WINDOW_OPENGL 2
#define SDL_WINDOW_SHOWN 4
#define SDL_WINDOW_RESIZABLE 8
").

% the usual way
:- type window_flag
     ---> fullscreen ; opengl ; shown ; resizable.

:- pragma foreign_enum("C", window_flag/0, [
     fullscreen          - "SDL_WINDOW_FULLSCREEN",
     opengl              - "SDL_WINDOW_OPENGL",
     shown               - "SDL_WINDOW_SHOWN",
     resizable           - "SDL_WINDOW_RESIZABLE"
]).

% ------------------------------------------------------------

flags_to_int(L) = foldl(or, L, 0).

:- pragma foreign_proc("C",
     or(Flag::in, Acc0::in) = (Acc::out),
     [will_not_call_mercury, promise_pure, thread_safe],
"
     Acc = Acc0 | Flag;
").


More information about the users mailing list