Files
glibc/stdlib/msort.c
T

161 lines
4.0 KiB
C
Raw Normal View History

1997-02-15 02:32:58 +00:00
/* An alternative to qsort, with an identical interface.
1997-02-10 03:19:57 +00:00
This file is part of the GNU C Library.
2004-02-07 15:57:44 +00:00
Copyright (C) 1992,95-97,99,2000,01,02,04 Free Software Foundation, Inc.
2002-01-29 07:54:51 +00:00
Written by Mike Haertel, September 1988.
1995-02-18 01:27:10 +00:00
1997-02-10 03:19:57 +00:00
The GNU C Library is free software; you can redistribute it and/or
2001-07-06 04:58:11 +00:00
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
1995-02-18 01:27:10 +00:00
1997-02-10 03:19:57 +00:00
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
2001-07-06 04:58:11 +00:00
Lesser General Public License for more details.
1995-02-18 01:27:10 +00:00
2001-07-06 04:58:11 +00:00
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
1995-02-18 01:27:10 +00:00
1999-10-28 21:38:59 +00:00
#include <alloca.h>
1995-02-18 01:27:10 +00:00
#include <stdlib.h>
#include <string.h>
2000-02-28 08:14:33 +00:00
#include <unistd.h>
#include <memcopy.h>
#include <errno.h>
1995-02-18 01:27:10 +00:00
2002-01-18 06:26:02 +00:00
static void msort_with_tmp (void *b, size_t n, size_t s,
2002-01-29 07:54:51 +00:00
__compar_fn_t cmp, char *t);
2002-01-18 06:26:02 +00:00
static void
2002-01-29 07:54:51 +00:00
msort_with_tmp (void *b, size_t n, size_t s, __compar_fn_t cmp,
char *t)
2002-01-18 06:26:02 +00:00
{
2002-01-29 07:54:51 +00:00
char *tmp;
char *b1, *b2;
size_t n1, n2;
2002-01-18 06:26:02 +00:00
2002-01-29 07:54:51 +00:00
if (n <= 1)
return;
n1 = n / 2;
n2 = n - n1;
b1 = b;
b2 = (char *) b + (n1 * s);
msort_with_tmp (b1, n1, s, cmp, t);
msort_with_tmp (b2, n2, s, cmp, t);
tmp = t;
if (s == OPSIZ && (b1 - (char *) 0) % OPSIZ == 0)
/* We are operating on aligned words. Use direct word stores. */
while (n1 > 0 && n2 > 0)
{
if ((*cmp) (b1, b2) <= 0)
{
--n1;
2004-02-07 15:57:44 +00:00
*((op_t *) tmp) = *((op_t *) b1);
tmp += sizeof (op_t);
b1 += sizeof (op_t);
2002-01-29 07:54:51 +00:00
}
else
{
--n2;
2004-02-07 15:57:44 +00:00
*((op_t *) tmp) = *((op_t *) b2);
tmp += sizeof (op_t);
b2 += sizeof (op_t);
2002-01-29 07:54:51 +00:00
}
}
2002-01-18 06:26:02 +00:00
else
2002-01-29 07:54:51 +00:00
while (n1 > 0 && n2 > 0)
{
if ((*cmp) (b1, b2) <= 0)
{
tmp = (char *) __mempcpy (tmp, b1, s);
b1 += s;
--n1;
}
else
{
tmp = (char *) __mempcpy (tmp, b2, s);
b2 += s;
--n2;
}
}
if (n1 > 0)
memcpy (tmp, b1, n1 * s);
memcpy (b, t, (n - n2) * s);
1995-02-18 01:27:10 +00:00
}
void
1999-10-28 21:38:59 +00:00
qsort (void *b, size_t n, size_t s, __compar_fn_t cmp)
1995-02-18 01:27:10 +00:00
{
1996-09-27 03:45:24 +00:00
const size_t size = n * s;
1995-02-18 01:27:10 +00:00
if (size < 1024)
{
void *buf = __alloca (size);
/* The temporary array is small, so put it on the stack. */
msort_with_tmp (b, n, s, cmp, buf);
}
1995-02-18 01:27:10 +00:00
else
{
2000-02-28 08:14:33 +00:00
/* We should avoid allocating too much memory since this might
have to be backed up by swap space. */
static long int phys_pages;
static int pagesize;
if (phys_pages == 0)
1995-02-18 01:27:10 +00:00
{
2000-02-28 08:14:33 +00:00
phys_pages = __sysconf (_SC_PHYS_PAGES);
if (phys_pages == -1)
/* Error while determining the memory size. So let's
assume there is enough memory. Otherwise the
implementer should provide a complete implementation of
the `sysconf' function. */
phys_pages = (long int) (~0ul >> 1);
/* The following determines that we will never use more than
a quarter of the physical memory. */
phys_pages /= 4;
pagesize = __sysconf (_SC_PAGESIZE);
1995-02-18 01:27:10 +00:00
}
2000-02-28 08:14:33 +00:00
/* Just a comment here. We cannot compute
phys_pages * pagesize
and compare the needed amount of memory against this value.
The problem is that some systems might have more physical
memory then can be represented with a `size_t' value (when
measured in bytes. */
/* If the memory requirements are too high don't allocate memory. */
if (size / pagesize > (size_t) phys_pages)
2000-02-28 08:14:33 +00:00
_quicksort (b, n, s, cmp);
1995-02-18 01:27:10 +00:00
else
{
2000-02-28 08:14:33 +00:00
/* It's somewhat large, so malloc it. */
int save = errno;
char *tmp = malloc (size);
if (tmp == NULL)
{
/* Couldn't get space, so use the slower algorithm
that doesn't need a temporary array. */
__set_errno (save);
_quicksort (b, n, s, cmp);
}
else
{
__set_errno (save);
msort_with_tmp (b, n, s, cmp, tmp);
free (tmp);
}
1995-02-18 01:27:10 +00:00
}
}
}
libc_hidden_def (qsort)