Add qsort - add support for sorting data arrays
authorWolfgang Denk <wd@denx.de>
Sat, 12 Jun 2010 23:45:10 +0000 (01:45 +0200)
committerWolfgang Denk <wd@denx.de>
Sun, 19 Sep 2010 17:29:47 +0000 (19:29 +0200)
Code adapted from uClibc-0.9.30.3

Signed-off-by: Wolfgang Denk <wd@denx.de>
include/common.h
lib/Makefile
lib/qsort.c [new file with mode: 0644]

index 6a79ec2aad44ffb883cb0e31a5fadc2e2fff8d56..2f85d12db04a28dfef701a33bcc1edab196e3c7f 100644 (file)
@@ -631,6 +631,10 @@ static inline IPaddr_t getenv_IPaddr (char *var)
        return (string_to_ip(getenv(var)));
 }
 
+/* lib/qsort.c */
+void qsort(void *base, size_t nmemb, size_t size,
+          int(*compar)(const void *, const void *));
+
 /* lib/time.c */
 void   udelay        (unsigned long);
 
index c26536d0b312ccc56fa895809cd277e706b52cb3..2d969a3d77df063830a094175c9b61bbee1af000 100644 (file)
@@ -43,6 +43,7 @@ COBJS-$(CONFIG_LMB) += lmb.o
 COBJS-y += ldiv.o
 COBJS-$(CONFIG_MD5) += md5.o
 COBJS-y += net_utils.o
+COBJS-y += qsort.o
 COBJS-$(CONFIG_SHA1) += sha1.o
 COBJS-$(CONFIG_SHA256) += sha256.o
 COBJS-y += string.o
diff --git a/lib/qsort.c b/lib/qsort.c
new file mode 100644 (file)
index 0000000..bb47319
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Code adapted from uClibc-0.9.30.3
+ *
+ * It is therefore covered by the GNU LESSER GENERAL PUBLIC LICENSE
+ * Version 2.1, February 1999
+ *
+ * Wolfgang Denk <wd@denx.de>
+ */
+
+/* This code is derived from a public domain shell sort routine by
+ * Ray Gardner and found in Bob Stout's snippets collection.  The
+ * original code is included below in an #if 0/#endif block.
+ *
+ * I modified it to avoid the possibility of overflow in the wgap
+ * calculation, as well as to reduce the generated code size with
+ * bcc and gcc. */
+
+#include <linux/types.h>
+#if 0
+#include <assert.h>
+#else
+#define assert(arg)
+#endif
+
+void qsort(void  *base,
+           size_t nel,
+           size_t width,
+           int (*comp)(const void *, const void *))
+{
+       size_t wgap, i, j, k;
+       char tmp;
+
+       if ((nel > 1) && (width > 0)) {
+               assert(nel <= ((size_t)(-1)) / width); /* check for overflow */
+               wgap = 0;
+               do {
+                       wgap = 3 * wgap + 1;
+               } while (wgap < (nel-1)/3);
+               /* From the above, we know that either wgap == 1 < nel or */
+               /* ((wgap-1)/3 < (int) ((nel-1)/3) <= (nel-1)/3 ==> wgap <  nel. */
+               wgap *= width;                  /* So this can not overflow if wnel doesn't. */
+               nel *= width;                   /* Convert nel to 'wnel' */
+               do {
+                       i = wgap;
+                       do {
+                               j = i;
+                               do {
+                                       register char *a;
+                                       register char *b;
+
+                                       j -= wgap;
+                                       a = j + ((char *)base);
+                                       b = a + wgap;
+                                       if ((*comp)(a, b) <= 0) {
+                                               break;
+                                       }
+                                       k = width;
+                                       do {
+                                               tmp = *a;
+                                               *a++ = *b;
+                                               *b++ = tmp;
+                                       } while (--k);
+                               } while (j >= wgap);
+                               i += width;
+                       } while (i < nel);
+                       wgap = (wgap - width)/3;
+               } while (wgap);
+       }
+}