Simple Decision Tables

Deep nested branches can get quite ugly to read and even follow, I find decision tables can be a good technique to cleaning up some code. It also a good way to make code data centeric. Wiki has an article on it.

Here is a simple/contrived example.

#include <stdint.h>
#include <stdio.h>


int
main() {
        /* flags that represent some data */
        uint32_t renderable_bit = 1 << 0;
        uint32_t input_bit = 1 << 1;
        uint32_t menu_bit = 1 << 2;
        uint32_t player_bit = 1 << 3;

        /* conditions */
        uint32_t should_render = renderable_bit;
        uint32_t should_update_player = player_bit | input_bit;
        uint32_t should_play_menu_audio = menu_bit | input_bit;

        /* world data - in the real world this will be runtime */
        struct renderable {int i;};
        struct renderable renderables[1];

        struct player {int i;};
        struct player players[1];

        struct menu {int i;};
        struct menu menu_items[0];

        struct input {int i;};
        struct input inputs[1];

        /* world state */
        uint32_t world = 0;
        world |= (sizeof(renderables) ? renderable_bit : 0);
        world |= (sizeof(players) ? player_bit : 0);
        world |= (sizeof(menu_items) ? menu_bit : 0);
        world |= (sizeof(inputs) ? input_bit : 0);

        /* process world */
        if((world & should_update_player) == should_update_player) {
                printf("update_player();\n");
        }

        if((world & should_render) == should_render) {
                printf("render();\n");
        }

        if((world & should_play_menu_audio) == should_play_menu_audio) {
                printf("play_menu_audio();\n");
        }
}

build and go

cc simple_decision_table.c && ./a.out

Outputs

update_player();
render();

As you can see we don’t play any audio because the bit never got set. I have in the past used to this to know what tasks to send off to the thread pool.