Blame isl-0.16.1/isl_sort.c

Packit fb9d21
/*
Packit fb9d21
 * The code of this file was taken from http://jeffreystedfast.blogspot.be,
Packit fb9d21
 * where it was posted in 2011 by Jeffrey Stedfast under the MIT license.
Packit fb9d21
 * The MIT license text is as follows:
Packit fb9d21
 *
Packit fb9d21
 * Permission is hereby granted, free of charge, to any person obtaining a copy
Packit fb9d21
 * of this software and associated documentation files (the "Software"), to
Packit fb9d21
 * deal in the Software without restriction, including without limitation the
Packit fb9d21
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
Packit fb9d21
 * sell copies of the Software, and to permit persons to whom the Software is
Packit fb9d21
 * furnished to do so, subject to the following conditions:
Packit fb9d21
 *
Packit fb9d21
 * The above copyright notice and this permission notice shall be included in
Packit fb9d21
 * all copies or substantial portions of the Software.
Packit fb9d21
 *
Packit fb9d21
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
Packit fb9d21
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
Packit fb9d21
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
Packit fb9d21
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
Packit fb9d21
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
Packit fb9d21
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
Packit fb9d21
 * IN THE SOFTWARE.
Packit fb9d21
 */
Packit fb9d21
Packit fb9d21
#include <errno.h>
Packit fb9d21
#include <string.h>
Packit fb9d21
#include <stdlib.h>
Packit fb9d21
#include <isl_sort.h>
Packit fb9d21
Packit fb9d21
#define MID(lo, hi) (lo + ((hi - lo) >> 1))
Packit fb9d21
Packit fb9d21
/* The code here is an optimized merge sort. Starting from a generic merge sort
Packit fb9d21
 * the following optimizations were applied:
Packit fb9d21
 *
Packit fb9d21
 * o Batching of memcpy() calls: Instead of calling memcpy() to copy each and
Packit fb9d21
 *   every element into a temporary buffer, blocks of elements are copied
Packit fb9d21
 *   at a time.
Packit fb9d21
 *
Packit fb9d21
 * o To reduce the number of memcpy() calls further, copying leading
Packit fb9d21
 *   and trailing elements into our temporary buffer is avoided, in case it is
Packit fb9d21
 *   not necessary to merge them.
Packit fb9d21
 *
Packit fb9d21
 * A further optimization could be to specialize memcpy calls based on the
Packit fb9d21
 * size of the types we compare. For now, this code does not include the
Packit fb9d21
 * relevant optimization, as clang e.g. inlines a very efficient memcpy()
Packit fb9d21
 * implementation. It is not clear, that the specialized version as provided in
Packit fb9d21
 * the blog post, is really superior to the one that will be inlined by
Packit fb9d21
 * default. So we decided to keep the code simple until this optimization was
Packit fb9d21
 * proven to be beneficial.
Packit fb9d21
 */
Packit fb9d21
Packit fb9d21
static void
Packit fb9d21
msort (void *array, void *buf, size_t low, size_t high, size_t size,
Packit fb9d21
       int (* compare) (const void *, const void *, void *), void *arg)
