Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Add a convenient dynar function to sort the dynar using the Dutch national flag techn...
authorArnaud Legrand <arnaud.legrand@imag.fr>
Wed, 25 Apr 2012 22:03:38 +0000 (00:03 +0200)
committerArnaud Legrand <arnaud.legrand@imag.fr>
Wed, 25 Apr 2012 23:13:39 +0000 (01:13 +0200)
include/xbt/dynar.h
include/xbt/function_types.h
src/xbt/dynar.c

index 382c643..c86b868 100644 (file)
@@ -97,6 +97,8 @@ XBT_PUBLIC(unsigned int) xbt_dynar_search(xbt_dynar_t const dynar, void *elem);
 XBT_PUBLIC(int) xbt_dynar_member(xbt_dynar_t const dynar, void *elem);
 XBT_PUBLIC(void) xbt_dynar_sort(xbt_dynar_t const dynar,
                                 int_f_cpvoid_cpvoid_t compar_fn);
 XBT_PUBLIC(int) xbt_dynar_member(xbt_dynar_t const dynar, void *elem);
 XBT_PUBLIC(void) xbt_dynar_sort(xbt_dynar_t const dynar,
                                 int_f_cpvoid_cpvoid_t compar_fn);
+XBT_PUBLIC(void) xbt_dynar_three_way_partition(xbt_dynar_t const dynar,
+    int_f_pvoid_t color);
 XBT_PUBLIC(int) xbt_dynar_compare(xbt_dynar_t d1, xbt_dynar_t d2,
                                   int(*compar)(const void *, const void *));
 XBT_PUBLIC(void *) xbt_dynar_to_array (xbt_dynar_t dynar);
 XBT_PUBLIC(int) xbt_dynar_compare(xbt_dynar_t d1, xbt_dynar_t d2,
                                   int(*compar)(const void *, const void *));
 XBT_PUBLIC(void *) xbt_dynar_to_array (xbt_dynar_t dynar);
index d140c97..fc1b458 100644 (file)
@@ -21,6 +21,7 @@ typedef void *(*pvoid_f_pvoid_t) (void *);
 typedef void (*void_f_void_t) (void);
 
 typedef int (*int_f_void_t) (void);
 typedef void (*void_f_void_t) (void);
 
 typedef int (*int_f_void_t) (void);
+typedef int (*int_f_pvoid_t) (void*);
 
 typedef int (*int_f_pvoid_pvoid_t) (void *, void *);
 typedef int (*int_f_cpvoid_cpvoid_t) (const void *, const void *);
 
 typedef int (*int_f_pvoid_pvoid_t) (void *, void *);
 typedef int (*int_f_cpvoid_cpvoid_t) (const void *, const void *);
index 7e6f015..02f7414 100644 (file)
@@ -720,6 +720,54 @@ XBT_INLINE void xbt_dynar_sort(xbt_dynar_t dynar,
   _dynar_unlock(dynar);
 }
 
   _dynar_unlock(dynar);
 }
 
+/** @brief Sorts a dynar according to their color assuming elements can have only three colors.
+ * Since there are only three colors, it is linear and much faster than a classical sort.
+ * See for example http://en.wikipedia.org/wiki/Dutch_national_flag_problem
+ *
+ * \param dynar the dynar to sort
+ * \param color the color function of type (int (compar_fn*) (void*) (void*)). The return value of color is assumed to be 0, 1, or 2.
+ *
+ * At the end of the call, elements with color 0 are at the beginning of the dynar, elements with color 2 are at the end and elements with color 1 are in the middle.
+ *
+ * Remark: if the elements stored in the dynar are structures, the color
+ * function has to retrieve the field to sort first.
+ */
+XBT_PUBLIC(void) xbt_dynar_three_way_partition(xbt_dynar_t const dynar,
+                                               int_f_pvoid_t color)
+{
+  _dynar_lock(dynar);
+  unsigned long size = xbt_dynar_length(dynar);
+  void *data = dynar->data;
+  unsigned long int i;
+  unsigned long int p = -1;
+  unsigned long int q = size;
+  unsigned long elmsize = dynar->elmsize;
+  void *tmp = xbt_malloc(elmsize);
+
+#define swap(a,b) do {     \
+    memcpy(tmp,  a , elmsize);  \
+    memcpy( a ,  b , elmsize);  \
+    memcpy( b , tmp, elmsize);  \
+  } while(0)
+
+  for (i = 0; i < q;) {
+    void *datai = data + i*elmsize;
+    int colori = color(datai);
+
+    if(colori==0) {
+      void *datap = data + (++p)*elmsize;
+      swap(datai, datap);
+      ++i;
+    } else if (colori==2) {
+      void *dataq = data + (--q)*elmsize;
+      swap(datai, dataq);
+    } else {
+      ++i;
+    }
+  }
+  _dynar_unlock(dynar);
+}
+
 /** @brief Transform a dynar into a NULL terminated array
  *
  * \param dynar the dynar to transform
 /** @brief Transform a dynar into a NULL terminated array
  *
  * \param dynar the dynar to transform