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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
#ifndef CCAN_CAST_IF_TYPE_H
#define CCAN_CAST_IF_TYPE_H
#if (__GNUC__ >= 3)
#define HAVE_TYPEOF 1
#define HAVE_BUILTIN_CHOOSE_EXPR 1
#define HAVE_BUILTIN_TYPES_COMPATIBLE_P 1
#endif
#if HAVE_TYPEOF && HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P
/**
* cast_if_type - only cast an expression if test matches a given type
* @desttype: the type to cast to
* @expr: the expression to cast
* @test: the expression to test
* @oktype: the type we allow
*
* This macro is used to create functions which allow multiple types.
* The result of this macro is used somewhere that a @desttype type is
* expected: if @expr was of type @oktype, it will be cast to
* @desttype type. As a result, if @expr is any type other than
* @oktype or @desttype, a compiler warning will be issued.
*
* This macro can be used in static initializers.
*
* This is merely useful for warnings: if the compiler does not
* support the primitives required for cast_if_type(), it becomes an
* unconditional cast, and the @test and @oktype argument is not used. In
* particular, this means that @oktype can be a type which uses
* the "typeof": it will not be evaluated if typeof is not supported.
*
* Example:
* // We can take either an unsigned long or a void *.
* void _set_some_value(void *val);
* #define set_some_value(e) \
* _set_some_value(cast_if_type(void *, (e), (e), unsigned long))
*/
#define cast_if_type(desttype, expr, test, oktype) \
__builtin_choose_expr(__builtin_types_compatible_p(typeof(1?(test):0), oktype), \
(desttype)(expr), (expr))
#else
#define cast_if_type(desttype, expr, test, oktype) ((desttype)(expr))
#endif
/**
* cast_if_any - only cast an expression if it is one of the three given types
* @desttype: the type to cast to
* @expr: the expression to cast
* @test: the expression to test
* @ok1: the first type we allow
* @ok2: the second type we allow
* @ok3: the third type we allow
*
* This is a convenient wrapper for multiple cast_if_type() calls. You can
* chain them inside each other (ie. use cast_if_any() for expr) if you need
* more than 3 arguments.
*
* Example:
* // We can take either a long, unsigned long, void * or a const void *.
* void _set_some_value(void *val);
* #define set_some_value(expr) \
* _set_some_value(cast_if_any(void *, (expr), (expr), \
* long, unsigned long, const void *))
*/
#define cast_if_any(desttype, expr, test, ok1, ok2, ok3) \
cast_if_type(desttype, \
cast_if_type(desttype, \
cast_if_type(desttype, (expr), (test), ok1), \
ok2), \
ok3)
/**
* typesafe_cb - cast a callback function if it matches the arg
* @rtype: the return type of the callback function
* @fn: the callback function to cast
* @arg: the (pointer) argument to hand to the callback function.
*
* If a callback function takes a single argument, this macro does
* appropriate casts to a function which takes a single void * argument if the
* callback provided matches the @arg (or a const or volatile version).
*
* It is assumed that @arg is of pointer type: usually @arg is passed
* or assigned to a void * elsewhere anyway.
*
* Example:
* void _register_callback(void (*fn)(void *arg), void *arg);
* #define register_callback(fn, arg) \
* _register_callback(typesafe_cb(void, (fn), (arg)), (arg))
*/
#define typesafe_cb(rtype, fn, arg) \
cast_if_type(rtype (*)(void *), (fn), (fn)(arg), rtype)
/**
* typesafe_cb_const - cast a const callback function if it matches the arg
* @rtype: the return type of the callback function
* @fn: the callback function to cast
* @arg: the (pointer) argument to hand to the callback function.
*
* If a callback function takes a single argument, this macro does appropriate
* casts to a function which takes a single const void * argument if the
* callback provided matches the @arg.
*
* It is assumed that @arg is of pointer type: usually @arg is passed
* or assigned to a void * elsewhere anyway.
*
* Example:
* void _register_callback(void (*fn)(const void *arg), const void *arg);
* #define register_callback(fn, arg) \
* _register_callback(typesafe_cb_const(void, (fn), (arg)), (arg))
*/
#define typesafe_cb_const(rtype, fn, arg) \
sizeof((fn)((const void *)0)), \
cast_if_type(rtype (*)(const void *), \
(fn), (fn)(arg), rtype (*)(typeof(arg)))
/**
* typesafe_cb_preargs - cast a callback function if it matches the arg
* @rtype: the return type of the callback function
* @fn: the callback function to cast
* @arg: the (pointer) argument to hand to the callback function.
*
* This is a version of typesafe_cb() for callbacks that take other arguments
* before the @arg.
*
* Example:
* void _register_callback(void (*fn)(int, void *arg), void *arg);
* #define register_callback(fn, arg) \
* _register_callback(typesafe_cb_preargs(void, (fn), (arg), int),\
* (arg))
*/
#define typesafe_cb_preargs(rtype, fn, arg, ...) \
cast_if_type(rtype (*)(__VA_ARGS__, void *), (fn), (fn), \
rtype (*)(__VA_ARGS__, typeof(arg)))
/**
* typesafe_cb_postargs - cast a callback function if it matches the arg
* @rtype: the return type of the callback function
* @fn: the callback function to cast
* @arg: the (pointer) argument to hand to the callback function.
*
* This is a version of typesafe_cb() for callbacks that take other arguments
* after the @arg.
*
* Example:
* void _register_callback(void (*fn)(void *arg, int), void *arg);
* #define register_callback(fn, arg) \
* _register_callback(typesafe_cb_postargs(void, (fn), (arg), int),\
* (arg))
*/
#define typesafe_cb_postargs(rtype, fn, arg, ...) \
cast_if_type(rtype (*)(void *, __VA_ARGS__), (fn), (fn), \
rtype (*)(typeof(arg), __VA_ARGS__))
/**
* typesafe_cb_cmp - cast a compare function if it matches the arg
* @rtype: the return type of the callback function
* @fn: the callback function to cast
* @arg: the (pointer) argument(s) to hand to the compare function.
*
* If a callback function takes two matching-type arguments, this macro does
* appropriate casts to a function which takes two const void * arguments if
* the callback provided takes two a const pointers to @arg.
*
* It is assumed that @arg is of pointer type: usually @arg is passed
* or assigned to a void * elsewhere anyway. Note also that the type
* arg points to must be defined.
*
* Example:
* void _my_qsort(void *base, size_t nmemb, size_t size,
* int (*cmp)(const void *, const void *));
* #define my_qsort(base, nmemb, cmpfn) \
* _my_qsort((base), (nmemb), sizeof(*(base)), \
* typesafe_cb_cmp(int, (cmpfn), (base)), (arg))
*/
#define typesafe_cb_cmp(rtype, cmpfn, arg) \
cast_if_type(rtype (*)(const void *, const void *), (cmpfn), \
rtype (*)(const typeof(*arg)*, const typeof(*arg)*))
#endif /* CCAN_CAST_IF_TYPE_H */
|