return buffer_cmp(array1->buffer, array2->buffer);
}
+bool array_equal_fn_i(const struct array *array1, const struct array *array2,
+ int (*cmp)(const void *, const void*))
+{
+ unsigned int count1, count2, i, size;
+
+ if (!array_is_created_i(array1) || array1->buffer->used == 0)
+ return !array_is_created_i(array2) || array2->buffer->used == 0;
+
+ if (!array_is_created_i(array2))
+ return FALSE;
+
+ count1 = array_count_i(array1); count2 = array_count_i(array2);
+ if (count1 != count2)
+ return FALSE;
+
+ size = array1->element_size;
+ i_assert(size == array2->element_size);
+
+ for (i = 0; i < count1; i++) {
+ if (cmp(CONST_PTR_OFFSET(array1->buffer->data, i * size),
+ CONST_PTR_OFFSET(array2->buffer->data, i * size)) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool array_equal_fn_ctx_i(const struct array *array1, const struct array *array2,
+ int (*cmp)(const void *, const void *, const void *),
+ const void *context)
+{
+ unsigned int count1, count2, i, size;
+
+ if (!array_is_created_i(array1) || array1->buffer->used == 0)
+ return !array_is_created_i(array2) || array2->buffer->used == 0;
+
+ if (!array_is_created_i(array2))
+ return FALSE;
+
+ count1 = array_count_i(array1); count2 = array_count_i(array2);
+ if (count1 != count2)
+ return FALSE;
+
+ size = array1->element_size;
+ i_assert(size == array2->element_size);
+
+ for (i = 0; i < count1; i++) {
+ if (cmp(CONST_PTR_OFFSET(array1->buffer->data, i * size),
+ CONST_PTR_OFFSET(array2->buffer->data, i * size), context) != 0)
+ return FALSE;
+ }
+ return TRUE;
+}
+
void array_reverse_i(struct array *array)
{
const size_t element_size = array->element_size;
# define ARRAY_TYPE_CHECK(array, data) \
COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
**(array)->v_modifiable, *(data))
+# define ARRAY_TYPES_CHECK(array1, array2) \
+ COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE( \
+ **(array1)->v_modifiable, **(array2)->v_modifiable)
+
#else
# define ARRAY_TYPE_CAST_CONST(array)
# define ARRAY_TYPE_CAST_MODIFIABLE(array)
# define ARRAY_TYPE_CHECK(array, data) 0
+# define ARRAY_TYPES_CHECK(array1, array2) 0
#endif
/* usage: struct foo *foo; array_foreach(foo_arr, foo) { .. } */
#define array_cmp(array1, array2) \
array_cmp_i(&(array1)->arr, &(array2)->arr)
+/* Test equality via a comparator */
+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)
+bool array_equal_fn_ctx_i(const struct array *array1,
+ const struct array *array2,
+ int (*cmp)(const void*, const void *, const void *),
+ const void *context) ATTR_PURE;
+/* Same, but with a context pointer.
+ 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)
+
void array_reverse_i(struct array *array);
#define array_reverse(array) \
array_reverse_i(&(array)->arr)