xref: /inferno-os/lib9/qsort.c (revision ad4c862fd80d3ad38a6464a9ea169a78354a77fc)
137da2899SCharles.Forsyth /*
237da2899SCharles.Forsyth  * qsort -- simple quicksort
337da2899SCharles.Forsyth  */
437da2899SCharles.Forsyth 
5*ad4c862fSforsyth #include "lib9.h"
637da2899SCharles.Forsyth typedef
737da2899SCharles.Forsyth struct
837da2899SCharles.Forsyth {
937da2899SCharles.Forsyth 	int	(*cmp)(void*, void*);
1037da2899SCharles.Forsyth 	void	(*swap)(char*, char*, long);
1137da2899SCharles.Forsyth 	long	es;
1237da2899SCharles.Forsyth } Sort;
1337da2899SCharles.Forsyth 
1437da2899SCharles.Forsyth static	void
swapb(char * i,char * j,long es)1537da2899SCharles.Forsyth swapb(char *i, char *j, long es)
1637da2899SCharles.Forsyth {
1737da2899SCharles.Forsyth 	char c;
1837da2899SCharles.Forsyth 
1937da2899SCharles.Forsyth 	do {
2037da2899SCharles.Forsyth 		c = *i;
2137da2899SCharles.Forsyth 		*i++ = *j;
2237da2899SCharles.Forsyth 		*j++ = c;
2337da2899SCharles.Forsyth 		es--;
2437da2899SCharles.Forsyth 	} while(es != 0);
2537da2899SCharles.Forsyth 
2637da2899SCharles.Forsyth }
2737da2899SCharles.Forsyth 
2837da2899SCharles.Forsyth static	void
swapi(char * ii,char * ij,long es)2937da2899SCharles.Forsyth swapi(char *ii, char *ij, long es)
3037da2899SCharles.Forsyth {
3137da2899SCharles.Forsyth 	long *i, *j, c;
3237da2899SCharles.Forsyth 
3337da2899SCharles.Forsyth 	i = (long*)ii;
3437da2899SCharles.Forsyth 	j = (long*)ij;
3537da2899SCharles.Forsyth 	do {
3637da2899SCharles.Forsyth 		c = *i;
3737da2899SCharles.Forsyth 		*i++ = *j;
3837da2899SCharles.Forsyth 		*j++ = c;
3937da2899SCharles.Forsyth 		es -= sizeof(long);
4037da2899SCharles.Forsyth 	} while(es != 0);
4137da2899SCharles.Forsyth }
4237da2899SCharles.Forsyth 
4337da2899SCharles.Forsyth static	char*
pivot(char * a,long n,Sort * p)4437da2899SCharles.Forsyth pivot(char *a, long n, Sort *p)
4537da2899SCharles.Forsyth {
4637da2899SCharles.Forsyth 	long j;
4737da2899SCharles.Forsyth 	char *pi, *pj, *pk;
4837da2899SCharles.Forsyth 
4937da2899SCharles.Forsyth 	j = n/6 * p->es;
5037da2899SCharles.Forsyth 	pi = a + j;	/* 1/6 */
5137da2899SCharles.Forsyth 	j += j;
5237da2899SCharles.Forsyth 	pj = pi + j;	/* 1/2 */
5337da2899SCharles.Forsyth 	pk = pj + j;	/* 5/6 */
5437da2899SCharles.Forsyth 	if(p->cmp(pi, pj) < 0) {
5537da2899SCharles.Forsyth 		if(p->cmp(pi, pk) < 0) {
5637da2899SCharles.Forsyth 			if(p->cmp(pj, pk) < 0)
5737da2899SCharles.Forsyth 				return pj;
5837da2899SCharles.Forsyth 			return pk;
5937da2899SCharles.Forsyth 		}
6037da2899SCharles.Forsyth 		return pi;
6137da2899SCharles.Forsyth 	}
6237da2899SCharles.Forsyth 	if(p->cmp(pj, pk) < 0) {
6337da2899SCharles.Forsyth 		if(p->cmp(pi, pk) < 0)
6437da2899SCharles.Forsyth 			return pi;
6537da2899SCharles.Forsyth 		return pk;
6637da2899SCharles.Forsyth 	}
6737da2899SCharles.Forsyth 	return pj;
6837da2899SCharles.Forsyth }
6937da2899SCharles.Forsyth 
7037da2899SCharles.Forsyth static	void
qsorts(char * a,long n,Sort * p)7137da2899SCharles.Forsyth qsorts(char *a, long n, Sort *p)
7237da2899SCharles.Forsyth {
7337da2899SCharles.Forsyth 	long j, es;
7437da2899SCharles.Forsyth 	char *pi, *pj, *pn;
7537da2899SCharles.Forsyth 
7637da2899SCharles.Forsyth 	es = p->es;
7737da2899SCharles.Forsyth 	while(n > 1) {
7837da2899SCharles.Forsyth 		if(n > 10) {
7937da2899SCharles.Forsyth 			pi = pivot(a, n, p);
8037da2899SCharles.Forsyth 		} else
8137da2899SCharles.Forsyth 			pi = a + (n>>1)*es;
8237da2899SCharles.Forsyth 
8337da2899SCharles.Forsyth 		p->swap(a, pi, es);
8437da2899SCharles.Forsyth 		pi = a;
8537da2899SCharles.Forsyth 		pn = a + n*es;
8637da2899SCharles.Forsyth 		pj = pn;
8737da2899SCharles.Forsyth 		for(;;) {
8837da2899SCharles.Forsyth 			do
8937da2899SCharles.Forsyth 				pi += es;
9037da2899SCharles.Forsyth 			while(pi < pn && p->cmp(pi, a) < 0);
9137da2899SCharles.Forsyth 			do
9237da2899SCharles.Forsyth 				pj -= es;
9337da2899SCharles.Forsyth 			while(pj > a && p->cmp(pj, a) > 0);
9437da2899SCharles.Forsyth 			if(pj < pi)
9537da2899SCharles.Forsyth 				break;
9637da2899SCharles.Forsyth 			p->swap(pi, pj, es);
9737da2899SCharles.Forsyth 		}
9837da2899SCharles.Forsyth 		p->swap(a, pj, es);
9937da2899SCharles.Forsyth 		j = (pj - a) / es;
10037da2899SCharles.Forsyth 
10137da2899SCharles.Forsyth 		n = n-j-1;
10237da2899SCharles.Forsyth 		if(j >= n) {
10337da2899SCharles.Forsyth 			qsorts(a, j, p);
10437da2899SCharles.Forsyth 			a += (j+1)*es;
10537da2899SCharles.Forsyth 		} else {
10637da2899SCharles.Forsyth 			qsorts(a + (j+1)*es, n, p);
10737da2899SCharles.Forsyth 			n = j;
10837da2899SCharles.Forsyth 		}
10937da2899SCharles.Forsyth 	}
11037da2899SCharles.Forsyth }
11137da2899SCharles.Forsyth 
11237da2899SCharles.Forsyth void
qsort(void * va,long n,long es,int (* cmp)(void *,void *))11337da2899SCharles.Forsyth qsort(void *va, long n, long es, int (*cmp)(void*, void*))
11437da2899SCharles.Forsyth {
11537da2899SCharles.Forsyth 	Sort s;
11637da2899SCharles.Forsyth 
11737da2899SCharles.Forsyth 	s.cmp = cmp;
11837da2899SCharles.Forsyth 	s.es = es;
11937da2899SCharles.Forsyth 	s.swap = swapi;
120*ad4c862fSforsyth 	if(((uintptr)va | es) % sizeof(long))
12137da2899SCharles.Forsyth 		s.swap = swapb;
12237da2899SCharles.Forsyth 	qsorts((char*)va, n, &s);
12337da2899SCharles.Forsyth }
124