]> granicus.if.org Git - postgresql/commitdiff
Replace insertion sort in contrib/intarray with qsort().
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 16 Mar 2015 03:22:03 +0000 (23:22 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 16 Mar 2015 03:22:03 +0000 (23:22 -0400)
It's all very well to claim that a simplistic sort is fast in easy
cases, but O(N^2) in the worst case is not good ... especially if the
worst case is as easy to hit as "descending order input".  Replace that
bit with our standard qsort.

Per bug #12866 from Maksym Boguk.  Back-patch to all active branches.

contrib/intarray/_int_tool.c

index 511c7acb54e811c5b3612230149253309e9f3f2e..3c52912bbf4500c47bcc237c882450df5419678c 100644 (file)
@@ -184,40 +184,34 @@ rt__int_size(ArrayType *a, float *size)
        *size = (float) ARRNELEMS(a);
 }
 
+/* qsort_arg comparison function for isort() */
+static int
+isort_cmp(const void *a, const void *b, void *arg)
+{
+       int32           aval = *((const int32 *) a);
+       int32           bval = *((const int32 *) b);
+
+       if (aval < bval)
+               return -1;
+       if (aval > bval)
+               return 1;
+
+       /*
+        * Report if we have any duplicates.  If there are equal keys, qsort must
+        * compare them at some point, else it wouldn't know whether one should go
+        * before or after the other.
+        */
+       *((bool *) arg) = true;
+       return 0;
+}
+
 /* Sort the given data (len >= 2).  Return true if any duplicates found */
 bool
 isort(int32 *a, int len)
 {
-       int32           cur,
-                               prev;
-       int32      *pcur,
-                          *pprev,
-                          *end;
-       bool            r = FALSE;
+       bool            r = false;
 
-       /*
-        * We use a simple insertion sort.  While this is O(N^2) in the worst
-        * case, it's quite fast if the input is already sorted or nearly so.
-        * Also, for not-too-large inputs it's faster than more complex methods
-        * anyhow.
-        */
-       end = a + len;
-       for (pcur = a + 1; pcur < end; pcur++)
-       {
-               cur = *pcur;
-               for (pprev = pcur - 1; pprev >= a; pprev--)
-               {
-                       prev = *pprev;
-                       if (prev <= cur)
-                       {
-                               if (prev == cur)
-                                       r = TRUE;
-                               break;
-                       }
-                       pprev[1] = prev;
-               }
-               pprev[1] = cur;
-       }
+       qsort_arg(a, len, sizeof(int32), isort_cmp, (void *) &r);
        return r;
 }