Захотелось сабжа. Недолго думая наваял несколько макросов.
Я их даже не тестировал и не компилировал примеры с ними, а V_SET даже и не
написан полностью (потому и приводить не буду - и так многабукаф), но, думаю, мысль основная ясна.
Подразумевается возможность ловли ошибок и просто событий в передаваемый кэллбак.
Остальное ясно из кода. Вопросов несколько:
1. Имеет ли право на существование такой код, или лучше переписать
всё на функциях (тип элемениов тупо void * и всё)?
2. Может комбинированный вариант (макросы типо DECLARE_FUNC_SET
(name,type), которые определяют функцию с нужными типами, но есть и
выигрыш в размере результирующего кода (за счёт использования функций)).
3. Ну и естественно - ваш вариант :).
================================
enum vec_event_e {
vec_event_SET = 0x01,
vec_event_GET = 0x02,
vec_event_INIT = 0x04,
vec_event_DESTROY = 0x08,
vec_event_OUT_OF_RANGE = 0x10,
vec_event_NOT_ENOUGH_MEMORY = 0x20,
vec_event_ALL = 0x3f,
};
enum grow_type_e { grow_type_ADD, grow_type_MUX };
#define DECLARE_VECTOR(name,type,null_elem,init_count) \
struct name##_s { \
type mas[(init_count)]={0}; \
int el_st_count = (init_count); \
type * values = NULL; \
type el_null = (null_elem); \
int el_last_idx = 0; \
int el_alloc = (init_count); \
int grow = 0; \
enum grow_type_e gr_type = 0; \
vec_event_e e_mask = 0; \
void (* log_f)(char * nm, \
vec_event_e ev, char * file, \
char * func, int line) = NULL; \
} name;
#define INIT_VECTOR(name, grow_type, grow_val, ev_mask, logf) \
do { \
name.values = name.mas; \
name.grow = (grow_val); \
name.gr_type = (grow_type); \
name.e_mask = (ev_mask); \
name.log_f = (logf); \
if(name.log_f && (name.e_mask & vec_event_INIT)){\
name.log_f(#name, vec_event_INIT, \
__FILE__, __func__, __LINE__); \
}\
}while
#define DESTROY_VECTOR(name) \
do { \
if(name.values != name.mas){\
free(name.values); \
name.values = NULL; \
} \
name.el_last_idx = 0; \
name.el_alloc = sizeof(name.mas)/sizeof(name.mas[0]);\
name.grow = 0; \
if(name.log_f && (name.e_mask & vec_event_DESTROY)){\
name.log_f(#name, vec_event_DESTROY, \
__FILE__, __func__, __LINE__); \
} \
name.e_mask = 0; \
name.log_f = NULL; \
}while
#define V_GET(name, pos) \
((name.el_last_idx>=(pos)) && ((pos)>0)) ? \
do{ \
if(name.log_f && (name.e_mask & vec_event_GET)){\
name.log_f(#name, vec_event_GET, \
__FILE__, __func__, __LINE__); \
} \
}while, name.values[pos] : \
do{ \
if(name.log_f && (name.e_mask & \
(vec_event_GET | vec_event_OUT_OF_RANGE))){\
name.log_f(#name, vec_event_GET | vec_event_OUT_OF_RANGE,\
__FILE__, __func__, __LINE__); \
} \
}while, name.el_null;