array: Add array_sort function
[strongswan.git] / src / libstrongswan / collections / array.c
index d0df23a..f6f9cf4 100644 (file)
@@ -1,4 +1,7 @@
 /*
+ * Copyright (C) 2014 Tobias Brunner
+ * Hochschule fuer Technik Rapperswil
+ *
  * Copyright (C) 2013 Martin Willi
  * Copyright (C) 2013 revosec AG
  *
@@ -13,6 +16,9 @@
  * for more details.
  */
 
+#define _GNU_SOURCE /* for qsort_r() */
+#include <stdlib.h>
+
 #include "array.h"
 
 /**
@@ -365,6 +371,54 @@ bool array_remove(array_t *array, int idx, void *data)
        return TRUE;
 }
 
+typedef struct {
+       /** the array */
+       array_t *array;
+       /** comparison function */
+       int (*cmp)(const void*,const void*,void*);
+       /** optional user arg */
+       void *arg;
+} sort_data_t;
+
+#ifdef HAVE_QSORT_R_GNU
+static int compare_elements(const void *a, const void *b, void *arg)
+#else /* HAVE_QSORT_R_BSD */
+static int compare_elements(void *arg, const void *a, const void *b)
+#endif
+{
+       sort_data_t *data = (sort_data_t*)arg;
+
+       if (data->array->esize)
+       {
+               return data->cmp(a, b, data->arg);
+       }
+       return data->cmp(*(void**)a, *(void**)b, data->arg);
+}
+
+void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*),
+                               void *user)
+{
+       if (array)
+       {
+               sort_data_t data = {
+                       .array = array,
+                       .cmp = cmp,
+                       .arg = user,
+               };
+               void *start;
+
+               start = array->data + get_size(array, array->head);
+
+#ifdef HAVE_QSORT_R_GNU
+               qsort_r(start, array->count, get_size(array, 1), compare_elements,
+                               &data);
+#else /* HAVE_QSORT_R_BSD */
+               qsort_r(start, array->count, get_size(array, 1), &data,
+                               compare_elements);
+#endif
+       }
+}
+
 void array_invoke(array_t *array, array_callback_t cb, void *user)
 {
        if (array)