Ever wished, you had C enums as similar powerful as Java enums? cppviz aims in this direction.
For example, write in your C code
#include "cppviz.h" #define PLANET_DATA(_,__,___, T, A, E) \ T(_,__,___, int , char * , int ) \ A(_,__,___, id , name , radius ) \ /*----------------------------------------------*/ \ E(_,__,___, MERCURY , "Mercury" , 2439 ) \ E(_,__,___, VENUS , "Venus" , 6051 ) \ E(_,__,___, EARTH , "Earth" , 6378 ) ENUM(PLANET);
Then the ENUM macro at the end lets the preprocessor create the following source
typedef enum _e_PLANET { PLANET_MERCURY, PLANET_VENUS, PLANET_EARTH, } PLANET;
How many planets are there in the enum? Find out with
COUNT(PLANET);
which gives
(0 + 1 + 1 + 1);
which is ... ehm ... kind of right :-) Well, if you can count it, you can iterate through it!
FOREACH(PLANET, planet) { printf("%d\n", (int) planet); }
From this, the preprocessor will create
for (PLANET planet = (PLANET) 0; planet < (0 + 1 + 1 + 1); planet = (PLANET) (((int) planet) + 1)) { printf("%d\n", (int) planet); }
printing each planets ordinal. Nice, but nicer would be to have the attributes of each planet at hand, right?
To grab display name and radius, just add
ATTRIBUTE(PLANET, 2); /* for the "name" attribute */ ATTRIBUTE(PLANET, 3); /* for the "radius" attribute */
resulting in two arrays
char * PLANET_name[] = { "Mercury", "Venus", "Earth", }; int PLANET_radius[] = { 2439, 6051, 6378, };
Want to have the ENUM NAMES of each of the planets, too? Get them with
NAMES(PLANET);
and this will create the array
const char * PLANET_element_name[] = { "MERCURY", "VENUS", "EARTH", };
Finally, you can apply a planet-specific landing procedure with
SWITCH(PLANET, planet, landing_procedure(x, y));
which will turn into
switch (planet) { case PLANET_MERCURY: PLANET_MERCURY_landing_procedure(x, y); break; case PLANET_VENUS: PLANET_VENUS_landing_procedure(x, y); break; case PLANET_EARTH: PLANET_EARTH_landing_procedure(x, y); break; default: break; };
Well, the specific landing functions/macros you will have to write for yourself :-)
Finally, a translation for a complete example. First, the source code
/* Include the magick. */ #include "cppviz.h" /* and some other stuff */ #include <stdio.h> /* Create the data table for planets. The table name has to end with "_DATA", everything before "_DATA" will be the main name, here "PLANET". Sorry for the crude underscore parameters ... */ #define PLANET_DATA(_,__,___, T, A, E) \ T(_,__,___, int , char * , int ) \ A(_,__,___, id , name , radius ) \ /*----------------------------------------------*/ \ E(_,__,___, MERCURY , "Mercury" , 2439 ) \ E(_,__,___, VENUS , "Venus" , 6051 ) \ E(_,__,___, EARTH , "Earth" , 6378 ) /* Now, create the enum, simple as that! */ ENUM(PLANET); /* We want to access the planets attributes, name and radius. Simple as that! */ ATTRIBUTE(PLANET, 2); ATTRIBUTE(PLANET, 3); /* We also want the enum ELEMENT NAMES of all planets, simple as that! */ NAMES(PLANET); /* The landing procedures, one for each planet. Your job to fill them ... */ void PLANET_MERCURY_landing_procedure(int x, int y) { /* ... */ } void PLANET_VENUS_landing_procedure(int x, int y) { /* ... */ } void PLANET_EARTH_landing_procedure(int x, int y) { /* ... */ } /* Let the spaceship roll! */ int main() { /* Some totally relevant x, y coordinates. */ int x, y; /* Print stuff for each planet, simple as that! */ FOREACH(PLANET, planet) { printf("%s %s %d\n", PLANET_element_name[planet], PLANET_name[planet], PLANET_radius[planet]); } /* Perform the planet specific landing procedure. */ /* Yes, simple as that! */ PLANET planet; /* ... */ SWITCH(PLANET, planet, landing_procedure(x, y)); }
and the result is
typedef enum _e_PLANET { PLANET_MERCURY, PLANET_VENUS, PLANET_EARTH, } PLANET; char * PLANET_name[] = { "Mercury", "Venus", "Earth", }; int PLANET_radius[] = { 2439, 6051, 6378, }; const char * PLANET_element_name[] = { "MERCURY", "VENUS", "EARTH", }; void PLANET_MERCURY_landing_procedure(int x, int y) { } void PLANET_VENUS_landing_procedure(int x, int y) { } void PLANET_EARTH_landing_procedure(int x, int y) { } int main() { int x, y; for (PLANET planet = (PLANET) 0; (int) planet < (0 + 1 + 1 + 1); planet = (PLANET) (((int) planet) + 1)) { printf("%s %s %d\n", PLANET_element_name[planet], PLANET_name[planet], PLANET_radius[planet]); } PLANET planet; switch (planet) { case PLANET_MERCURY: PLANET_MERCURY_landing_procedure(x, y); break; case PLANET_VENUS: PLANET_VENUS_landing_procedure(x, y); break; case PLANET_EARTH: PLANET_EARTH_landing_procedure(x, y); break; default: break; }; }
You guessed it, some conventions are called for.
Thats about it, have fun!
Georg
GCC-tested!