479 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			479 lines
		
	
	
		
			12 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*
 | |
|     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved.
 | |
| 
 | |
|     Redistribution and use in source and binary forms, with or without
 | |
|     modification, are permitted provided that the following conditions
 | |
|     are met:
 | |
|     1. Redistributions of source code must retain the above copyright
 | |
|        notice, this list of conditions and the following disclaimer.
 | |
|     2. Redistributions in binary form must reproduce the above copyright
 | |
|        notice, this list of conditions and the following disclaimer in the
 | |
|        documentation and/or other materials provided with the distribution.
 | |
| 
 | |
|     THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
 | |
|     IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 | |
|     OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 | |
|     IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
 | |
|     INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | |
|     NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 | |
|     DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 | |
|     THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | |
|     (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 | |
|     THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| /*-
 | |
|  * Copyright (c) 1992, 1993
 | |
|  *	The Regents of the University of California.  All rights reserved.
 | |
|  *
 | |
|  * Redistribution and use in source and binary forms, with or without
 | |
|  * modification, are permitted provided that the following conditions
 | |
|  * are met:
 | |
|  * 1. Redistributions of source code must retain the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer.
 | |
|  * 2. Redistributions in binary form must reproduce the above copyright
 | |
|  *    notice, this list of conditions and the following disclaimer in the
 | |
|  *    documentation and/or other materials provided with the distribution.
 | |
|  * 3. Neither the name of the University nor the names of its contributors
 | |
|  *    may be used to endorse or promote products derived from this software
 | |
|  *    without specific prior written permission.
 | |
|  *
 | |
|  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 | |
|  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | |
|  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | |
|  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 | |
|  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | |
|  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | |
|  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | |
|  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | |
|  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | |
|  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | |
|  * SUCH DAMAGE.
 | |
|  */
 | |
| 
 | |
| #include <hawk-utl.h>
 | |
| 
 | |
| #define qsort_min(a,b) (((a)<(b))? a: b)
 | |
| 
 | |
| /*
 | |
|  * Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
 | |
|  */
 | |
| #define swapcode(TYPE,parmi,parmj,n) do { \
 | |
| 	hawk_oow_t i = (n) / HAWK_SIZEOF (TYPE); \
 | |
| 	register TYPE *pi = (TYPE*)(parmi); \
 | |
| 	register TYPE *pj = (TYPE*)(parmj); \
 | |
| 	do { 						\
 | |
| 		register TYPE t = *pi;	\
 | |
| 		*pi++ = *pj;	\
 | |
| 		*pj++ = t;		\
 | |
| 	} while (--i > 0);	\
 | |
| } while(0)
 | |
| 
 | |
| 
 | |
| #define get_swaptype(a, elemsize) (((hawk_oob_t*)(a) - (hawk_oob_t*)0) % HAWK_SIZEOF(long) || elemsize % HAWK_SIZEOF(long)? 2 : elemsize == HAWK_SIZEOF(long)? 0 : 1)
 | |
| 
 | |
| #define swap(a, b, elemsize) do { \
 | |
| 	switch (swaptype) \
 | |
| 	{ \
 | |
| 		case 0: \
 | |
| 		{ \
 | |
| 			long t = *(long*)(a); \
 | |
| 			*(long*)(a) = *(long*)(b); \
 | |
| 			*(long*)(b) = t; \
 | |
| 			break; \
 | |
| 		} \
 | |
| 		case 1: \
 | |
| 			swapcode(long, a, b, elemsize); \
 | |
| 			break; \
 | |
| 		default: \
 | |
| 			swapcode(hawk_oob_t, a, b, elemsize); \
 | |
| 			break; \
 | |
| 	} \
 | |
| } while(0)
 | |
| 
 | |
| 
 | |
| #define vecswap(a,b,n) do {  \
 | |
| 	if ((n) > 0)  \
 | |
| 	{ \
 | |
| 		if (swaptype <= 1) swapcode(long, a, b, n); \
 | |
| 		else swapcode(hawk_oob_t, a, b, n);  \
 | |
| 	} \
 | |
| } while(0)
 | |
