phobos/internal/qsort.d
2007-09-10 04:30:47 +00:00

161 lines
4.4 KiB
D

/*
Portions of this file are:
Copyright Prototronics, 1987
Totem Lake P.O. 8117
Kirkland, Washington 98034
(206) 820-1972
Licensed to Digital Mars.
June 11, 1987 from Ray Gardner's
Denver, Colorado) public domain version
Use qsort2.d instead of this file if a redistributable version of
_adSort() is required.
*/
/*
** Sorts an array starting at base, of length nbr_elements, each
** element of size width_bytes, ordered via compare_function; which
** is called as (*comp_fp)(ptr_to_element1, ptr_to_element2)
** and returns < 0 if element1 < element2, 0 if element1 = element2,
** > 0 if element1 > element2. Most of the refinements are due to
** R. Sedgewick. See "Implementing Quicksort Programs", Comm. ACM,
** Oct. 1978, and Corrigendum, Comm. ACM, June 1979.
*/
//debug=qsort; // uncomment to turn on debugging printf's
import std.c.stdio;
import std.c.stdlib;
import std.string;
import std.outofmemory;
struct Array
{
int length;
void *ptr;
}
private const int _maxspan = 7; // subarrays of _maxspan or fewer elements
// will be sorted by a simple insertion sort
/* Adjust _maxspan according to relative cost of a swap and a compare. Reduce
_maxspan (not less than 1) if a swap is very expensive such as when you have
an array of large structures to be sorted, rather than an array of pointers to
structures. The default value is optimized for a high cost for compares. */
extern (C) long _adSort(Array a, TypeInfo ti)
{
byte* base;
byte*[40] stack; // stack
byte** sp; // stack pointer
byte* i, j, limit; // scan and limit pointers
uint thresh; // size of _maxspan elements in bytes
uint width = ti.tsize();
base = cast(byte *)a.ptr;
thresh = _maxspan * width; // init threshold
sp = stack; // init stack pointer
limit = base + a.length * width; // pointer past end of array
while (1) // repeat until done then return
{
while (limit - base > thresh) // if more than _maxspan elements
{
//swap middle, base
ti.swap((cast(uint)(limit - base) >> 1) -
(((cast(uint)(limit - base) >> 1)) % width) + base, base);
i = base + width; // i scans from left to right
j = limit - width; // j scans from right to left
if (ti.compare(i, j) > 0) // Sedgewick's
ti.swap(i, j); // three-element sort
if (ti.compare(base, j) > 0) // sets things up
ti.swap(base, j); // so that
if (ti.compare(i, base) > 0) // *i <= *base <= *j
ti.swap(i, base); // *base is the pivot element
while (1)
{
do // move i right until *i >= pivot
i += width;
while (ti.compare(i, base) < 0);
do // move j left until *j <= pivot
j -= width;
while (ti.compare(j, base) > 0);
if (i > j) // break loop if pointers crossed
break;
ti.swap(i, j); // else swap elements, keep scanning
}
ti.swap(base, j); // move pivot into correct place
if (j - base > limit - i) // if left subarray is larger...
{
sp[0] = base; // stack left subarray base
sp[1] = j; // and limit
base = i; // sort the right subarray
}
else // else right subarray is larger
{
sp[0] = i; // stack right subarray base
sp[1] = limit; // and limit
limit = j; // sort the left subarray
}
sp += 2; // increment stack pointer
assert(sp < cast(byte**)stack + stack.length);
}
// Insertion sort on remaining subarray
i = base + width;
while (i < limit)
{
j = i;
while (j > base && ti.compare(j - width, j) > 0)
{
ti.swap(j - width, j);
j -= width;
}
i += width;
}
if (sp > stack) // if any entries on stack...
{
sp -= 2; // pop the base and limit
base = sp[0];
limit = sp[1];
}
else // else stack empty, all done
return *cast(long*)(&a);
}
}
unittest
{
debug(qsort) printf("array.sort.unittest()\n");
int a[] = new int[10];
a[0] = 23;
a[1] = 1;
a[2] = 64;
a[3] = 5;
a[4] = 6;
a[5] = 5;
a[6] = 17;
a[7] = 3;
a[8] = 0;
a[9] = -1;
a.sort;
for (int i = 0; i < a.length - 1; i++)
{
//printf("i = %d", i);
//printf(" %d %d\n", a[i], a[i + 1]);
assert(a[i] <= a[i + 1]);
}
}