LCOV - code coverage report
Current view: top level - src/port - qsort_arg.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 71 72 98.6 %
Date: 2017-09-29 13:40:31 Functions: 3 3 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  qsort_arg.c: qsort with a passthrough "void *" argument
       3             :  *
       4             :  *  Modifications from vanilla NetBSD source:
       5             :  *    Add do ... while() macro fix
       6             :  *    Remove __inline, _DIAGASSERTs, __P
       7             :  *    Remove ill-considered "swap_cnt" switch to insertion sort,
       8             :  *    in favor of a simple check for presorted input.
       9             :  *    Take care to recurse on the smaller partition, to bound stack usage.
      10             :  *
      11             :  *  CAUTION: if you change this file, see also qsort.c, gen_qsort_tuple.pl
      12             :  *
      13             :  *  src/port/qsort_arg.c
      14             :  */
      15             : 
      16             : /*  $NetBSD: qsort.c,v 1.13 2003/08/07 16:43:42 agc Exp $   */
      17             : 
      18             : /*-
      19             :  * Copyright (c) 1992, 1993
      20             :  *  The Regents of the University of California.  All rights reserved.
      21             :  *
      22             :  * Redistribution and use in source and binary forms, with or without
      23             :  * modification, are permitted provided that the following conditions
      24             :  * are met:
      25             :  * 1. Redistributions of source code must retain the above copyright
      26             :  *    notice, this list of conditions and the following disclaimer.
      27             :  * 2. Redistributions in binary form must reproduce the above copyright
      28             :  *    notice, this list of conditions and the following disclaimer in the
      29             :  *    documentation and/or other materials provided with the distribution.
      30             :  * 3. Neither the name of the University nor the names of its contributors
      31             :  *    may be used to endorse or promote products derived from this software
      32             :  *    without specific prior written permission.
      33             :  *
      34             :  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
      35             :  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
      36             :  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
      37             :  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      38             :  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
      39             :  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
      40             :  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      41             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
      42             :  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
      43             :  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
      44             :  * SUCH DAMAGE.
      45             :  */
      46             : 
      47             : #include "c.h"
      48             : 
      49             : 
      50             : static char *med3(char *a, char *b, char *c,
      51             :      qsort_arg_comparator cmp, void *arg);
      52             : static void swapfunc(char *, char *, size_t, int);
      53             : 
      54             : /*
      55             :  * Qsort routine based on J. L. Bentley and M. D. McIlroy,
      56             :  * "Engineering a sort function",
      57             :  * Software--Practice and Experience 23 (1993) 1249-1265.
      58             :  *
      59             :  * We have modified their original by adding a check for already-sorted input,
      60             :  * which seems to be a win per discussions on pgsql-hackers around 2006-03-21.
      61             :  *
      62             :  * Also, we recurse on the smaller partition and iterate on the larger one,
      63             :  * which ensures we cannot recurse more than log(N) levels (since the
      64             :  * partition recursed to is surely no more than half of the input).  Bentley
      65             :  * and McIlroy explicitly rejected doing this on the grounds that it's "not
      66             :  * worth the effort", but we have seen crashes in the field due to stack
      67             :  * overrun, so that judgment seems wrong.
      68             :  */
      69             : 
      70             : #define swapcode(TYPE, parmi, parmj, n) \
      71             : do {        \
      72             :     size_t i = (n) / sizeof (TYPE);         \
      73             :     TYPE *pi = (TYPE *)(void *)(parmi);         \
      74             :     TYPE *pj = (TYPE *)(void *)(parmj);         \
      75             :     do {                        \
      76             :         TYPE    t = *pi;            \
      77             :         *pi++ = *pj;                \
      78             :         *pj++ = t;              \
      79             :         } while (--i > 0);               \
      80             : } while (0)
      81             : 
      82             : #define SWAPINIT(a, es) swaptype = ((char *)(a) - (char *)0) % sizeof(long) || \
      83             :     (es) % sizeof(long) ? 2 : (es) == sizeof(long)? 0 : 1;
      84             : 
      85             : static void
      86     4168487 : swapfunc(char *a, char *b, size_t n, int swaptype)
      87             : {
      88     4168487 :     if (swaptype <= 1)
      89     4168487 :         swapcode(long, a, b, n);
      90             :     else
      91           0 :         swapcode(char, a, b, n);
      92     4168487 : }
      93             : 
      94             : #define swap(a, b)                      \
      95             :     if (swaptype == 0) {                    \
      96             :         long t = *(long *)(void *)(a);          \
      97             :         *(long *)(void *)(a) = *(long *)(void *)(b);    \
      98             :         *(long *)(void *)(b) = t;           \
      99             :     } else                          \
     100             :         swapfunc(a, b, es, swaptype)
     101             : 
     102             : #define vecswap(a, b, n) if ((n) > 0) swapfunc(a, b, n, swaptype)
     103             : 
     104             : static char *
     105      399970 : med3(char *a, char *b, char *c, qsort_arg_comparator cmp, void *arg)
     106             : {
     107      799940 :     return cmp(a, b, arg) < 0 ?
     108      187425 :         (cmp(b, c, arg) < 0 ? b : (cmp(a, c, arg) < 0 ? c : a))
     109      587395 :         : (cmp(b, c, arg) > 0 ? b : (cmp(a, c, arg) < 0 ? a : c));
     110             : }
     111             : 
     112             : void
     113      533471 : qsort_arg(void *a, size_t n, size_t es, qsort_arg_comparator cmp, void *arg)
     114             : {
     115             :     char       *pa,
     116             :                *pb,
     117             :                *pc,
     118             :                *pd,
     119             :                *pl,
     120             :                *pm,
     121             :                *pn;
     122             :     size_t      d1,
     123             :                 d2;
     124             :     int         r,
     125             :                 swaptype,
     126             :                 presorted;
     127             : 
     128      533471 : loop:SWAPINIT(a, es);
     129      533471 :     if (n < 7)
     130             :     {
     131      943628 :         for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
     132     2112983 :             for (pl = pm; pl > (char *) a && cmp(pl - es, pl, arg) > 0;
     133      708099 :                  pl -= es)
     134      708099 :                 swap(pl, pl - es);
     135      241186 :         return;
     136             :     }
     137      292285 :     presorted = 1;
     138     2003506 :     for (pm = (char *) a + es; pm < (char *) a + n * es; pm += es)
     139             :     {
     140     1996367 :         if (cmp(pm - es, pm, arg) > 0)
     141             :         {
     142      285146 :             presorted = 0;
     143      285146 :             break;
     144             :         }
     145             :     }
     146      292285 :     if (presorted)
     147        7139 :         return;
     148      285146 :     pm = (char *) a + (n / 2) * es;
     149      285146 :     if (n > 7)
     150             :     {
     151      258022 :         pl = (char *) a;
     152      258022 :         pn = (char *) a + (n - 1) * es;
     153      258022 :         if (n > 40)
     154             :         {
     155       47316 :             size_t      d = (n / 8) * es;
     156             : 
     157       47316 :             pl = med3(pl, pl + d, pl + 2 * d, cmp, arg);
     158       47316 :             pm = med3(pm - d, pm, pm + d, cmp, arg);
     159       47316 :             pn = med3(pn - 2 * d, pn - d, pn, cmp, arg);
     160             :         }
     161      258022 :         pm = med3(pl, pm, pn, cmp, arg);
     162             :     }
     163      285146 :     swap(a, pm);
     164      285146 :     pa = pb = (char *) a + es;
     165      285146 :     pc = pd = (char *) a + (n - 1) * es;
     166             :     for (;;)
     167             :     {
     168    10824440 :         while (pb <= pc && (r = cmp(pb, a, arg)) <= 0)
     169             :         {
     170     4710494 :             if (r == 0)
     171             :             {
     172       63717 :                 swap(pa, pb);
     173       63717 :                 pa += es;
     174             :             }
     175     4710494 :             pb += es;
     176             :         }
     177    10547204 :         while (pb <= pc && (r = cmp(pc, a, arg)) >= 0)
     178             :         {
     179     4433258 :             if (r == 0)
     180             :             {
     181       58501 :                 swap(pc, pd);
     182       58501 :                 pd -= es;
     183             :             }
     184     4433258 :             pc -= es;
     185             :         }
     186     3056973 :         if (pb > pc)
     187      285146 :             break;
     188     2771827 :         swap(pb, pc);
     189     2771827 :         pb += es;
     190     2771827 :         pc -= es;
     191     2771827 :     }
     192      285146 :     pn = (char *) a + n * es;
     193      285146 :     d1 = Min(pa - (char *) a, pb - pa);
     194      285146 :     vecswap(a, pb - d1, d1);
     195      285146 :     d1 = Min(pd - pc, pn - pd - es);
     196      285146 :     vecswap(pb, pn - d1, d1);
     197      285146 :     d1 = pb - pa;
     198      285146 :     d2 = pd - pc;
     199      285146 :     if (d1 <= d2)
     200             :     {
     201             :         /* Recurse on left partition, then iterate on right partition */
     202      134543 :         if (d1 > es)
     203      111565 :             qsort_arg(a, d1 / es, es, cmp, arg);
     204      134543 :         if (d2 > es)
     205             :         {
     206             :             /* Iterate rather than recurse to save stack space */
     207             :             /* qsort_arg(pn - d2, d2 / es, es, cmp, arg); */
     208      134543 :             a = pn - d2;
     209      134543 :             n = d2 / es;
     210      134543 :             goto loop;
     211             :         }
     212             :     }
     213             :     else
     214             :     {
     215             :         /* Recurse on right partition, then iterate on left partition */
     216      150603 :         if (d2 > es)
     217       96346 :             qsort_arg(pn - d2, d2 / es, es, cmp, arg);
     218      150603 :         if (d1 > es)
     219             :         {
     220             :             /* Iterate rather than recurse to save stack space */
     221             :             /* qsort_arg(a, d1 / es, es, cmp, arg); */
     222      150603 :             n = d1 / es;
     223      150603 :             goto loop;
     224             :         }
     225             :     }
     226             : }

Generated by: LCOV version 1.11