mmozeiko
What is "table" in C++?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | enum ANIMATION_DATA { anim_bub_idle = 0, anim_bub_idle_bubble = 4, anim_bub_jump = 8, anim_bub_dead = 12, anim_bub_run = 16, anim_bub_moving_bubble = 20, anim_bubble_spawn = 24, anim_bubble_normal = 28, anim_bubble_bounce = 32, anim_bubble_alert = 36, anim_bubble_alert_bounce = 40, anim_bubble_pop = 44, anim_banebou_normal = 48, anim_banebou_captured = 52, anim_banebou_captured_alert1 = 56, anim_banebou_captured_alert2 = 60, anim_banebou_angry = 64, anim_invader_normal = 68, anim_invader_angry = 72, anim_invader_captured = 76, anim_invader_captured_alert1 = 80, anim_invader_captured_alert2 = 84, }; i32 animation_list[22*4] = // ID, first, last, duration { 0, 0, 1, 20, // bub_idle 4, 2, 3, 10, // bub_idle_bubble 8, 4, 7, 8, // bub_jump 12, 8, 11, 20, // bub_dead 16, 12, 18, 6, // bub_run 20, 19, 25, 50, // bub_moving_bubble 24, 9, 15, 6, // bubble_spawn 28, 0, 1, 10, // bubble_normal 32, 1, 2, 20, // bubble_bounce 36, 3, 4, 30, // bubble_alert 40, 5, 6, 60, // bubble_alert_bounce 44, 7, 8, 40, // bubble_pop 48, 0, 3, 20, // banebou_normal 52, 4, 7, 20, // banebou_captured 56, 8, 11, 20, // banebou_captured_alert1 60, 12, 15, 20, // banebou_captured_alert2 64, 16, 19, 20, // banebou_angry 68, 0, 1, 20, // invader_normal 72, 2, 3, 20, // invader_angry 76, 4, 7, 20, // invader_captured 80, 8, 11, 20, // invader_captured_alert1 84, 12, 15, 20, // invader_captured_alert2 }; |
immortalx
If that's the case, yeah it's difficult to maintain. But I'm not aware of another solution and would like to know myself if there's one.
immortalx
Oh, I see it supports multiple types. That's pretty cool! Would you mind sharing some more info about your language?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #define OpenGL_Procs \ OpenGL_Proc( PFNGLATTACHSHADERPROC, glAttachShader ) \ OpenGL_Proc( PFNGLBINDBUFFERPROC, glBindBuffer ) \ OpenGL_Proc( PFNGLBINDVERTEXARRAYPROC, glBindVertexArray ) \ OpenGL_Proc( PFNGLBUFFERDATAPROC, glBufferData ) \ OpenGL_Proc( PFNGLCOMPILESHADERPROC, glCompileShader ) \ OpenGL_Proc( PFNGLCREATEPROGRAMPROC, glCreateProgram ) \ OpenGL_Proc( PFNGLCREATESHADERPROC, glCreateShader ) \ #define OpenGL_Proc(type, name) static type name; OpenGL_Procs #undef OpenGL_Proc static const struct { const char *name; void (**funcptr)(void); } opengl_procs_to_load[] = { #define OpenGL_Proc(type, name) { # name, (void(**)(void))&name }, OpenGL_Procs #undef OpenGL_Procs }; |
jstimpfle
I haven't seen a mention of a technique called X-macros, which I use frequently, and which covers most of my table needs.
What you do is you define a macro that makes itself a number of calls to functions that are not defined.
Then you use this macro at various places, by first defining the undefined functions as macros and then simply writing the macro's name.
As an example, here's an excerpt from my OpenGL loader code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #define OpenGL_Procs \ OpenGL_Proc( PFNGLATTACHSHADERPROC, glAttachShader ) \ OpenGL_Proc( PFNGLBINDBUFFERPROC, glBindBuffer ) \ OpenGL_Proc( PFNGLBINDVERTEXARRAYPROC, glBindVertexArray ) \ OpenGL_Proc( PFNGLBUFFERDATAPROC, glBufferData ) \ OpenGL_Proc( PFNGLCOMPILESHADERPROC, glCompileShader ) \ OpenGL_Proc( PFNGLCREATEPROGRAMPROC, glCreateProgram ) \ OpenGL_Proc( PFNGLCREATESHADERPROC, glCreateShader ) \ #define OpenGL_Proc(type, name) static type name; OpenGL_Procs #undef OpenGL_Proc static const struct { const char *name; void (**funcptr)(void); } opengl_procs_to_load[] = { #define OpenGL_Proc(type, name) { # name, (void(**)(void))&name }, OpenGL_Procs #undef OpenGL_Procs };
It's crufty, admittedly, but there's very little boilerplate involved and no extra build system integration is needed.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | typedef uint8_t OrchInputCommand; #define OrchInputCommand_nav 0 #define OrchInputCommand_replace 1 #define OrchInputCommand_insert 2 #define OrchInputCommand_move 3 #define OrchInputCommand_delete 4 #define OrchInputCommand_modify 5 #define OrchInputCommand_undo 6 #define OrchInputCommand_redo 7 #define OrchInputCommand_locate 8 #define OrchInputCommand_validate 9 #define OrchInputCommand_save 10 #define OrchInputCommand_close 11 #define OrchInputCommand_COUNT 12 extern char* OrchInputCommand_hint_box_strings[]; char* OrchInputCommand_hint_box_strings[] = { [OrchInputCommand_replace] = "replace", [OrchInputCommand_insert] = "insert", [OrchInputCommand_move] = "move", [OrchInputCommand_delete] = "delete", [OrchInputCommand_modify] = "modify", [OrchInputCommand_undo] = "undo", [OrchInputCommand_redo] = "redo", [OrchInputCommand_locate] = "locate", [OrchInputCommand_validate] = "validate", [OrchInputCommand_save] = "save", [OrchInputCommand_close] = "close", }; |
HRose
Since C99, you can include a "designator" in array initialization literials.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | // Pre-conditions: // name contains at most 12 characters before the null terminator // Codes: // 1..26 is a..z or A..Z (case insensitive) // _ is 27 constexpr uint64_t getSparseIndex(const char* name) { uint64_t result = 0U; for (uint64_t i = 0U; i < 12; i++) { char c = name[i]; if (c == '\0') { return result; } else if (c >= 'a' && c <= 'z') { result = (result << 5) | (c - 'a' + 1); } else if (c >= 'A' && c <= 'Z') { result = (result << 5) | (c - 'A' + 1); } else if (c == '_') { result = (result << 5) | 27U; } } return result; } #define ID(NAME) getSparseIndex(#NAME) |