/*
 * An example of use of unions and function pointers 
 * to implement a "generic" array
 */
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #define N 4

typedef enum { NONE, CHAR, INT, STRING } type;

typedef union {
	char chr;
	int  itg;
	char *str;
} _data;

typedef struct {
 	type typ;
	_data data;
} datatype;

datatype to_datatype(type the_type, _data payload){
	datatype *res = malloc(sizeof(datatype));
	res->typ=the_type;
	res->data=payload;
	return *res;
}

datatype f1(datatype d){ 
	printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); 
	d.data.chr+=1;
	return d;
}

datatype f2(datatype d){ 
	printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); 
	d.data.itg*=2;
	return d;
}

datatype f3(datatype d){ 
	printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); 
	return to_datatype(INT,(_data)((int)strlen(d.data.str)));
}

datatype f0(datatype d){ 
	printf("%s %d %s\n", __FILE__, __LINE__, __FUNCTION__); 
	return d;
}

struct {
  type the_type;
	datatype (*fun)(datatype);
} table[N] = {
  { CHAR, f1 },
	{ INT,  f2 },
	{ STRING, f3 },
  { NONE, f0 },
};

datatype apply(datatype d){
	int i;
  for(i=0; i<N; i++) {
	 	if (table[i].the_type == d.typ)
			return (table[i].fun)(d);
	}
	return to_datatype(NONE, (_data)0);
}



int main(int argc, char **argv){
	datatype array[N];
	printf("%c, %d, %s\n", 'c', argc, argv[0]);
	array[0] = to_datatype(CHAR,(_data)'c');
	array[1] = to_datatype(INT, (_data)argc);
	array[2] = to_datatype(STRING, (_data)argv[0]);
	array[3] = to_datatype(NONE, (_data)0);
	printf("%c, %d, %s\n", array[0].data.chr, array[1].data.itg, array[2].data.str);
	array[0] = apply(array[0]);
	array[1] = apply(array[1]);
	array[2] = apply(array[2]);
	printf("%c, %d, %d\n", array[0].data.chr, array[1].data.itg, array[2].data.itg);
}
