ucx_array_sort() uses qsort_r(), if available feature/array

Wed, 07 Aug 2019 21:14:58 +0200

author
Mike Becker <universe@uap-core.de>
date
Wed, 07 Aug 2019 21:14:58 +0200
branch
feature/array
changeset 345
6089eb30a51a
parent 344
320b962afaf9
child 346
1a9c112f4116

ucx_array_sort() uses qsort_r(), if available

src/array.c file | annotate | diff | comparison | revisions
src/ucx/array.h file | annotate | diff | comparison | revisions
     1.1 --- a/src/array.c	Wed Aug 07 20:45:21 2019 +0200
     1.2 +++ b/src/array.c	Wed Aug 07 21:14:58 2019 +0200
     1.3 @@ -26,10 +26,30 @@
     1.4   * POSSIBILITY OF SUCH DAMAGE.
     1.5   */
     1.6  
     1.7 +#define _GNU_SOURCE /* we want to use qsort_r(), if available */
     1.8 +
     1.9  #include "ucx/array.h"
    1.10  #include "ucx/utils.h"
    1.11  
    1.12  #include <string.h>
    1.13 +#include <stdlib.h>
    1.14 +
    1.15 +#ifndef UCX_ARRAY_DISABLE_QSORT
    1.16 +#if defined(__GLIBC__)
    1.17 +#if __GLIBC__ > 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ >= 8)
    1.18 +#define ucx_array_sort_impl qsort_r
    1.19 +#endif /* glibc version >= 2.8 */
    1.20 +#endif /* __GLIBC__ */
    1.21 +
    1.22 +#if defined(__APPLE__) || defined(__FreeBSD__)
    1.23 +#define ucx_array_sort_impl ucx_qsort_r
    1.24 +#define USE_UCX_QSORT_R
    1.25 +#endif /* __APLE__ or __FreeBSD__ */
    1.26 +#endif /* UCX_ARRAY_DISABLE_QSORT */
    1.27 +
    1.28 +#ifndef ucx_array_sort_impl
    1.29 +#define ucx_array_sort_impl ucx_mergesort
    1.30 +#endif
    1.31  
    1.32  UcxArray ucx_array_new(size_t capacity, size_t elemsize) {
    1.33      return ucx_array_new_a(capacity, elemsize, ucx_default_allocator());
    1.34 @@ -212,36 +232,39 @@
    1.35      return ucx_array_find(array, elem, cmpfnc, data) != array.size;
    1.36  }
    1.37  
    1.38 -static void ucx_array_merge(UcxArray *array, cmp_func cmpfnc, void *data,
    1.39 +static void ucx_mergesort_merge(void *arrdata,size_t elemsize,
    1.40 +        cmp_func cmpfnc, void *data,
    1.41          size_t start, size_t mid, size_t end) { 
    1.42      
    1.43 +    char* array = arrdata;
    1.44 +    
    1.45      size_t rightstart = mid + 1; 
    1.46    
    1.47 -    if (cmpfnc(ucx_array_at(*array, mid),
    1.48 -            ucx_array_at(*array, rightstart), data) <= 0) {
    1.49 +    if (cmpfnc(array + mid*elemsize,
    1.50 +            array + rightstart*elemsize, data) <= 0) {
    1.51          /* already sorted */
    1.52          return;
    1.53      }
    1.54    
    1.55      /* we need memory for one element */
    1.56 -    void *value = malloc(array->elemsize);
    1.57 +    void *value = malloc(elemsize);
    1.58      
    1.59      while (start <= mid && rightstart <= end) { 
    1.60 -        if (cmpfnc(ucx_array_at(*array, start),
    1.61 -                ucx_array_at(*array, rightstart), data) <= 0) { 
    1.62 +        if (cmpfnc(array + start*elemsize,
    1.63 +                array + rightstart*elemsize, data) <= 0) { 
    1.64              start++; 
    1.65          } else {
    1.66              /* save the value from the right */
    1.67 -            memcpy(value, ucx_array_at(*array, rightstart), array->elemsize);
    1.68 +            memcpy(value, array + rightstart*elemsize, elemsize);
    1.69                          
    1.70              /* shift all left elements one element to the right */
    1.71              size_t shiftcount = rightstart-start;
    1.72 -            void *startptr = ucx_array_at(*array, start);
    1.73 -            void *dest = ucx_array_at(*array, start+1);
    1.74 -            memmove(dest, startptr, shiftcount*array->elemsize);
    1.75 +            void *startptr = array + start*elemsize;
    1.76 +            void *dest = array + (start+1)*elemsize;
    1.77 +            memmove(dest, startptr, shiftcount*elemsize);
    1.78              
    1.79              /* bring the first value from the right to the left */
    1.80 -            memcpy(startptr, value, array->elemsize);
    1.81 +            memcpy(startptr, value, elemsize);
    1.82    
    1.83              start++; 
    1.84              mid++; 
    1.85 @@ -253,19 +276,45 @@
    1.86      free(value);
    1.87  } 
    1.88    
    1.89 -static void ucx_array_mergesort(UcxArray *array, cmp_func cmpfnc, void *data,
    1.90 -        size_t l, size_t r) { 
    1.91 +static void ucx_mergesort_impl(void *arrdata, size_t elemsize,
    1.92 +        cmp_func cmpfnc, void *data, size_t l, size_t r) { 
    1.93      if (l < r) {
    1.94          size_t m = l + (r - l) / 2; 
    1.95    
    1.96 -        ucx_array_mergesort(array, cmpfnc, data, l, m); 
    1.97 -        ucx_array_mergesort(array, cmpfnc, data, m + 1, r); 
    1.98 -        ucx_array_merge(array, cmpfnc, data, l, m, r);
    1.99 +        ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, l, m); 
   1.100 +        ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, m + 1, r); 
   1.101 +        ucx_mergesort_merge(arrdata, elemsize, cmpfnc, data, l, m, r);
   1.102      } 
   1.103  }
   1.104  
   1.105 -void ucx_array_sort(UcxArray array, cmp_func cmpfnc, void *data) {   
   1.106 -    ucx_array_mergesort(&array, cmpfnc, data, 0, array.size-1);
   1.107 +static void ucx_mergesort(void *arrdata, size_t count, size_t elemsize,
   1.108 +        cmp_func cmpfnc, void *data) {
   1.109 +    
   1.110 +    ucx_mergesort_impl(arrdata, elemsize, cmpfnc, data, 0, count-1);
   1.111 +}
   1.112 +
   1.113 +#ifdef USE_UCX_QSORT_R
   1.114 +struct cmpfnc_swapargs_info {
   1.115 +    cmp_func func;
   1.116 +    void *data;
   1.117 +};
   1.118 +
   1.119 +static int cmp_func_swap_args(void *data, const void *x, const void *y) {
   1.120 +    cmpfnc_swapargs_info* info = data;
   1.121 +    return info->func(x, y, info->data);
   1.122 +}
   1.123 +
   1.124 +static void ucx_qsort_r(void *array, size_t count, size_t elemsize,
   1.125 +		     cmp_func cmpfnc, void *data) {
   1.126 +    struct cmpfnc_swapargs_info info;
   1.127 +    info.func = cmpfnc;
   1.128 +    info.data = data;
   1.129 +    qsort_r(array, count, elemsize, &info, cmp_func_swap_args);
   1.130 +}
   1.131 +#endif /* USE_UCX_QSORT_R */
   1.132 +
   1.133 +void ucx_array_sort(UcxArray array, cmp_func cmpfnc, void *data) {
   1.134 +    ucx_array_sort_impl(array.data, array.size, array.elemsize, cmpfnc, data);
   1.135  }
   1.136  
   1.137  void ucx_array_remove(UcxArray *array, size_t index) {
     2.1 --- a/src/ucx/array.h	Wed Aug 07 20:45:21 2019 +0200
     2.2 +++ b/src/ucx/array.h	Wed Aug 07 21:14:58 2019 +0200
     2.3 @@ -234,8 +234,12 @@
     2.4  /**
     2.5   * Sorts a UcxArray with the best available sort algorithm.
     2.6   * 
     2.7 - * A merge sort algorithm is used, which is guaranteed to use no more additional
     2.8 - * memory than for exactly one element.
     2.9 + * The qsort_r() function is used, if available (glibc, FreeBSD or MacOS).
    2.10 + * The order of arguments is automatically adjusted for the FreeBSD and MacOS
    2.11 + * version of qsort_r().
    2.12 + * 
    2.13 + * If qsort_r() is not available, a merge sort algorithm is used, which is
    2.14 + * guaranteed to use no more additional memory than for exactly one element.
    2.15   * 
    2.16   * @param array the array to sort
    2.17   * @param cmpfnc the function that shall be used to compare the element data

mercurial