Blame stdlib/qsort.c

Packit 6c4009
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Written by Douglas C. Schmidt (schmidt@ics.uci.edu).
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
/* If you consider tuning this algorithm, you should consult first:
Packit 6c4009
   Engineering a sort function; Jon Bentley and M. Douglas McIlroy;
Packit 6c4009
   Software - Practice and Experience; Vol. 23 (11), 1249-1265, 1993.  */
Packit 6c4009
Packit 6c4009
#include <alloca.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
Packit 6c4009
/* Byte-wise swap two items of size SIZE. */
Packit 6c4009
#define SWAP(a, b, size)						      \
Packit 6c4009
  do									      \
Packit 6c4009
    {									      \
Packit 6c4009
      size_t __size = (size);						      \
Packit 6c4009
      char *__a = (a), *__b = (b);					      \
Packit 6c4009
      do								      \
Packit 6c4009
	{								      \
Packit 6c4009
	  char __tmp = *__a;						      \
Packit 6c4009
	  *__a++ = *__b;						      \
Packit 6c4009
	  *__b++ = __tmp;						      \
Packit 6c4009
	} while (--__size > 0);						      \
Packit 6c4009
    } while (0)
Packit 6c4009
Packit 6c4009
/* Discontinue quicksort algorithm when partition gets below this size.
Packit 6c4009
   This particular magic number was chosen to work best on a Sun 4/260. */
Packit 6c4009
#define MAX_THRESH 4
Packit 6c4009
Packit 6c4009
/* Stack node declarations used to store unfulfilled partition obligations. */
Packit 6c4009
typedef struct
Packit 6c4009
  {
Packit 6c4009
    char *lo;
Packit 6c4009
    char *hi;
Packit 6c4009
  } stack_node;
Packit 6c4009
Packit 6c4009
/* The next 4 #defines implement a very fast in-line stack abstraction. */
Packit 6c4009
/* The stack needs log (total_elements) entries (we could even subtract
Packit 6c4009
   log(MAX_THRESH)).  Since total_elements has type size_t, we get as
Packit 6c4009
   upper bound for log (total_elements):
Packit 6c4009
   bits per byte (CHAR_BIT) * sizeof(size_t).  */
Packit 6c4009
#define STACK_SIZE	(CHAR_BIT * sizeof(size_t))
Packit 6c4009
#define PUSH(low, high)	((void) ((top->lo = (low)), (top->hi = (high)), ++top))
Packit 6c4009
#define	POP(low, high)	((void) (--top, (low = top->lo), (high = top->hi)))
Packit 6c4009
#define	STACK_NOT_EMPTY	(stack < top)
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Order size using quicksort.  This implementation incorporates
Packit 6c4009
   four optimizations discussed in Sedgewick:
Packit 6c4009
Packit 6c4009
   1. Non-recursive, using an explicit stack of pointer that store the
Packit 6c4009
      next array partition to sort.  To save time, this maximum amount
Packit 6c4009
      of space required to store an array of SIZE_MAX is allocated on the
Packit 6c4009
      stack.  Assuming a 32-bit (64 bit) integer for size_t, this needs
Packit 6c4009
      only 32 * sizeof(stack_node) == 256 bytes (for 64 bit: 1024 bytes).
Packit 6c4009
      Pretty cheap, actually.
Packit 6c4009
Packit 6c4009
   2. Chose the pivot element using a median-of-three decision tree.
Packit 6c4009
      This reduces the probability of selecting a bad pivot value and
Packit 6c4009
      eliminates certain extraneous comparisons.
Packit 6c4009
Packit 6c4009
   3. Only quicksorts TOTAL_ELEMS / MAX_THRESH partitions, leaving
Packit 6c4009
      insertion sort to order the MAX_THRESH items within each partition.
Packit 6c4009
      This is a big win, since insertion sort is faster for small, mostly
Packit 6c4009
      sorted array segments.
Packit 6c4009
Packit 6c4009
   4. The larger of the two sub-partitions is always pushed onto the
Packit 6c4009
      stack first, with the algorithm then concentrating on the
Packit 6c4009
      smaller partition.  This *guarantees* no more than log (total_elems)