| 
 | |
| static HAWK_INLINE hawk_oob_t* med3 (hawk_oob_t* a, hawk_oob_t* b, hawk_oob_t* c, hawk_sort_comper_t comper, void* ctx)
 | |
| {
 | |
| 	if (comper(a, b, ctx) < 0)
 | |
| 	{
 | |
| 		if (comper(b, c, ctx) < 0) return b;
 | |
| 		return (comper(a, c, ctx) < 0)? c: a;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (comper(b, c, ctx) > 0) return b;
 | |
| 		return (comper(a, c, ctx) > 0)? c: a;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| static HAWK_INLINE hawk_oob_t* med3x (hawk_oob_t* a, hawk_oob_t* b, hawk_oob_t* c, hawk_sort_comperx_t comper, void* ctx)
 | |
| {
 | |
| 	int n;
 | |
| 
 | |
| 	if (comper(a, b, ctx, &n) <= -1) return HAWK_NULL;
 | |
| 	if (n < 0)
 | |
| 	{
 | |
| 		if (comper(b, c, ctx, &n) <= -1) return HAWK_NULL;
 | |
| 		if (n < 0) return b;
 | |
| 
 | |
| 		if (comper(a, c, ctx, &n) <= -1) return HAWK_NULL;
 | |
| 		return (n < 0)? c: a;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 		if (comper(b, c, ctx, &n) <= -1) return HAWK_NULL;
 | |
| 		if (n > 0) return b;
 | |
| 		if (comper(a, c, ctx, &n) <= -1) return HAWK_NULL;
 | |
| 		return (n > 0)? c: a;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| void hawk_qsort (void* base, hawk_oow_t nmemb, hawk_oow_t size, hawk_sort_comper_t comper, void* ctx)
 | |
| {
 | |
| 	hawk_oob_t* pa, * pb, * pc, * pd, * pl, * pm, * pn;
 | |
| 	int swaptype, swap_cnt;
 | |
| 	long r;
 | |
| 	hawk_oow_t d;
 | |
| 	register hawk_oob_t* a = (hawk_oob_t*)base;
 | |
| 
 | |
| loop:
 | |
| 	swaptype = get_swaptype(a, size);
 | |
| 
 | |
| 	swap_cnt = 0;
 | |
| 	if (nmemb < 7)
 | |
| 	{
 | |
| 		hawk_oob_t* end = (hawk_oob_t*)a + (nmemb * size);
 | |
| 		for (pm = (hawk_oob_t*)a + size; pm < end; pm += size)
 | |
| 		{
 | |
| 			for (pl = pm; pl > (hawk_oob_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size)
 | |
| 			{
 | |
| 				swap(pl, pl - size, size);
 | |
| 			}
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 	pm = (hawk_oob_t*)a + (nmemb / 2) * size;
 | |
| 	if (nmemb > 7)
 | |
| 	{
 | |
| 		pl = (hawk_oob_t*)a;
 | |
| 		pn = (hawk_oob_t*)a + (nmemb - 1) * size;
 | |
| 		if (nmemb > 40)
 | |
| 		{
 | |
| 			d = (nmemb / 8) * size;
 | |
| 			pl = med3(pl, pl + d, pl + 2 * d, comper, ctx);
 | |
| 			pm = med3(pm - d, pm, pm + d, comper, ctx);
 | |
| 			pn = med3(pn - 2 * d, pn - d, pn, comper, ctx);
 | |
| 		}
 | |
| 		pm = med3(pl, pm, pn, comper, ctx);
 | |
| 	}
 | |
| 	swap(a, pm, size);
 | |
| 	pa = pb = (hawk_oob_t*)a + size;
 | |
| 
 | |
| 	pc = pd = (hawk_oob_t*)a + (nmemb - 1) * size;
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		while (pb <= pc && (r = comper(pb, a, ctx)) <= 0)
 | |
| 		{
 | |
| 			if (r == 0)
 | |
| 			{
 | |
| 				swap_cnt = 1;
 | |
| 				swap(pa, pb, size);
 | |
| 				pa += size;
 | |
| 			}
 | |
| 			pb += size;
 | |
| 		}
 | |
| 		while (pb <= pc && (r = comper(pc, a, ctx)) >= 0)
 | |
| 		{
 | |
| 			if (r == 0)
 | |
| 			{
 | |
| 				swap_cnt = 1;
 | |
| 				swap(pc, pd, size);
 | |
| 				pd -= size;
 | |
| 			}
 | |
| 			pc -= size;
 | |
| 		}
 | |
| 		if (pb > pc) break;
 | |
| 		swap (pb, pc, size);
 | |
| 		swap_cnt = 1;
 | |
| 		pb += size;
 | |
| 		pc -= size;
 | |
| 	}
 | |
| 
 | |
| 	if (swap_cnt == 0)
 | |
| 	{
 | |
| 		 /* switch to insertion sort */
 | |
| 		for (pm = (hawk_oob_t*)a + size;
 | |
| 		     pm < (hawk_oob_t*)a + nmemb * size; pm += size)
 | |
| 		{
 | |
| 			for (pl = pm; pl > (hawk_oob_t*)a && comper(pl - size, pl, ctx) > 0; pl -= size)
 | |
| 			{
 | |
| 				swap(pl, pl - size, size);
 | |
| 			}
 | |
| 		}
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	pn = (hawk_oob_t*)a + nmemb * size;
 | |
| 	r = qsort_min(pa - (hawk_oob_t*)a, pb - pa);
 | |
| 	vecswap (a, pb - r, r);
 | |
| 	r = qsort_min (pd - pc, pn - pd - size);
 | |
| 	vecswap (pb, pn - r, r);
 | |
| 
 | |
| 	if ((r = pb - pa) > size) hawk_qsort(a, r / size, size, comper, ctx);
 | |
| 
 | |
| 	if ((r = pd - pc) > size)
 | |
| 	{
 | |
| 		/* Iterate rather than recurse to save stack space */
 | |
| 		a = pn - r;
 | |
| 		nmemb = r / size;
 | |
| 		goto loop;
 | |
| 	}
 | |
| /*	qsort(pn - r, r / size, size, comper);*/
 | |
| }
 | |
| 
 | |
| int hawk_qsortx (void* base, hawk_oow_t nmemb, hawk_oow_t size, hawk_sort_comperx_t comper, void* ctx)
 | |
| {
 | |
| 	hawk_oob_t* pa, * pb, * pc, * pd, * pl, * pm, * pn;
 | |
| 	int swaptype, swap_cnt;
 | |
| 	long r;
 | |
| 	int n;
 | |
| 	hawk_oow_t d;
 | |
| 	register hawk_oob_t* a = (hawk_oob_t*)base;
 | |
| 
 | |
| loop:
 | |
| 	swaptype = get_swaptype(a, size);
 | |
| 
 | |
| 	swap_cnt = 0;
 | |
| 	if (nmemb < 7)
 | |
| 	{
 | |
| 		hawk_oob_t* end = (hawk_oob_t*)a + (nmemb * size);
 | |
| 		for (pm = (hawk_oob_t*)a + size; pm < end; pm += size)
 | |
| 		{
 | |
| 			pl = pm;
 | |
| 			while (pl > (hawk_oob_t*)a)
 | |
| 			{
 | |
| 				hawk_oob_t* pl2 = pl - size;
 | |
| 				if (comper(pl2, pl, ctx, &n) <= -1) return -1;
 | |
| 				if (n <= 0) break;
 | |
| 				swap (pl, pl2, size);
 | |
| 				pl = pl2;
 | |
| 			}
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 	pm = (hawk_oob_t*)a + (nmemb / 2) * size;
 | |
| 	if (nmemb > 7)
 | |
| 	{
 | |
| 		pl = (hawk_oob_t*)a;
 | |
| 		pn = (hawk_oob_t*)a + (nmemb - 1) * size;
 | |
| 		if (nmemb > 40)
 | |
| 		{
 | |
| 			d = (nmemb / 8) * size;
 | |
| 			pl = med3x(pl, pl + d, pl + 2 * d, comper, ctx);
 | |
| 			if (!pl) return -1;
 | |
| 			pm = med3x(pm - d, pm, pm + d, comper, ctx);
 | |
| 			if (!pm) return -1;
 | |
| 			pn = med3x(pn - 2 * d, pn - d, pn, comper, ctx);
 | |
| 			if (!pn) return -1;
 | |
| 		}
 | |
| 		pm = med3x(pl, pm, pn, comper, ctx);
 | |
| 		if (!pm) return -1;
 | |
| 	}
 | |
| 	swap(a, pm, size);
 | |
| 	pa = pb = (hawk_oob_t*)a + size;
 | |
| 
 | |
| 	pc = pd = (hawk_oob_t*)a + (nmemb - 1) * size;
 | |
| 	for (;;)
 | |
| 	{
 | |
| 		while (pb <= pc)
 | |
| 		{
 | |
| 			if (comper(pb, a, ctx, &n) <= -1) return -1;
 | |
| 			if (n > 0) break;
 | |
| 
 | |
| 			if (n == 0)
 | |
| 			{
 | |
| 				swap_cnt = 1;
 | |
| 				swap(pa, pb, size);
 | |
| 				pa += size;
 | |
| 			}
 | |
| 			pb += size;
 | |
| 		}
 | |
| 		while (pb <= pc)
 | |
| 		{
 | |
| 			if (comper(pc, a, ctx, &n) <= -1) return -1;
 | |
| 			if (n < 0) break;
 | |
| 
 | |
| 			if (n == 0)
 | |
| 			{
 | |
| 				swap_cnt = 1;
 | |
| 				swap(pc, pd, size);
 | |
| 				pd -= size;
 | |
| 			}
 | |
| 			pc -= size;
 | |
| 		}
 | |
| 		if (pb > pc) break;
 | |
| 		swap (pb, pc, size);
 | |
| 		swap_cnt = 1;
 | |
| 		pb += size;
 | |
| 		pc -= size;
 | |
| 	}
 | |
| 
 | |
| 	if (swap_cnt == 0)
 | |
| 	{
 | |
| 		/* switch to insertion sort */
 | |
| 		hawk_oob_t* end = (hawk_oob_t*)a + (nmemb * size);
 | |
| 		for (pm = (hawk_oob_t*)a + size; pm < end; pm += size)
 | |
| 		{
 | |
| 			pl = pm;
 | |
| 			while (pl > (hawk_oob_t*)a)
 | |
| 			{
 | |
| 				if (comper(pl - size, pl, ctx, &n) <= -1) return -1;
 | |
| 				if (n <= 0) break;
 | |
| 				swap(pl, pl - size, size);
 | |
| 				pl = pl - size;
 | |
| 			}
 | |
| 		}
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	pn = (hawk_oob_t*)a + nmemb * size;
 | |
| 	r = qsort_min(pa - (hawk_oob_t*)a, pb - pa);
 | |
| 	vecswap (a, pb - r, r);
 | |
| 	r = qsort_min (pd - pc, pn - pd - size);
 | |
| 	vecswap (pb, pn - r, r);
 | |
| 
 | |
| 	if ((r = pb - pa) > size)
 | |
| 	{
 | |
| 		if (hawk_qsortx(a, r / size, size, comper, ctx) <= -1) return -1;
 | |
| 	}
 | |
| 
 | |
| 	if ((r = pd - pc) > size)
 | |
| 	{
 | |
| 		/* Iterate rather than recurse to save stack space */
 | |
| 		a = pn - r;
 | |
| 		nmemb = r / size;
 | |
| 		goto loop;
 | |
| 	}
 | |
| /*	qsortx(pn - r, r / size, size, comper);*/
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #if 0
 | |
| 
 | |
| /*
 | |
|  * Below is an example of a naive qsort implementation
 | |
|  */
 | |
| 
 | |
| #define swap(a,b,size) \
 | |
| 	do  { \
 | |
| 		hawk_oow_t i = 0; \
 | |
| 		hawk_oob_t* p1 = (a); \
 | |
| 		hawk_oob_t* p2 = (b); \
 | |
| 		for (i = 0; i < size; i++) { \
 | |
| 			hawk_oob_t t = *p1; \
 | |
| 			*p1 = *p2; \
 | |
| 			*p2 = t; \
 | |
| 			p1++; p2++; \
 | |
| 		} \
 | |
| 	} while (0)
 | |
| 
 | |
| #define REF(x,i) (&((x)[(i)*size]))
 | |
| 
 | |
| void hawk_qsort (void* base, hawk_oow_t nmemb, hawk_oow_t size, void* arg,
 | |
| 	int (*compar)(const void*, const void*, void*))
 | |
| {
 | |
| 	hawk_oow_t pivot, start, end;
 | |
| 	hawk_oob_t* p = (hawk_oob_t*)base;
 | |
| 
 | |
| 	if (nmemb <= 1) return;
 | |
| 	if (nmemb == 2) {
 | |
| 		if (compar(REF(p,0), REF(p,1), arg) > 0)
 | |
| 			swap (REF(p,0), REF(p,1), size);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	pivot = nmemb >> 1; /* choose the middle as the pivot index */
 | |
| 	swap (REF(p,pivot), REF(p,nmemb-1), size); /* swap the pivot with the last item */
 | |
| 
 | |
| 	start = 0; end = nmemb - 2;
 | |
| 
 | |
| 	while (1) {
 | |
| 		/* look for the larger value than pivot */
 | |
| 		while (start <= end &&
 | |
| 		       compar(REF(p,start), REF(p,nmemb-1), arg) <= 0) start++;
 | |
| 
 | |
| 		/* look for the less value than pivot. */
 | |
| 		while (end > start &&
 | |
| 		       compar(REF(p,end), REF(p,nmemb-1), arg) >= 0) end--;
 | |
| 
 | |
| 		if (start >= end) break; /* no more to swap */
 | |
| 		swap (REF(p,start), REF(p,end), size);
 | |
| 		start++; end--;
 | |
| 	}
 | |
| 
 | |
| 	swap (REF(p,nmemb-1), REF(p,start), size);
 | |
| 	pivot = start;  /* adjust the pivot index */
 | |
| 
 | |
| 	hawk_qsort (REF(p,0), pivot, size, arg, compar);
 | |
| 	hawk_qsort (REF(p,pivot+1), nmemb - pivot - 1, size, arg, compar);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * For easier understanding, see the following
 | |
|  */
 | |
| 
 | |
| #define swap(a, b) do { a ^= b; b ^= a; a ^= b; } while (0)
 | |
| 
 | |
| void qsort (int* x, size_t n)
 | |
| {
 | |
| 	size_t index, start, end;
 | |
| 	int pivot;
 | |
| 
 | |
| 	if (n <= 1) return;
 | |
| 	if (n == 2) {
 | |
| 		if (x[0] > x[1]) swap (x[0], x[1]);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	index = n / 2; /* choose the middle as the pivot index */
 | |
| 	pivot = x[index]; /* store the pivot value */
 | |
| 	swap (x[index], x[n - 1]); /* swap the pivot with the last item */
 | |
| 
 | |
| 	start = 0; end = n - 2;
 | |
| 	while (1) {
 | |
| 		/* look for the larger value than pivot */
 | |
| 		while (start <= end && x[start] <= pivot) start++;
 | |
| 
 | |
| 		/* look for the less value than pivot. */
 | |
| 		while (end > start && x[end] >= pivot) end--;
 | |
| 
 | |
| 		if (start >= end) {
 | |
| 			/* less values all on the left,
 | |
| 			 * larger values all on the right
 | |
| 			 */
 | |
| 			break;
 | |
| 		}
 | |
| 
 | |
| 		swap (x[start], x[end]);
 | |
| 		start++; end--;
 | |
| 	}
 | |
| 
 | |
| 	x[n - 1] = x[start]; /* restore the pivot value */
 | |
| 	x[start] = pivot;
 | |
| 	index = start;  /* adjust the pivot index */
 | |
| 
 | |
| 	qsort (x, index);
 | |
| 	qsort (&x[index + 1], n - index - 1);
 | |
| }
 | |
| 
 | |
| #endif
 |