shithub: scc

Download patch

ref: 428e86f306625a3192e03260a921a19c3109f57d
parent: bb99c8599bac91bd98e0f9bbe0c994e97f0956a1
author: Roberto E. Vargas Caballero <k0ga@shike2.com>
date: Thu Dec 7 20:14:36 EST 2017

[lib/c] Add qsort()

--- a/lib/c/src/Makefile
+++ b/lib/c/src/Makefile
@@ -2,7 +2,7 @@
 
 include ../../../config.mk
 
-OBJ = bsearch.o \
+OBJ = bsearch.o qsort.o \
       abs.o __abs.o labs.o __labs.o llabs.o __labs.o \
       perror.o strerror.o \
       printf.o fprintf.o vfprintf.o \
--- /dev/null
+++ b/lib/c/src/qsort.c
@@ -1,0 +1,155 @@
+
+#include <stdlib.h>
+#include <string.h>
+#undef qsort
+
+/*
+ * This implementation of qsort is based in the paper
+ * "Engineering a Sort Function", by Jon L.Bentley and M. Douglas McIlroy
+ */
+
+struct qsort {
+	size_t es;
+	int (*cmp)(const void *, const void *);
+	void (*swap)(char *i, char *j, size_t n);
+};
+
+static void
+swapb(char *i, char *j, size_t n)
+{
+	do {
+		char c = *i;
+		*i++ = *j;
+		*j++ = c;
+	} while (--n > 0);
+}
+
+static void
+swapw(char *i, char *j, size_t n)
+{
+	int w, *wi = (int *) i, *wj = (int *) j;
+
+	n /= sizeof(w);
+
+	do {
+		w = *wi;
+		*wi++ = *wj;
+		*wj++ = w;
+	} while (--n > 0);
+}
+
+static void
+swapl(char *i, char *j, size_t n)
+{
+	char *tmp[n];
+
+	memcpy(tmp, i, n);
+	memcpy(i, j, n);
+	memcpy(j, tmp, n);
+}
+
+static char *
+med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
+{
+	if (cmp(a, b) < 0) {
+		if (cmp(b, c) < 0)
+			return b;
+		return (cmp(a, c) < 0) ? c : a;
+	} else {
+		if (cmp(b, c) > 0)
+			return b;
+		return (cmp(a, c) > 0) ? c : a;
+	}
+}
+
+static char *
+pivot(char *v, size_t n, struct qsort *qs)
+{
+	char *p1, *pm, *pn; /* 1st, middle, nth */
+	int (*cmp)(const void *, const void *);
+	size_t s, es = qs->es;
+	
+
+	pm = v + n/2 * es;
+	if (n < 10)
+		return pm;
+
+	cmp = qs->cmp;
+	s = n/6 * es;
+	p1 = v + s;
+	pn = pm + 2*s;
+
+	if (n > 50) {
+		s = n/8 * es;
+		p1 = med3(p1, p1+s, p1 + 2*s, cmp);
+		pm = med3(pm-s, pm, pm+s, cmp);
+		pn = med3(pn-2*s, pn-s, pn, cmp);
+	}
+
+	return med3(p1, pm, pn, qs->cmp);
+}
+
+static void
+xqsort(char *a, size_t n, struct qsort *qs)
+{
+	size_t j, es = qs->es;
+	char *pi, *pj, *pn;
+
+tail_recursion:
+	if (n <= 1)
+		return;
+
+	pi = a;
+	pn = pj = a + n*es;
+
+	qs->swap(a, pivot(a, n, qs), es);
+	for (;;) {
+		do {
+			pi += es;
+		} while  (pi < pn && qs->cmp(pi, pn) < 0);
+
+		do {
+			pj -= es;
+		} while (pj > a && qs->cmp(pj, a) > 0);
+
+		if (pj < pi)
+			break;
+		qs->swap(pi, pj, es);
+	}
+	qs->swap(a, pj, es);
+
+	/*
+	 * We have to recurse over two subarrays. One of them can be
+	 * optimized with tail recursion. We select to recurse over
+	 * the bigger subarray, because it will allow us to apply a
+	 * better divide and conquer strategy.
+	 */
+	j = (pj - a) / es;
+	if (j >= n) {
+		xqsort(a, j, qs);
+		a += (j+1) * es;
+	} else {
+		xqsort(a + (j+1) * es, n-j-1, qs);
+		n = j;
+	}
+	goto tail_recursion;
+}
+
+void
+qsort(void *base, size_t nmemb, size_t size,
+      int (*f)(const void *, const void *))
+{
+	struct qsort qs;
+
+	qs.cmp = f;
+	qs.es = size;
+
+	if (size > 7 * sizeof(int))
+		qs.swap = swapl;
+	else if (size % sizeof(int) == 0)
+		qs.swap = swapw;
+	else
+		qs.swap = swapb;
+
+	xqsort(base, nmemb, &qs);
+}