| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2020-04-16 03:42:30 +00:00
										 |  |  |     Copyright (c) 2006-2020 Chung, Hyung-Hwan. All rights reserved. | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  |     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) | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | #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) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (comper(a, b, ctx) < 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		if (comper(b, c, ctx) < 0) return b; | 
					
						
							|  |  |  | 		return (comper(a, c, ctx) < 0)? c: a; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		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; | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	else | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | loop: | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	swaptype = get_swaptype(a, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	swap_cnt = 0; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (nmemb < 7) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (nmemb > 7) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		pl = (hawk_oob_t*)a; | 
					
						
							|  |  |  | 		pn = (hawk_oob_t*)a + (nmemb - 1) * size; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		if (nmemb > 40) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	for (;;) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		while (pb <= pc && (r = comper(pb, a, ctx)) <= 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 			if (r == 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				swap_cnt = 1; | 
					
						
							|  |  |  | 				swap(pa, pb, size); | 
					
						
							|  |  |  | 				pa += size; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			pb += size; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		while (pb <= pc && (r = comper(pc, a, ctx)) >= 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		{ | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 			if (r == 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (swap_cnt == 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		 /* switch to insertion sort */ | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		for (pm = (hawk_oob_t*)a + size; | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		     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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if ((r = pd - pc) > size) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		/* 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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | loop: | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	swaptype = get_swaptype(a, size); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	swap_cnt = 0; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (nmemb < 7) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (nmemb > 7) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		pl = (hawk_oob_t*)a; | 
					
						
							|  |  |  | 		pn = (hawk_oob_t*)a + (nmemb - 1) * size; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		if (nmemb > 40) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		{ | 
					
						
							|  |  |  | 			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; | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	for (;;) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		while (pb <= pc) | 
					
						
							|  |  |  | 		{ | 
					
						
							|  |  |  | 			if (comper(pb, a, ctx, &n) <= -1) return -1; | 
					
						
							|  |  |  | 			if (n > 0) break; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 			if (n == 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				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; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 			if (n == 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 			{ | 
					
						
							|  |  |  | 				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; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if (swap_cnt == 0) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		/* 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if ((r = pb - pa) > size) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		if (hawk_qsortx(a, r / size, size, comper, ctx) <= -1) return -1; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	if ((r = pd - pc) > size) | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	{ | 
					
						
							|  |  |  | 		/* 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
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  |  * 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 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	start = 0; end = nmemb - 2; | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	while (1) { | 
					
						
							|  |  |  | 		/* look for the larger value than pivot */ | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		while (start <= end && | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		       compar(REF(p,start), REF(p,nmemb-1), arg) <= 0) start++; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/* look for the less value than pivot. */ | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 		while (end > start && | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 		       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); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | /*
 | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  |  * 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 */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 	start = 0; end = n - 2; | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 	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) { | 
					
						
							| 
									
										
										
										
											2024-05-02 22:47:30 +09:00
										 |  |  | 			/* less values all on the left,
 | 
					
						
							| 
									
										
										
										
											2019-12-13 04:29:58 +00:00
										 |  |  | 			 * 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
 |