Packit fb9d21
{
Packit fb9d21
    char *a1, *al, *am, *ah, *ls, *hs, *lo, *hi, *b;
Packit fb9d21
    size_t copied = 0;
Packit fb9d21
    size_t mid;
Packit fb9d21
Packit fb9d21
    mid = MID (low, high);
Packit fb9d21
Packit fb9d21
    if (mid + 1 < high)
Packit fb9d21
        msort (array, buf, mid + 1, high, size, compare, arg);
Packit fb9d21
Packit fb9d21
    if (mid > low)
Packit fb9d21
        msort (array, buf, low, mid, size, compare, arg);
Packit fb9d21
Packit fb9d21
    ah = ((char *) array) + ((high + 1) * size);
Packit fb9d21
    am = ((char *) array) + ((mid + 1) * size);
Packit fb9d21
    a1 = al = ((char *) array) + (low * size);
Packit fb9d21
Packit fb9d21
    b = (char *) buf;
Packit fb9d21
    lo = al;
Packit fb9d21
    hi = am;
Packit fb9d21
Packit fb9d21
    do {
Packit fb9d21
        ls = lo;
Packit fb9d21
        hs = hi;
Packit fb9d21
Packit fb9d21
        if (lo > al || hi > am) {
Packit fb9d21
            /* our last loop already compared lo & hi and found lo <= hi */
Packit fb9d21
            lo += size;
Packit fb9d21
        }
Packit fb9d21
Packit fb9d21
        while (lo < am && compare (lo, hi, arg) <= 0)
Packit fb9d21
            lo += size;
Packit fb9d21
Packit fb9d21
        if (lo < am) {
Packit fb9d21
            if (copied == 0) {
Packit fb9d21
                /* avoid copying the leading items */
Packit fb9d21
                a1 = lo;
Packit fb9d21
                ls = lo;
Packit fb9d21
            }
Packit fb9d21
Packit fb9d21
            /* our last compare tells us hi < lo */
Packit fb9d21
            hi += size;
Packit fb9d21
Packit fb9d21
            while (hi < ah && compare (hi, lo, arg) < 0)
Packit fb9d21
                hi += size;
Packit fb9d21
Packit fb9d21
            if (lo > ls) {
Packit fb9d21
                memcpy (b, ls, lo - ls);
Packit fb9d21
                copied += (lo - ls);
Packit fb9d21
                b += (lo - ls);
Packit fb9d21
            }
Packit fb9d21
Packit fb9d21
            memcpy (b, hs, hi - hs);
Packit fb9d21
            copied += (hi - hs);
Packit fb9d21
            b += (hi - hs);
Packit fb9d21
        } else if (copied) {
Packit fb9d21
            memcpy (b, ls, lo - ls);
Packit fb9d21
            copied += (lo - ls);
Packit fb9d21
            b += (lo - ls);
Packit fb9d21
Packit fb9d21
            /* copy everything we needed to re-order back into array */
Packit fb9d21
            memcpy (a1, buf, copied);
Packit fb9d21
            return;
Packit fb9d21
        } else {
Packit fb9d21
            /* everything already in order */
Packit fb9d21
            return;
Packit fb9d21
        }
Packit fb9d21
    } while (hi < ah);
Packit fb9d21
Packit fb9d21
    if (lo < am) {
Packit fb9d21
        memcpy (b, lo, am - lo);
Packit fb9d21
        copied += (am - lo);
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    memcpy (a1, buf, copied);
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
static int
Packit fb9d21
MergeSort (void *base, size_t nmemb, size_t size,
Packit fb9d21
           int (* compare) (const void *, const void *, void *), void *arg)
Packit fb9d21
{
Packit fb9d21
    void *tmp;
Packit fb9d21
Packit fb9d21
    if (nmemb < 2)
Packit fb9d21
        return 0;
Packit fb9d21
Packit fb9d21
    if (!(tmp = malloc (nmemb * size))) {
Packit fb9d21
        errno = ENOMEM;
Packit fb9d21
        return -1;
Packit fb9d21
    }
Packit fb9d21
Packit fb9d21
    msort (base, tmp, 0, nmemb - 1, size, compare, arg);
Packit fb9d21
Packit fb9d21
    free (tmp);
Packit fb9d21
Packit fb9d21
    return 0;
Packit fb9d21
}
Packit fb9d21
Packit fb9d21
int isl_sort(void *const pbase, size_t total_elems, size_t size,
Packit fb9d21
	int (*cmp)(const void *, const void *, void *arg), void *arg)
Packit fb9d21
{
Packit fb9d21
    return MergeSort (pbase, total_elems, size, cmp, arg);
Packit fb9d21
}