dovecot-2.2: lib: array - element-wise comparison via callback

dovecot at dovecot.org dovecot at dovecot.org
Tue Nov 25 01:53:53 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/b8ac4e5a1002
changeset: 18111:b8ac4e5a1002
user:      Phil Carmody <phil at dovecot.fi>
date:      Tue Nov 25 03:43:02 2014 +0200
description:
lib: array - element-wise comparison via callback
2 are provided - with and without a context pointer.

Signed-off-by: Phil Carmody <phil at dovecot.fi>

diffstat:

 src/lib/array.c |  53 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lib/array.h |  34 ++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+), 0 deletions(-)

diffs (118 lines):

diff -r a45ee7e221b0 -r b8ac4e5a1002 src/lib/array.c
--- a/src/lib/array.c	Tue Nov 25 03:43:02 2014 +0200
+++ b/src/lib/array.c	Tue Nov 25 03:43:02 2014 +0200
@@ -69,6 +69,59 @@
 	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;
diff -r a45ee7e221b0 -r b8ac4e5a1002 src/lib/array.h
--- a/src/lib/array.h	Tue Nov 25 03:43:02 2014 +0200
+++ b/src/lib/array.h	Tue Nov 25 03:43:02 2014 +0200
@@ -47,10 +47,15 @@
 #  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 @@
 #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)


More information about the dovecot-cvs mailing list