Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /****************************************************************************
  2. *
  3. *                            Open Watcom Project
  4. *
  5. *    Portions Copyright (c) 1983-2002 Sybase, Inc. All Rights Reserved.
  6. *
  7. *  ========================================================================
  8. *
  9. *    This file contains Original Code and/or Modifications of Original
  10. *    Code as defined in and that are subject to the Sybase Open Watcom
  11. *    Public License version 1.0 (the 'License'). You may not use this file
  12. *    except in compliance with the License. BY USING THIS FILE YOU AGREE TO
  13. *    ALL TERMS AND CONDITIONS OF THE LICENSE. A copy of the License is
  14. *    provided with the Original Code and Modifications, and is also
  15. *    available at www.sybase.com/developer/opensource.
  16. *
  17. *    The Original Code and all software distributed under the License are
  18. *    distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
  19. *    EXPRESS OR IMPLIED, AND SYBASE AND ALL CONTRIBUTORS HEREBY DISCLAIM
  20. *    ALL SUCH WARRANTIES, INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF
  21. *    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR
  22. *    NON-INFRINGEMENT. Please see the License for the specific language
  23. *    governing rights and limitations under the License.
  24. *
  25. *  ========================================================================
  26. *
  27. * Description:  Implementation of qsort_s() - bounds-checking qsort().
  28. *               Included by qsort_s.c.
  29. *
  30. ****************************************************************************/
  31.  
  32.  
  33. /* Support OS/2 16-bit protected mode - will never get stack overflow */
  34. #define MAXDEPTH        (sizeof( long ) * 8)
  35.  
  36. #define SHELL           3       /* Shell constant used in shell sort */
  37.  
  38. typedef int WORD;
  39. #define W sizeof( WORD )
  40.  
  41. /*
  42.     swap() is a macro that chooses between an in_line function call and
  43.     an exchange macro.
  44. */
  45. #define exch( a, b, t)          ( t = a, a = b, b = t )
  46. #define swap( a, b )                            \
  47.     swaptype != 0 ? BYTESWAP( a, b, size ) :    \
  48.     ( void ) exch( *( WORD* )( a ), *( WORD* )( b ), t )
  49.  
  50. /*
  51.     Note:   The following assembly was timed against several other methods
  52.     of doing the same thing.  The pragmas here were either fastest on all
  53.     machines tested, or fastest on most machines tested. (including an 8088,
  54.     386 16mhz, 386 33mhz, and 486 25mhz).
  55. */
  56.  
  57. #if defined( __386__ )
  58.     /* this is intended for 386 only... */
  59.     void inline_swap( char *p, char *q, size_t size );
  60.     #pragma aux inline_swap = \
  61.         0x06                            /*      push es             */ \
  62.         0x1e                            /*      push ds             */ \
  63.         0x07                            /*      pop  es             */ \
  64.         0x0f 0xb6 0xd1                  /*      movzx   edx,cl      */ \
  65.         0xc1 0xe9 0x02                  /*      shr     ecx,02H     */ \
  66.         0x74 0x0b                       /*      je      L1          */ \
  67.         0x8b 0x07                       /*L2    mov     eax,[edi]   */ \
  68.         0x87 0x06                       /*      xchg    eax,[esi]   */ \
  69.         0xab                            /*      stosd               */ \
  70.         0x83 0xc6 0x04                  /*      add     esi,0004H   */ \
  71.         0x49                            /*      dec     ecx         */ \
  72.         0x75 0xf5                       /*      jne     L2          */ \
  73.         0x80 0xe2 0x03                  /*L1    and     dl,03H      */ \
  74.         0x74 0x09                       /*      je      L3          */ \
  75.         0x8a 0x07                       /*L4    mov     al,[edi]    */ \
  76.         0x86 0x06                       /*      xchg    al,[esi]    */ \
  77.         0xaa                            /*      stosb               */ \
  78.         0x46                            /*      inc     esi         */ \
  79.         0x4a                            /*      dec     edx         */ \
  80.         0x75 0xf7                       /*      jne     L4          */ \
  81.                                         /*L3                        */ \
  82.         0x07                            /*      pop  es             */ \
  83.         parm caller [esi] [edi] [ecx] \
  84.         value \
  85.         modify exact [esi edi ecx eax edx];
  86.     #pragma aux byteswap parm [esi] [edi] [ecx] \
  87.         modify exact [esi edi ecx eax edx];
  88.     static void _WCNEAR byteswap( char *p, char *q, size_t size ) {
  89.         inline_swap( p, q, size );
  90.     }
  91.  
  92. #elif defined( M_I86 ) && defined( __BIG_DATA__ )
  93.     void inline_swap( char _WCFAR *p, char _WCFAR *q, size_t size );
  94.     #pragma aux inline_swap = \
  95.         0x1e                            /*      push ds             */ \
  96.         0x8e 0xda                       /*      mov ds,dx           */ \
  97.         0xd1 0xe9                       /*      shr cx,1            */ \
  98.         0x74 0x0b                       /*      je L1               */ \
  99.         0x26 0x8b 0x05                  /*L2    mov ax,es:[di]      */ \
  100.         0x87 0x04                       /*      xchg ax,[si]        */ \
  101.         0xab                            /*      stosw               */ \
  102.         0x46                            /*      inc si              */ \
  103.         0x46                            /*      inc si              */ \
  104.         0x49                            /*      dec cx              */ \
  105.         0x75 0xf5                       /*      jne L2              */ \
  106.         0x73 0x07                       /*L1    jnc L3              */ \
  107.         0x8a 0x04                       /*      mov al,[si]         */ \
  108.         0x26 0x86 0x05                  /*      xchg al,es:[di]     */ \
  109.         0x88 0x04                       /*      mov [si],al         */ \
  110.         0x1f                            /*L3    pop ds              */ \
  111.         parm caller [dx si] [es di] [cx] \
  112.         value \
  113.         modify exact [si di cx ax];
  114.     #pragma aux byteswap parm [dx si] [es di] [cx] modify exact [si di cx ax];
  115.     static void _WCNEAR byteswap( char _WCFAR *p, char _WCFAR *q, size_t size ) {
  116.         inline_swap( p, q, size );
  117.     }
  118.  
  119. #elif defined( M_I86 ) && defined( __SMALL_DATA__ )
  120.     /* we'll ask for char __far *q to save us writing code to load es */
  121.     void inline_swap( char *p, char _WCFAR *q, size_t size );
  122.     #pragma aux inline_swap = \
  123.         0xd1 0xe9                       /*      shr cx,1            */ \
  124.         0x74 0x0b                       /*      je L1               */ \
  125.         0x26 0x8b 0x05                  /*L2    mov ax,es:[di]      */ \
  126.         0x87 0x04                       /*      xchg ax,[si]        */ \
  127.         0xab                            /*      stosw               */ \
  128.         0x46                            /*      inc si              */ \
  129.         0x46                            /*      inc si              */ \
  130.         0x49                            /*      dec cx              */ \
  131.         0x75 0xf5                       /*      jne L2              */ \
  132.         0x73 0x07                       /*L1    jnc L3              */ \
  133.         0x8a 0x04                       /*      mov al,[si]         */ \
  134.         0x26 0x86 0x05                  /*      xchg al,es:[di]     */ \
  135.         0x88 0x04                       /*      mov [si],al         */ \
  136.                                         /*L3                        */ \
  137.         parm caller [si] [es di] [cx] \
  138.         value \
  139.         modify exact [si di cx ax];
  140.     #pragma aux byteswap parm [si] [es di] [cx] modify exact [si di cx ax];
  141.     static void _WCNEAR byteswap( char *p, char _WCFAR *q, size_t size ) {
  142.         inline_swap( p, q, size );
  143.     }
  144.  
  145. #else
  146.     /* this is an optimized version of a simple byteswap */
  147.     #define inline_swap BYTESWAP
  148.     static void _WCNEAR BYTESWAP( PTRATTR char *p, PTRATTR char *q, size_t size ) {
  149.         long    dword;
  150.         short   word;
  151.         char    byte;
  152.  
  153.         #if 1       /* this is for 32 bit machines */
  154.             while( size > 3 ) {
  155.                 dword = *(PTRATTR long *)p;
  156.                 *(PTRATTR long *)p = *(PTRATTR long *)q;
  157.                 *(PTRATTR long *)q = dword;
  158.                 p += 4;
  159.                 q += 4;
  160.                 size -= 4;
  161.             }
  162.             if( size > 1 ) {
  163.                 word = *(PTRATTR short *)p;
  164.                 *(PTRATTR short *)p = *(PTRATTR short *)q;
  165.                 *(PTRATTR short *)q = word;
  166.                 p += 2;
  167.                 q += 2;
  168.                 size -= 2;
  169.             }
  170.         #else       /* this is for 16 bit machines */
  171.             while( size > 1 ) {
  172.                 word = *(PTRATTR short *)p;
  173.                 *(PTRATTR short *)p = *(PTRATTR short *)q;
  174.                 *(PTRATTR short *)q = word;
  175.                 p += 2;
  176.                 q += 2;
  177.                 size -= 2;
  178.             }
  179.         #endif
  180.         if( size ) {
  181.             byte = *p;
  182.             *p = *q;
  183.             *q = byte;
  184.         }
  185.     }
  186. #endif
  187.  
  188.  
  189. FUNCTION_LINKAGE errno_t FUNCTION_NAME( PTRATTR void *in_base,
  190.                                         rsize_t n, rsize_t size,
  191.                int (*compar)( const void *, const void *, void * ),
  192.                                         void *context )
  193. /*****************************************************************/
  194. {
  195.     PTRATTR char        *base = (PTRATTR char*) in_base;
  196.     PTRATTR char        *p1;
  197.     PTRATTR char        *p2;
  198.     PTRATTR char        *pa;
  199.     PTRATTR char        *pb;
  200.     PTRATTR char        *pc;
  201.     PTRATTR char        *pd;
  202.     PTRATTR char        *pn;
  203.     PTRATTR char        *pv;
  204.     PTRATTR char        *mid;
  205.     WORD                v;              /* used in pivot initialization */
  206.     WORD                t;              /* used in exch() macro */
  207.     int                 comparison, swaptype, shell;
  208.     size_t              count, r, s;
  209.     unsigned            sp;
  210.     auto char           *base_stack[MAXDEPTH];
  211.     unsigned            n_stack[MAXDEPTH];
  212.     qcomp               *cmp = (qcomp*)compar;
  213.     errno_t             rc = -1;
  214.  
  215.     /* runtime-constraints */
  216.     // n     <= RSIZE_MAX
  217.     // size  <= RSIZE_MAX
  218.     // if n  > 0  then in_base, compar not NULL
  219.     if( __check_constraint_maxsize( n ) &&
  220.         __check_constraint_maxsize( size ) &&
  221.         ((n == 0) || __check_constraint_nullptr( in_base ) &&
  222.                      __check_constraint_nullptr( compar )) ) {
  223.  
  224.         if( n == 0 ) {                              /* empty array - nothing to do */
  225.             return( 0 );
  226.         }
  227.  
  228.         /*
  229.             Initialization of the swaptype variable, which determines which
  230.             type of swapping should be performed when swap() is called.
  231.             0 for single-word swaps, 1 for general swapping by words, and
  232.             2 for swapping by bytes.  W (it's a macro) = sizeof(WORD).
  233.         */
  234.         swaptype = ( ( base - (char *)0 ) | size ) % W ? 2 : size > W ? 1 : 0;
  235.         sp = 0;
  236.         for( ;; ) {
  237.             while( n > 1 ) {
  238.                 if( n < 16 ) {      /* 2-shell sort on smallest arrays */
  239.                     for( shell = (size * SHELL) ;
  240.                          shell > 0 ;
  241.                          shell -= ((SHELL-1) * size) ) {
  242.                         p1 = base + shell;
  243.                         for( ; p1 < base + n * size; p1 += shell ) {
  244.                             for( p2 = p1;
  245.                                  p2 > base && cmp( p2 - shell, p2, context ) > 0;
  246.                                  p2 -= shell ) {
  247.                                 swap( p2, p2 - shell );
  248.                             }
  249.                         }
  250.                     }
  251.                     break;
  252.                 } else {    /* n >= 16 */
  253.                     /* Small array (15 < n < 30), mid element */
  254.                     mid = base + (n >> 1) * size;
  255.                     if( n > 29 ) {
  256.                         p1 = base;
  257.                         p2 = base + ( n - 1 ) * size;
  258.                         if( n > 42 ) {      /* Big array, pseudomedian of 9 */
  259.                             s = (n >> 3) * size;
  260.                             p1  = MED3( p1, p1 + s, p1 + (s << 1), cmp, context );
  261.                             mid = MED3( mid - s, mid, mid + s, cmp, context );
  262.                             p2  = MED3( p2 - (s << 1), p2 - s, p2, cmp, context );
  263.                         }
  264.                         /* Mid-size (29 < n < 43), med of 3 */
  265.                         mid = MED3( p1, mid, p2, cmp, context );
  266.                     }
  267.                     /*
  268.                         The following sets up the pivot (pv) for partitioning.
  269.                         It's better to store the pivot value out of line
  270.                         instead of swapping it to base. However, it's
  271.                         inconvenient in C unless the element size is fixed.
  272.                         So, only the important special case of word-size
  273.                         objects has utilized it.
  274.                     */
  275.                     if( swaptype != 0 ) { /* Not word-size objects */
  276.                         pv = base;
  277.                         swap( pv, mid );
  278.                     } else {        /* Storing the pivot out of line (at v) */
  279.                         pv = (char *)&v;
  280.                         v = *(WORD *)mid;
  281.                     }
  282.  
  283.                     pa = pb = base;
  284.                     pc = pd = base + ( n - 1 ) * size;
  285.                     count = n;
  286.                     /*
  287.                         count keeps track of how many entries we have
  288.                         examined.  Once we have looked at all the entries
  289.                         then we know that the partitioning is complete.
  290.                         We use count to terminate the looping, rather than
  291.                         a pointer comparison, to handle 16bit pointer
  292.                         limitations that may lead pb or pc to wrap.
  293.                         i.e. pc  = 0x0000;
  294.                              pc -= 0x0004;
  295.                              pc == 0xfffc;
  296.                              pc is no longer less that 0x0000;
  297.                     */
  298.                     for( ;; ) {
  299.                         while( count && (comparison = cmp(pb, pv, context )) <= 0 ) {
  300.                             if( comparison == 0 ) {
  301.                                 swap( pa, pb );
  302.                                 pa += size;
  303.                             }
  304.                             pb += size;
  305.                             count--;
  306.                         }
  307.                         while( count && (comparison = cmp(pc, pv, context )) >= 0 ) {
  308.                             if( comparison == 0 ) {
  309.                                 swap( pc, pd );
  310.                                 pd -= size;
  311.                             }
  312.                             pc -= size;
  313.                             count--;
  314.                         }
  315.                         if( !count ) break;
  316.                         swap( pb, pc );
  317.                         pb += size;
  318.                         count--;
  319.                         if( !count ) break;
  320.                         pc -= size;
  321.                         count--;
  322.                     }
  323.                     pn = base + n * size;
  324.                     s = min( pa - base, pb - pa );
  325.                     if( s > 0 ) {
  326.                         inline_swap( base, pb - s, s );
  327.                     }
  328.                     s = min( pd - pc, pn - pd - size);
  329.                     if( s > 0 ) {
  330.                         inline_swap( pb, pn - s, s );
  331.                     }
  332.                     /* Now, base to (pb-pa) needs to be sorted              */
  333.                     /* Also, pn-(pd-pc) needs to be sorted                  */
  334.                     /* The middle 'chunk' contains all elements=pivot value */
  335.                     r = pb - pa;
  336.                     s = pd - pc;
  337.                     if( s >= r ) {          /* Stack up the larger chunk */
  338.                         base_stack[sp] = pn - s;    /* Stack up base            */
  339.                         n_stack[sp] = s / size;     /* Stack up n               */
  340.                         n = r / size;               /* Set up n for next 'call' */
  341.                                                     /* next base is still base  */
  342.                     } else {
  343.                         if( r <= size ) break;
  344.                         base_stack[sp] = base;      /* Stack up base            */
  345.                         n_stack[sp] = r / size;     /* Stack up n               */
  346.                         base = pn - s;              /* Set up base and n for    */
  347.                         n = s / size;               /* next 'call'              */
  348.                     }
  349.                     ++sp;
  350.                 }
  351.             }
  352.             if( sp == 0 ) break;
  353.             --sp;
  354.             base = base_stack[sp];
  355.             n    = n_stack[sp];
  356.         }
  357.         rc = 0;
  358.     }
  359.     return( rc );
  360. }
  361.