Add qsort_r() implementation to the C library.

NOTE: This replaces qsort.c with the FreeBSD version. While
      the patch changes the source, it should not alter the
      implementation that should use the exact same algorithm.
This commit is contained in:
David 'Digit' Turner 2009-12-02 17:38:41 -08:00
parent e1e684920f
commit 754c178ae5
4 changed files with 76 additions and 37 deletions

View file

@ -154,6 +154,7 @@ libc_common_src_files := \
stdlib/nrand48.c \
stdlib/putenv.c \
stdlib/qsort.c \
stdlib/qsort_r.c \
stdlib/seed48.c \
stdlib/setenv.c \
stdlib/setjmperr.c \

View file

@ -101,6 +101,7 @@ extern void * bsearch(const void *key, const void *base0,
int (*compar)(const void *, const void *));
extern void qsort(void *, size_t, size_t, int (*)(const void *, const void *));
extern void qsort_r(void *a, size_t n, size_t es, void *thunk, int (*)(void *, const void *, const void *));
extern long jrand48(unsigned short *);
extern long mrand48(void);

View file

@ -1,4 +1,3 @@
/* $OpenBSD: qsort.c,v 1.10 2005/08/08 08:05:37 espie Exp $ */
/*-
* Copyright (c) 1992, 1993
* The Regents of the University of California. All rights reserved.
@ -11,7 +10,7 @@
* 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
* 4. 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.
*
@ -28,11 +27,16 @@
* SUCH DAMAGE.
*/
#include <sys/types.h>
#include <sys/cdefs.h>
#include <stdlib.h>
static __inline char *med3(char *, char *, char *, int (*)(const void *, const void *));
static __inline void swapfunc(char *, char *, int, int);
#ifdef I_AM_QSORT_R
typedef int cmp_t(void *, const void *, const void *);
#else
typedef int cmp_t(const void *, const void *);
#endif
static inline char *med3(char *, char *, char *, cmp_t *, void *);
static inline void swapfunc(char *, char *, int, int);
#define min(a, b) (a) < (b) ? a : b
@ -41,10 +45,10 @@ static __inline void swapfunc(char *, char *, int, int);
*/
#define swapcode(TYPE, parmi, parmj, n) { \
long i = (n) / sizeof (TYPE); \
TYPE *pi = (TYPE *) (parmi); \
TYPE *pj = (TYPE *) (parmj); \
TYPE *pi = (TYPE *) (parmi); \
TYPE *pj = (TYPE *) (parmj); \
do { \
TYPE t = *pi; \
TYPE t = *pi; \
*pi++ = *pj; \
*pj++ = t; \
} while (--i > 0); \
@ -53,10 +57,12 @@ static __inline void swapfunc(char *, char *, int, int);
#define SWAPINIT(a, es) swaptype = ((char *)a - (char *)0) % sizeof(long) || \
es % sizeof(long) ? 2 : es == sizeof(long)? 0 : 1;
static __inline void
swapfunc(char *a, char *b, int n, int swaptype)
static inline void
swapfunc(a, b, n, swaptype)
char *a, *b;
int n, swaptype;
{
if (swaptype <= 1)
if(swaptype <= 1)
swapcode(long, a, b, n)
else
swapcode(char, a, b, n)
@ -72,57 +78,75 @@ swapfunc(char *a, char *b, int n, int swaptype)
#define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
static __inline char *
med3(char *a, char *b, char *c, int (*cmp)(const void *, const void *))
#ifdef I_AM_QSORT_R
#define CMP(t, x, y) (cmp((t), (x), (y)))
#else
#define CMP(t, x, y) (cmp((x), (y)))
#endif
static inline char *
med3(char *a, char *b, char *c, cmp_t *cmp, void *thunk
#ifndef I_AM_QSORT_R
__unused
#endif
)
{
return cmp(a, b) < 0 ?
(cmp(b, c) < 0 ? b : (cmp(a, c) < 0 ? c : a ))
:(cmp(b, c) > 0 ? b : (cmp(a, c) < 0 ? a : c ));
return CMP(thunk, a, b) < 0 ?
(CMP(thunk, b, c) < 0 ? b : (CMP(thunk, a, c) < 0 ? c : a ))
:(CMP(thunk, b, c) > 0 ? b : (CMP(thunk, a, c) < 0 ? a : c ));
}
#ifdef I_AM_QSORT_R
void
qsort(void *aa, size_t n, size_t es, int (*cmp)(const void *, const void *))
qsort_r(void *a, size_t n, size_t es, void *thunk, cmp_t *cmp)
#else
#define thunk NULL
void
qsort(void *a, size_t n, size_t es, cmp_t *cmp)
#endif
{
char *pa, *pb, *pc, *pd, *pl, *pm, *pn;
int d, r, swaptype, swap_cnt;
char *a = aa;
size_t d, r;
int cmp_result;
int swaptype, swap_cnt;
loop: SWAPINIT(a, es);
swap_cnt = 0;
if (n < 7) {
for (pm = (char *)a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
pm = (char *)a + (n / 2) * es;
if (n > 7) {
pl = (char *)a;
pl = a;
pn = (char *)a + (n - 1) * es;
if (n > 40) {
d = (n / 8) * es;
pl = med3(pl, pl + d, pl + 2 * d, cmp);
pm = med3(pm - d, pm, pm + d, cmp);
pn = med3(pn - 2 * d, pn - d, pn, cmp);
pl = med3(pl, pl + d, pl + 2 * d, cmp, thunk);
pm = med3(pm - d, pm, pm + d, cmp, thunk);
pn = med3(pn - 2 * d, pn - d, pn, cmp, thunk);
}
pm = med3(pl, pm, pn, cmp);
pm = med3(pl, pm, pn, cmp, thunk);
}
swap(a, pm);
pa = pb = (char *)a + es;
pc = pd = (char *)a + (n - 1) * es;
for (;;) {
while (pb <= pc && (r = cmp(pb, a)) <= 0) {
if (r == 0) {
while (pb <= pc && (cmp_result = CMP(thunk, pb, a)) <= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swap(pa, pb);
pa += es;
}
}
pb += es;
}
while (pb <= pc && (r = cmp(pc, a)) >= 0) {
if (r == 0) {
while (pb <= pc && (cmp_result = CMP(thunk, pc, a)) >= 0) {
if (cmp_result == 0) {
swap_cnt = 1;
swap(pc, pd);
pd -= es;
@ -137,21 +161,26 @@ loop: SWAPINIT(a, es);
pc -= es;
}
if (swap_cnt == 0) { /* Switch to insertion sort */
for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
for (pl = pm; pl > (char *) a && cmp(pl - es, pl) > 0;
for (pm = (char *)a + es; pm < (char *)a + n * es; pm += es)
for (pl = pm;
pl > (char *)a && CMP(thunk, pl - es, pl) > 0;
pl -= es)
swap(pl, pl - es);
return;
}
}
pn = (char *)a + n * es;
r = min(pa - (char *)a, pb - pa);
vecswap(a, pb - r, r);
r = min(pd - pc, pn - pd - (int)es);
vecswap(pb, pn - r, r);
if ((r = pb - pa) > (int)es)
if ((r = pb - pa) > es)
#ifdef I_AM_QSORT_R
qsort_r(a, r / es, es, thunk, cmp);
#else
qsort(a, r / es, es, cmp);
if ((r = pd - pc) > (int)es) {
#endif
if ((r = pd - pc) > es) {
/* Iterate rather than recurse to save stack space */
a = pn - r;
n = r / es;

8
libc/stdlib/qsort_r.c Normal file
View file

@ -0,0 +1,8 @@
/*
* This file is in the public domain. Originally written by Garrett
* A. Wollman.
*
* $FreeBSD: src/lib/libc/stdlib/qsort_r.c,v 1.1.36.1.2.1 2009/10/25 01:10:29 kensmith Exp $
*/
#define I_AM_QSORT_R
#include "qsort.c"