Blame stdlib/qsort.c

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