|
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 |
}
|