From 574a14ec63c644ead300e6bcc7ce3e9cdf45720c Mon Sep 17 00:00:00 2001 From: Arnaud Legrand Date: Thu, 26 Apr 2012 00:03:38 +0200 Subject: [PATCH] Add a convenient dynar function to sort the dynar using the Dutch national flag technique. --- include/xbt/dynar.h | 2 ++ include/xbt/function_types.h | 1 + src/xbt/dynar.c | 48 ++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/include/xbt/dynar.h b/include/xbt/dynar.h index 382c643d0b..c86b868a23 100644 --- a/include/xbt/dynar.h +++ b/include/xbt/dynar.h @@ -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(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); diff --git a/include/xbt/function_types.h b/include/xbt/function_types.h index d140c97767..fc1b45883d 100644 --- a/include/xbt/function_types.h +++ b/include/xbt/function_types.h @@ -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 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 *); diff --git a/src/xbt/dynar.c b/src/xbt/dynar.c index 7e6f0152c6..02f7414962 100644 --- a/src/xbt/dynar.c +++ b/src/xbt/dynar.c @@ -720,6 +720,54 @@ XBT_INLINE void xbt_dynar_sort(xbt_dynar_t 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 -- 2.20.1