]> granicus.if.org Git - python/commitdiff
Tim's revision of the previous patch. He also added some sparts to
authorGuido van Rossum <guido@python.org>
Fri, 29 May 1998 17:56:32 +0000 (17:56 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 29 May 1998 17:56:32 +0000 (17:56 +0000)
the median-of-three code to get a few percent back.

Objects/listobject.c

index c2e9d5e297ab784e7494038cbf8e3637f17201de..cae18d9ce87a66c9a86ba4502f6df5064be11536 100644 (file)
@@ -659,8 +659,6 @@ quicksort(list, compare)
        PyListObject *list; /* List to sort */
        PyObject *compare;/* Comparison function object, or NULL for default */
 {
-       int size = list->ob_size; /* Number of elements to sort */
-       PyObject **array = list->ob_item; /* Start of array to sort */
        register PyObject *tmp, *pivot;
        register PyObject **l, **r, **p;
        PyObject **lo, **hi, **notp;
@@ -669,10 +667,12 @@ quicksort(list, compare)
        PyObject **histack[STACKSIZE];
 
        /* Start out with the whole array on the work stack */
-       lostack[0] = array;
-       histack[0] = array+size;
+       lostack[0] = list->ob_item;
+       histack[0] = list->ob_item + list->ob_size;
        top = 1;
 
+#define SETK(X,Y) if ((k = docompare(X,Y,compare,list))==CMPERROR) goto fail
+
        /* Repeat until the work stack is empty */
        while (--top >= 0) {
                lo = lostack[top];
@@ -688,10 +688,7 @@ quicksort(list, compare)
                                pivot = *r;
                                do {
                                        p = l + ((r - l) >> 1);
-                                       k = docompare(pivot, *p,
-                                                     compare, list);
-                                       if (k == CMPERROR)
-                                               return -1;
+                                       SETK(pivot, *p);
                                        if (k < 0)
                                                r = p;
                                        else
@@ -708,28 +705,30 @@ quicksort(list, compare)
                        continue;
                }
 
-               /* Choose median of first, middle and last as pivot */
+               /* Choose median of first, middle and last as pivot;
+                  this is a simple unrolled 3-element insertion sort */
                l = lo;          /* First  */
                p = lo + (n>>1); /* Middle */
                r = hi - 1;      /* Last   */
 
-               k = docompare(*p, *l, compare, list);
-               if (k == CMPERROR)
-                       return -1;
-               if (k < 0)
-                       { tmp = *p; *p = *l; *l = tmp; }
-
-               k = docompare(*r, *p, compare, list);
-               if (k == CMPERROR)
-                       return -1;
-               if (k < 0)
-                       { tmp = *r; *r = *p; *p = tmp; }
+               pivot = *p;
+               SETK(pivot, *l);
+               if (k < 0) {
+                       *p = *l;
+                       *l = pivot;
+               }
 
-               k = docompare(*p, *l, compare, list);
-               if (k == CMPERROR)
-                       return -1;
-               if (k < 0)
-                       { tmp = *p; *p = *l; *l = tmp; }
+               pivot = *r;
+               SETK(pivot, *p);
+               if (k < 0) {
+                       *r = *p;
+                       *p = pivot;   /* for consistency */
+                       SETK(pivot, *l);
+                       if (k < 0) {
+                               *p = *l;
+                               *l = pivot;
+                       }
+               }
 
                pivot = *p;
                l++;
@@ -741,9 +740,7 @@ quicksort(list, compare)
 
                        /* Move left index to element >= pivot */
                        while (l < p) {
-                               k = docompare(*l, pivot, compare, list);
-                               if (k == CMPERROR)
-                                       return -1;
+                               SETK(*l, pivot);
                                if (k < 0)
                                        l++;
                                else {
@@ -753,9 +750,7 @@ quicksort(list, compare)
                        }
                        /* Move right index to element <= pivot */
                        while (r > p) {
-                               k = docompare(pivot, *r, compare, list);
-                               if (k == CMPERROR)
-                                       return -1;
+                               SETK(pivot, *r);
                                if (k < 0)
                                        r--;
                                else {
@@ -780,9 +775,9 @@ quicksort(list, compare)
                        /* One (exactly) of the pointers is at p */
                        /* assert (p == l) ^ (p == r) */
                        notp = lisp ? r : l;
+                       *p = *notp;
                        k = (r - l) >> 1;
                        if (k) {
-                               *p = *notp;
                                if (lisp) {
                                        p = r - k;
                                        l++;
@@ -791,14 +786,12 @@ quicksort(list, compare)
                                        p = l + k;
                                        r--;
                                }
-                               /* assert l < p < r */
                                *notp = *p;
                                *p = pivot;    /* for consistency */
                                continue;
                        }
 
                        /* assert l+1 == r */
-                       *p = *notp;
                        *notp = pivot;
                        p = notp;
                        break;
@@ -818,9 +811,7 @@ quicksort(list, compare)
                 * This wastes a compare if it fails, but can win big
                 * when there are runs of duplicates.
                 */
-               k = docompare(pivot, *l, compare, list);
-               if (k == CMPERROR)
-                       return -1;
+               SETK(pivot, *l);
                if (!(k < 0)) {
                        /* Now extend as far as possible (around p) so that:
                           All in [lo,r) are <= pivot
@@ -831,9 +822,7 @@ quicksort(list, compare)
                        */
                        while (r > lo) {
                                /* because r-1 < p, *(r-1) <= pivot is known */
-                               k = docompare(*(r-1), pivot, compare, list);
-                               if (k == CMPERROR)
-                                       return -1;
+                               SETK(*(r-1), pivot);
                                if (k < 0)
                                        break;
                                /* <= and not < implies == */
@@ -843,9 +832,7 @@ quicksort(list, compare)
                        l++;
                        while (l < hi) {
                                /* because l > p, pivot <= *l is known */
-                               k = docompare(pivot, *l, compare, list);
-                               if (k == CMPERROR)
-                                       return -1;
+                               SETK(pivot, *l);
                                if (k < 0)
                                        break;
                                /* <= and not < implies == */
@@ -873,6 +860,11 @@ quicksort(list, compare)
 
        /* Success */
        return 0;
+
+ fail:
+       return -1;
+
+#undef SETK
 }
 
 static PyObject *