Packit 6c4009
      stack size is needed (actually O(1) in this case)!  */
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
_quicksort (void *const pbase, size_t total_elems, size_t size,
Packit 6c4009
	    __compar_d_fn_t cmp, void *arg)
Packit 6c4009
{
Packit 6c4009
  char *base_ptr = (char *) pbase;
Packit 6c4009
Packit 6c4009
  const size_t max_thresh = MAX_THRESH * size;
Packit 6c4009
Packit 6c4009
  if (total_elems == 0)
Packit 6c4009
    /* Avoid lossage with unsigned arithmetic below.  */
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  if (total_elems > MAX_THRESH)
Packit 6c4009
    {
Packit 6c4009
      char *lo = base_ptr;
Packit 6c4009
      char *hi = &lo[size * (total_elems - 1)];
Packit 6c4009
      stack_node stack[STACK_SIZE];
Packit 6c4009
      stack_node *top = stack;
Packit 6c4009
Packit 6c4009
      PUSH (NULL, NULL);
Packit 6c4009
Packit 6c4009
      while (STACK_NOT_EMPTY)
Packit 6c4009
        {
Packit 6c4009
          char *left_ptr;
Packit 6c4009
          char *right_ptr;
Packit 6c4009
Packit 6c4009
	  /* Select median value from among LO, MID, and HI. Rearrange
Packit 6c4009
	     LO and HI so the three values are sorted. This lowers the
Packit 6c4009
	     probability of picking a pathological pivot value and
Packit 6c4009
	     skips a comparison for both the LEFT_PTR and RIGHT_PTR in
Packit 6c4009
	     the while loops. */
Packit 6c4009
Packit 6c4009
	  char *mid = lo + size * ((hi - lo) / size >> 1);
Packit 6c4009
Packit 6c4009
	  if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
Packit 6c4009
	    SWAP (mid, lo, size);
Packit 6c4009
	  if ((*cmp) ((void *) hi, (void *) mid, arg) < 0)
Packit 6c4009
	    SWAP (mid, hi, size);
Packit 6c4009
	  else
Packit 6c4009
	    goto jump_over;
Packit 6c4009
	  if ((*cmp) ((void *) mid, (void *) lo, arg) < 0)
Packit 6c4009
	    SWAP (mid, lo, size);
Packit 6c4009
	jump_over:;
Packit 6c4009
Packit 6c4009
	  left_ptr  = lo + size;
Packit 6c4009
	  right_ptr = hi - size;
Packit 6c4009
Packit 6c4009
	  /* Here's the famous ``collapse the walls'' section of quicksort.
Packit 6c4009
	     Gotta like those tight inner loops!  They are the main reason
Packit 6c4009
	     that this algorithm runs much faster than others. */
Packit 6c4009
	  do
Packit 6c4009
	    {
Packit 6c4009
	      while ((*cmp) ((void *) left_ptr, (void *) mid, arg) < 0)
Packit 6c4009
		left_ptr += size;
Packit 6c4009
Packit 6c4009
	      while ((*cmp) ((void *) mid, (void *) right_ptr, arg) < 0)
Packit 6c4009
		right_ptr -= size;
Packit 6c4009
Packit 6c4009
	      if (left_ptr < right_ptr)
Packit 6c4009
		{
Packit 6c4009
		  SWAP (left_ptr, right_ptr, size);
Packit 6c4009
		  if (mid == left_ptr)
Packit 6c4009
		    mid = right_ptr;
Packit 6c4009
		  else if (mid == right_ptr)
Packit 6c4009
		    mid = left_ptr;
Packit 6c4009
		  left_ptr += size;
Packit 6c4009
		  right_ptr -= size;
Packit 6c4009
		}
Packit 6c4009
	      else if (left_ptr == right_ptr)
Packit 6c4009
		{
Packit 6c4009
		  left_ptr += size;
Packit 6c4009
		  right_ptr -= size;
Packit 6c4009
		  break;
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
	  while (left_ptr <= right_ptr);
Packit 6c4009
Packit 6c4009
          /* Set up pointers for next iteration.  First determine whether
Packit 6c4009
             left and right partitions are below the threshold size.  If so,
Packit 6c4009
             ignore one or both.  Otherwise, push the larger partition's
Packit 6c4009
             bounds on the stack and continue sorting the smaller one. */
Packit 6c4009
Packit 6c4009
          if ((size_t) (right_ptr - lo) <= max_thresh)
Packit 6c4009
            {
Packit 6c4009
              if ((size_t) (hi - left_ptr) <= max_thresh)
Packit 6c4009
		/* Ignore both small partitions. */
Packit 6c4009
                POP (lo, hi);
Packit 6c4009
              else
Packit 6c4009
		/* Ignore small left partition. */
Packit 6c4009
                lo = left_ptr;
Packit 6c4009
            }
Packit 6c4009
          else if ((size_t) (hi - left_ptr) <= max_thresh)
Packit 6c4009
	    /* Ignore small right partition. */
Packit 6c4009
            hi = right_ptr;
Packit 6c4009
          else if ((right_ptr - lo) > (hi - left_ptr))
Packit 6c4009
            {
Packit 6c4009
	      /* Push larger left partition indices. */
Packit 6c4009
              PUSH (lo, right_ptr);
Packit 6c4009
              lo = left_ptr;
Packit 6c4009
            }
Packit 6c4009
          else
Packit 6c4009
            {
Packit 6c4009
	      /* Push larger right partition indices. */
Packit 6c4009
              PUSH (left_ptr, hi);
Packit 6c4009
              hi = right_ptr;
Packit 6c4009
            }
Packit 6c4009
        }
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* Once the BASE_PTR array is partially sorted by quicksort the rest
Packit 6c4009
     is completely sorted using insertion sort, since this is efficient
Packit 6c4009
     for partitions below MAX_THRESH size. BASE_PTR points to the beginning
Packit 6c4009
     of the array to sort, and END_PTR points at the very last element in
Packit 6c4009
     the array (*not* one beyond it!). */
Packit 6c4009
Packit 6c4009
#define min(x, y) ((x) < (y) ? (x) : (y))
Packit 6c4009
Packit 6c4009
  {
Packit 6c4009
    char *const end_ptr = &base_ptr[size * (total_elems - 1)];
Packit 6c4009
    char *tmp_ptr = base_ptr;
Packit 6c4009
    char *thresh = min(end_ptr, base_ptr + max_thresh);
Packit 6c4009
    char *run_ptr;
Packit 6c4009
Packit 6c4009
    /* Find smallest element in first threshold and place it at the
Packit 6c4009
       array's beginning.  This is the smallest array element,
Packit 6c4009
       and the operation speeds up insertion sort's inner loop. */
Packit 6c4009
Packit 6c4009
    for (run_ptr = tmp_ptr + size; run_ptr <= thresh; run_ptr += size)
Packit 6c4009
      if ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
Packit 6c4009
        tmp_ptr = run_ptr;
Packit 6c4009
Packit 6c4009
    if (tmp_ptr != base_ptr)
Packit 6c4009
      SWAP (tmp_ptr, base_ptr, size);
Packit 6c4009
Packit 6c4009
    /* Insertion sort, running from left-hand-side up to right-hand-side.  */
Packit 6c4009
Packit 6c4009
    run_ptr = base_ptr + size;
Packit 6c4009
    while ((run_ptr += size) <= end_ptr)
Packit 6c4009
      {
Packit 6c4009
	tmp_ptr = run_ptr - size;
Packit 6c4009
	while ((*cmp) ((void *) run_ptr, (void *) tmp_ptr, arg) < 0)
Packit 6c4009
	  tmp_ptr -= size;
Packit 6c4009
Packit 6c4009
	tmp_ptr += size;
Packit 6c4009
        if (tmp_ptr != run_ptr)
Packit 6c4009
          {
Packit 6c4009
            char *trav;
Packit 6c4009
Packit 6c4009
	    trav = run_ptr + size;
Packit 6c4009
	    while (--trav >= run_ptr)
Packit 6c4009
              {
Packit 6c4009
                char c = *trav;
Packit 6c4009
                char *hi, *lo;
Packit 6c4009
Packit 6c4009
                for (hi = lo = trav; (lo -= size) >= tmp_ptr; hi = lo)
Packit 6c4009
                  *hi = *lo;
Packit 6c4009
                *hi = c;
Packit 6c4009
              }
Packit 6c4009
          }
Packit 6c4009
      }
Packit 6c4009
  }
Packit 6c4009
}