]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: array - element-wise comparison via callback
authorPhil Carmody <phil@dovecot.fi>
Tue, 25 Nov 2014 01:43:02 +0000 (03:43 +0200)
committerPhil Carmody <phil@dovecot.fi>
Tue, 25 Nov 2014 01:43:02 +0000 (03:43 +0200)
2 are provided - with and without a context pointer.

Signed-off-by: Phil Carmody <phil@dovecot.fi>
src/lib/array.c
src/lib/array.h

index a74160ef100d7427df790b50e40cd75df5fb80dd..a00731b6317209a10c1c26caf305874b43aff037 100644 (file)
@@ -69,6 +69,59 @@ bool array_cmp_i(const struct array *array1, const struct array *array2)
        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;
index 189b7045f3a1ed4033d431455f8ff637021cca11..261fef0b8e4f2eceb07a7154f0aa3e12298a9c64 100644 (file)
 #  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) { .. } */
@@ -259,6 +264,35 @@ bool array_cmp_i(const struct array *array1,
 #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)