}
#define array_append(array, data, count) \
- array_append_i(&(array)->arr + ARRAY_TYPE_CHECK(array, data), \
- data, count)
+ TYPE_CHECKS(void, ARRAY_TYPE_CHECK(array, data), \
+ array_append_i(&(array)->arr, data, count))
static inline void
array_append_array_i(struct array *dest_array, const struct array *src_array)
buffer_append_buf(dest_array->buffer, src_array->buffer, 0, SIZE_MAX);
}
#define array_append_array(dest_array, src_array) \
- array_append_array_i(&(dest_array)->arr + ARRAY_TYPES_CHECK(dest_array, src_array), \
- &(src_array)->arr)
+ TYPE_CHECKS(void, ARRAY_TYPES_CHECK(dest_array, src_array), \
+ array_append_array_i(&(dest_array)->arr, &(src_array)->arr))
static inline void
array_insert_i(struct array *array, unsigned int idx,
}
#define array_insert(array, idx, data, count) \
- array_insert_i(&(array)->arr + ARRAY_TYPE_CHECK(array, data), \
- idx, data, count)
+ TYPE_CHECKS(void, ARRAY_TYPE_CHECK(array, data), \
+ array_insert_i(&(array)->arr, idx, data, count))
static inline void
array_delete_i(struct array *array, unsigned int idx, unsigned int count)
void array_idx_set_i(struct array *array, unsigned int idx, const void *data);
#define array_idx_set(array, idx, data) \
- array_idx_set_i(&(array)->arr + ARRAY_TYPE_CHECK(array, data), \
- idx, data)
+ TYPE_CHECKS(void, ARRAY_TYPE_CHECK(array, data), \
+ array_idx_set_i(&(array)->arr, idx, data))
void array_idx_clear_i(struct array *array, unsigned int idx);
#define array_idx_clear(array, idx) \
array2->buffer = buffer;
array2->element_size = elsize;
}
-#define array_swap(array1, array2) \
- array_swap_i(&(array1)->arr + ARRAY_TYPES_CHECK(array1, array2), \
- &(array2)->arr)
+#define array_swap(array1, array2) \
+ TYPE_CHECKS(void, ARRAY_TYPES_CHECK(array1, array2), \
+ array_swap_i(&(array1)->arr, &(array2)->arr))
bool array_cmp_i(const struct array *array1,
const struct array *array2) ATTR_PURE;
bool array_equal_fn_i(const struct array *array1,
const struct array *array2,
int (*cmp)(const void*, const void *)) ATTR_PURE;
-#define array_equal_fn(array1, array2, cmp) \
- array_equal_fn_i(&(array1)->arr - \
- ARRAY_TYPES_CHECK(array1, array2), \
- &(array2)->arr - \
- CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array1)->v), \
- typeof(*(array2)->v))), \
- (int (*)(const void *, const void *))cmp)
+#define array_equal_fn(array1, array2, cmp) \
+ TYPE_CHECKS(bool, \
+ ARRAY_TYPES_CHECK(array1, array2) || \
+ CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array1)->v), \
+ typeof(*(array2)->v))), \
+ array_equal_fn_i(&(array1)->arr, &(array2)->arr, \
+ (int (*)(const void *, const void *))cmp))
bool array_equal_fn_ctx_i(const struct array *array1,
const struct array *array2,
int (*cmp)(const void*, const void *, const void *),
context can't be void* as ``const typeof(context)'' won't compile,
so ``const typeof(*context)*'' is required instead, and that requires a
complete type. */
-#define array_equal_fn_ctx(array1, array2, cmp, ctx) \
- array_equal_fn_ctx_i(&(array1)->arr - \
- ARRAY_TYPES_CHECK(array1, array2), \
- &(array2)->arr - \
- CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array1)->v), \
- typeof(*(array2)->v), \
- const typeof(*ctx)*)), \
- (int (*)(const void *, const void *, const void *))cmp, \
- ctx)
+#define array_equal_fn_ctx(array1, array2, cmp, ctx) \
+ TYPE_CHECKS(bool, \
+ ARRAY_TYPES_CHECK(array1, array2) || \
+ CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array1)->v), \
+ typeof(*(array2)->v), \
+ const typeof(*ctx)*)), \
+ array_equal_fn_ctx_i(&(array1)->arr, &(array2)->arr, \
+ (int (*)(const void *, const void *, const void *))cmp, ctx))
void array_reverse_i(struct array *array);
#define array_reverse(array) \
void array_sort_i(struct array *array, int (*cmp)(const void *, const void *));
#define array_sort(array, cmp) \
- array_sort_i(&(array)->arr - \
- CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array)->v), \
- typeof(*(array)->v))), \
- (int (*)(const void *, const void *))cmp)
+ TYPE_CHECKS(void, \
+ CALLBACK_TYPECHECK(cmp, int (*)(typeof(*(array)->v), \
+ typeof(*(array)->v))), \
+ array_sort_i(&(array)->arr, (int (*)(const void *, const void *))cmp))
void *array_bsearch_i(struct array *array, const void *key,
int (*cmp)(const void *, const void *));
#define array_bsearch(array, key, cmp) \
- ARRAY_TYPE_CAST_MODIFIABLE(array)array_bsearch_i(&(array)->arr - \
- CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
- typeof(*(array)->v))), \
- (const void *)key, (int (*)(const void *, const void *))cmp)
+ TYPE_CHECKS(void *, \
+ CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
+ typeof(*(array)->v))), \
+ ARRAY_TYPE_CAST_MODIFIABLE(array)array_bsearch_i(&(array)->arr, \
+ (const void *)key, (int (*)(const void *, const void *))cmp))
/* Returns pointer to first element for which cmp(key,elem)==0, or NULL */
const void *array_lsearch_i(const struct array *array, const void *key,
{
return (void *)array_lsearch_i(array, key, cmp);
}
-#define ARRAY_LSEARCH_CALL(modifiable, array, key, cmp) \
- array_lsearch##modifiable##i( \
- &(array)->arr - \
- CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
- typeof(*(array)->v))), \
- (const void *)key, \
- (int (*)(const void *, const void *))cmp)
+#define ARRAY_LSEARCH_CALL(modifiable, array, key, cmp) \
+ TYPE_CHECKS(void *, \
+ CALLBACK_TYPECHECK(cmp, int (*)(typeof(const typeof(*key) *), \
+ typeof(*(array)->v))), \
+ array_lsearch##modifiable##i( \
+ &(array)->arr, (const void *)key, \
+ (int (*)(const void *, const void *))cmp))
#define array_lsearch(array, key, cmp) \
ARRAY_TYPE_CAST_CONST(array)ARRAY_LSEARCH_CALL(_, array, key, cmp)
#define array_lsearch_modifiable(array, key, cmp) \
/* Create a non-modifiable buffer from given data. */
void buffer_create_from_const_data(buffer_t *buffer,
const void *data, size_t size);
-#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) > 401
-#define buffer_create_from_data(b,d,s) ({ \
- (void)COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)); \
- buffer_create_from_data((b), (d), (s)); })
-#define buffer_create_from_const_data(b,d,s) ({ \
- (void)COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)); \
- buffer_create_from_const_data((b), (d), (s)); })
-#endif
+#define buffer_create_from_data(b,d,s) \
+ TYPE_CHECKS(void, \
+ COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)), \
+ buffer_create_from_data((b), (d), (s)))
+#define buffer_create_from_const_data(b,d,s) \
+ TYPE_CHECKS(void, \
+ COMPILE_ERROR_IF_TRUE(__builtin_object_size((d),1) < ((s)>0?(s):1)), \
+ buffer_create_from_const_data((b), (d), (s)))
+
/* Creates a dynamically growing buffer. Whenever write would exceed the
current size it's grown. */
buffer_t *buffer_create_dynamic(pool_t pool, size_t init_size);
unsigned int initial_size,
hash_callback_t *hash_cb,
hash_cmp_callback_t *key_compare_cb);
-#if defined (__GNUC__) && !defined(__cplusplus)
-# define hash_table_create(table, pool, size, hash_cb, key_cmp_cb) \
- ({(void)COMPILE_ERROR_IF_TRUE( \
+#define hash_table_create(table, pool, size, hash_cb, key_cmp_cb) \
+ TYPE_CHECKS(void, \
+ COMPILE_ERROR_IF_TRUE( \
sizeof((*table)._key) != sizeof(void *) || \
- sizeof((*table)._value) != sizeof(void *)); \
- (void)COMPILE_ERROR_IF_TRUE( \
- !__builtin_types_compatible_p(typeof(&key_cmp_cb), \
- int (*)(typeof((*table)._key), typeof((*table)._key))) && \
- !__builtin_types_compatible_p(typeof(&key_cmp_cb), \
- int (*)(typeof((*table)._const_key), typeof((*table)._const_key)))); \
- (void)COMPILE_ERROR_IF_TRUE( \
+ sizeof((*table)._value) != sizeof(void *)) || \
+ COMPILE_ERROR_IF_TRUE( \
+ !__builtin_types_compatible_p(typeof(&key_cmp_cb), \
+ int (*)(typeof((*table)._key), typeof((*table)._key))) && \
+ !__builtin_types_compatible_p(typeof(&key_cmp_cb), \
+ int (*)(typeof((*table)._const_key), typeof((*table)._const_key)))) || \
+ COMPILE_ERROR_IF_TRUE( \
!__builtin_types_compatible_p(typeof(&hash_cb), \
unsigned int (*)(typeof((*table)._key))) && \
!__builtin_types_compatible_p(typeof(&hash_cb), \
- unsigned int (*)(typeof((*table)._const_key)))); \
+ unsigned int (*)(typeof((*table)._const_key)))), \
hash_table_create(&(*table)._table, pool, size, \
(hash_callback_t *)hash_cb, \
- (hash_cmp_callback_t *)key_cmp_cb);})
-#else
-# define hash_table_create(table, pool, size, hash_cb, key_cmp_cb) \
- hash_table_create(&(*table)._table, pool, size, \
- (hash_callback_t *)hash_cb, \
- (hash_cmp_callback_t *)key_cmp_cb)
-#endif
+ (hash_cmp_callback_t *)key_cmp_cb))
/* Create hash table where comparisons are done directly with the pointers. */
void hash_table_create_direct(struct hash_table **table_r, pool_t node_pool,
unsigned int initial_size);
-#if defined (__GNUC__) && !defined(__cplusplus)
-# define hash_table_create_direct(table, pool, size) \
- ({(void)COMPILE_ERROR_IF_TRUE( \
+#define hash_table_create_direct(table, pool, size) \
+ TYPE_CHECKS(void, \
+ COMPILE_ERROR_IF_TRUE( \
sizeof((*table)._key) != sizeof(void *) || \
- sizeof((*table)._value) != sizeof(void *)); \
- hash_table_create_direct(&(*table)._table, pool, size);})
-#else
-# define hash_table_create_direct(table, pool, size) \
- hash_table_create_direct(&(*table)._table, pool, size)
-#endif
+ sizeof((*table)._value) != sizeof(void *)), \
+ hash_table_create_direct(&(*table)._table, pool, size))
#define hash_table_is_created(table) \
((table)._table != NULL)
void *hash_table_lookup(const struct hash_table *table, const void *key) ATTR_PURE;
#define hash_table_lookup(table, key) \
- HASH_VALUE_CAST(table)hash_table_lookup((table)._table, \
- (const void *)((const char *)(key) + COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._key, (table)._const_key, key)))
+ TYPE_CHECKS(void *, \
+ COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._key, (table)._const_key, key), \
+ HASH_VALUE_CAST(table)hash_table_lookup((table)._table, (key)))
bool hash_table_lookup_full(const struct hash_table *table,
const void *lookup_key,
void **orig_key_r, void **value_r);
#ifndef __cplusplus
# define hash_table_lookup_full(table, lookup_key, orig_key_r, value_r) \
+ TYPE_CHECKS(bool, \
+ COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, lookup_key) || \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, orig_key_r) || \
+ COMPILE_ERROR_IF_TRUE(sizeof(*(orig_key_r)) != sizeof(void *)) || \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r) || \
+ COMPILE_ERROR_IF_TRUE(sizeof(*(value_r)) != sizeof(void *)), \
hash_table_lookup_full((table)._table, \
- (void *)((const char *)(lookup_key) + \
- COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, lookup_key)), \
- (void *)((orig_key_r) + \
- COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, orig_key_r) + \
- COMPILE_ERROR_IF_TRUE(sizeof(*(orig_key_r)) != sizeof(void *))), \
- (void *)((value_r) + \
- COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r) + \
- COMPILE_ERROR_IF_TRUE(sizeof(*(value_r)) != sizeof(void *))))
+ (lookup_key), (void *)(orig_key_r), (void *)(value_r)))
#else
/* C++ requires (void **) casting, but that's not possible with strict
aliasing, so .. we'll just disable the type checks */
If the key already exists, preserve the original key and update only the value.*/
void hash_table_update(struct hash_table *table, void *key, void *value);
#define hash_table_insert(table, key, value) \
- hash_table_insert((table)._table, \
- (void *)((char*)(key) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key)), \
- (void *)((char*)(value) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value)))
+ TYPE_CHECKS(void, \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key) || \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value), \
+ hash_table_insert((table)._table, (void *)(key), (void *)(value)))
#define hash_table_update(table, key, value) \
- hash_table_update((table)._table, \
- (void *)((char *)(key) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key)), \
- (void *)((char *)(value) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value)))
+ TYPE_CHECKS(void, \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._key, key) || \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._value, value), \
+ hash_table_update((table)._table, (void *)(key), (void *)(value)))
bool hash_table_try_remove(struct hash_table *table, const void *key);
#define hash_table_try_remove(table, key) \
- hash_table_try_remove((table)._table, \
- (const void *)((const char *)(key) + COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, key)))
+ TYPE_CHECKS(bool, \
+ COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE((table)._const_key, (table)._key, key), \
+ hash_table_try_remove((table)._table, (const void *)(key)))
#define hash_table_remove(table, key) \
STMT_START { \
if (unlikely(!hash_table_try_remove(table, key))) \
void **key_r, void **value_r);
#ifndef __cplusplus
# define hash_table_iterate(ctx, table, key_r, value_r) \
- hash_table_iterate(ctx, \
- (void *)((key_r) + \
- COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, key_r) + \
- COMPILE_ERROR_IF_TRUE(sizeof(*(key_r)) != sizeof(void *)) + \
- COMPILE_ERROR_IF_TRUE(sizeof(*(value_r)) != sizeof(void *))), \
- (void *)((value_r) + COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r)))
+ TYPE_CHECKS(bool, \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._keyp, key_r) || \
+ COMPILE_ERROR_IF_TRUE(sizeof(*(key_r)) != sizeof(void *)) || \
+ COMPILE_ERROR_IF_TRUE(sizeof(*(value_r)) != sizeof(void *)) || \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE((table)._valuep, value_r), \
+ hash_table_iterate(ctx, (void *)(key_r), (void *)(value_r)))
#else
/* C++ requires (void **) casting, but that's not possible with strict
aliasing, so .. we'll just disable the type checks */
COMPILE_ERROR_IF_TRUE( \
!__builtin_types_compatible_p(typeof(_a1), typeof(_b)) && \
!__builtin_types_compatible_p(typeof(_a2), typeof(_b)))
+# define TYPE_CHECKS(return_type, checks, func) \
+ (FALSE ? (return_type)(checks) : (func))
#else
# define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) 0
# define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) 0
+# define TYPE_CHECKS(return_type, checks, func) (func)
#endif
#if __GNUC__ > 2