Blame lib/unistring/array-mergesort.h

Packit 549fdc
/* Stable-sorting of an array using mergesort.
Packit 549fdc
   Copyright (C) 2009-2016 Free Software Foundation, Inc.
Packit 549fdc
   Written by Bruno Haible <bruno@clisp.org>, 2009.
Packit 549fdc
Packit 549fdc
   This program is free software: you can redistribute it and/or modify it
Packit 549fdc
   under the terms of either:
Packit 549fdc
Packit 549fdc
    * the GNU Lesser General Public License as published
Packit 549fdc
   by the Free Software Foundation; either version 3 of the License, or
Packit 549fdc
   (at your option) any later version.
Packit 549fdc
Packit 549fdc
   or
Packit 549fdc
Packit 549fdc
   * the GNU General Public License as published by the Free
Packit 549fdc
   Software Foundation; either version 2 of the License, or
Packit 549fdc
   (at your option) any later version.
Packit 549fdc
Packit 549fdc
   or both in parallel, as here.
Packit 549fdc
Packit 549fdc
   This program is distributed in the hope that it will be useful,
Packit 549fdc
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 549fdc
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 549fdc
   Lesser General Public License for more details.
Packit 549fdc
Packit 549fdc
   You should have received a copy of the GNU Lesser General Public License
Packit 549fdc
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
Packit 549fdc
Packit 549fdc
/* This file implements stable sorting of an array, using the mergesort
Packit 549fdc
   algorithm.
Packit 549fdc
   Worst-case running time for an array of length N is O(N log N).
Packit 549fdc
   Unlike the mpsort module, the algorithm here attempts to minimize not
Packit 549fdc
   only the number of comparisons, but also the number of copying operations.
Packit 549fdc
Packit 549fdc
   Before including this file, you need to define
Packit 549fdc
     ELEMENT      The type of every array element.
Packit 549fdc
     COMPARE      A two-argument macro that takes two 'const ELEMENT *'
Packit 549fdc
                  pointers and returns a negative, zero, or positive 'int'
Packit 549fdc
                  value if the element pointed to by the first argument is,
Packit 549fdc
                  respectively, less, equal, or greater than the element
Packit 549fdc
                  pointed to by the second argument.
Packit 549fdc
     STATIC       The storage class of the functions being defined.
Packit 549fdc
   Before including this file, you also need to include:
Packit 549fdc
     #include <stddef.h>
Packit 549fdc
 */
Packit 549fdc
Packit 549fdc
/* Merge the sorted arrays src1[0..n1-1] and src2[0..n2-1] into
Packit 549fdc
   dst[0..n1+n2-1].  In case of ambiguity, put the elements of src1
Packit 549fdc
   before the elements of src2.
Packit 549fdc
   n1 and n2 must be > 0.
Packit 549fdc
   The arrays src1 and src2 must not overlap the dst array, except that
Packit 549fdc
   src1 may be dst[n2..n1+n2-1], or src2 may be dst[n1..n1+n2-1].  */
Packit 549fdc
static void
Packit 549fdc
merge (const ELEMENT *src1, size_t n1,
Packit 549fdc
       const ELEMENT *src2, size_t n2,
Packit 549fdc
       ELEMENT *dst)
Packit 549fdc
{
Packit 549fdc
  for (;;) /* while (n1 > 0 && n2 > 0) */
Packit 549fdc
    {
Packit 549fdc
      if (COMPARE (src1, src2) <= 0)
Packit 549fdc
        {
Packit 549fdc
          *dst++ = *src1++;
Packit 549fdc
          n1--;
Packit 549fdc
          if (n1 == 0)
Packit 549fdc
            break;
Packit 549fdc
        }
Packit 549fdc
      else
Packit 549fdc
        {
Packit 549fdc
          *dst++ = *src2++;
Packit 549fdc
          n2--;
Packit 549fdc
          if (n2 == 0)
Packit 549fdc
            break;
Packit 549fdc
        }
Packit 549fdc
    }
Packit 549fdc
  /* Here n1 == 0 || n2 == 0 but also n1 > 0 || n2 > 0.  */
Packit 549fdc
  if (n1 > 0)
Packit 549fdc
    {
Packit 549fdc
      if (dst != src1)
Packit 549fdc
        do
Packit 549fdc
          {
Packit 549fdc
            *dst++ = *src1++;
Packit 549fdc
            n1--;
Packit 549fdc
          }
Packit 549fdc
        while (n1 > 0);
Packit 549fdc
    }
Packit 549fdc
  else /* n2 > 0 */
Packit 549fdc
    {
Packit 549fdc
      if (dst != src2)
Packit 549fdc
        do
Packit 549fdc
          {
Packit 549fdc
            *dst++ = *src2++;
Packit 549fdc
            n2--;
Packit 549fdc
          }
Packit 549fdc
        while (n2 > 0);
Packit 549fdc
    }
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* Sort src[0..n-1] into dst[0..n-1], using tmp[0..n/2-1] as temporary
Packit 549fdc
   (scratch) storage.
Packit 549fdc
   The arrays src, dst, tmp must not overlap.  */
Packit 549fdc
STATIC void
Packit 549fdc
merge_sort_fromto (const ELEMENT *src, ELEMENT *dst, size_t n, ELEMENT *tmp)
Packit 549fdc
{
Packit 549fdc
  switch (n)
Packit 549fdc
    {
Packit 549fdc
    case 0:
Packit 549fdc
      return;
Packit 549fdc
    case 1:
Packit 549fdc
      /* Nothing to do.  */
Packit 549fdc
      dst[0] = src[0];
Packit 549fdc
      return;
Packit 549fdc
    case 2:
Packit 549fdc
      /* Trivial case.  */
Packit 549fdc
      if (COMPARE (&src[0], &src[1]) <= 0)
Packit 549fdc
        {
Packit 549fdc
          /* src[0] <= src[1] */
Packit 549fdc
          dst[0] = src[0];
Packit 549fdc
          dst[1] = src[1];
Packit 549fdc
        }
Packit 549fdc
      else
Packit 549fdc
        {
Packit 549fdc
          dst[0] = src[1];
Packit 549fdc
          dst[1] = src[0];
Packit 549fdc
        }
Packit 549fdc
      break;
Packit 549fdc
    case 3:
Packit 549fdc
      /* Simple case.  */
Packit 549fdc
      if (COMPARE (&src[0], &src[1]) <= 0)
Packit 549fdc
        {
Packit 549fdc
          if (COMPARE (&src[1], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[0] <= src[1] <= src[2] */
Packit 549fdc
              dst[0] = src[0];
Packit 549fdc
              dst[1] = src[1];
Packit 549fdc
              dst[2] = src[2];
Packit 549fdc
            }
Packit 549fdc
          else if (COMPARE (&src[0], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[0] <= src[2] < src[1] */
Packit 549fdc
              dst[0] = src[0];
Packit 549fdc
              dst[1] = src[2];
Packit 549fdc
              dst[2] = src[1];
Packit 549fdc
            }
Packit 549fdc
          else
Packit 549fdc
            {
Packit 549fdc
              /* src[2] < src[0] <= src[1] */
Packit 549fdc
              dst[0] = src[2];
Packit 549fdc
              dst[1] = src[0];
Packit 549fdc
              dst[2] = src[1];
Packit 549fdc
            }
Packit 549fdc
        }
Packit 549fdc
      else
Packit 549fdc
        {
Packit 549fdc
          if (COMPARE (&src[0], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[1] < src[0] <= src[2] */
Packit 549fdc
              dst[0] = src[1];
Packit 549fdc
              dst[1] = src[0];
Packit 549fdc
              dst[2] = src[2];
Packit 549fdc
            }
Packit 549fdc
          else if (COMPARE (&src[1], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[1] <= src[2] < src[0] */
Packit 549fdc
              dst[0] = src[1];
Packit 549fdc
              dst[1] = src[2];
Packit 549fdc
              dst[2] = src[0];
Packit 549fdc
            }
Packit 549fdc
          else
Packit 549fdc
            {
Packit 549fdc
              /* src[2] < src[1] < src[0] */
Packit 549fdc
              dst[0] = src[2];
Packit 549fdc
              dst[1] = src[1];
Packit 549fdc
              dst[2] = src[0];
Packit 549fdc
            }
Packit 549fdc
        }
Packit 549fdc
      break;
Packit 549fdc
    default:
Packit 549fdc
      {
Packit 549fdc
        size_t n1 = n / 2;
Packit 549fdc
        size_t n2 = (n + 1) / 2;
Packit 549fdc
        /* Note: n1 + n2 = n, n1 <= n2.  */
Packit 549fdc
        /* Sort src[n1..n-1] into dst[n1..n-1], scratching tmp[0..n2/2-1].  */
Packit 549fdc
        merge_sort_fromto (src + n1, dst + n1, n2, tmp);
Packit 549fdc
        /* Sort src[0..n1-1] into tmp[0..n1-1], scratching dst[0..n1-1].  */
Packit 549fdc
        merge_sort_fromto (src, tmp, n1, dst);
Packit 549fdc
        /* Merge the two half results.  */
Packit 549fdc
        merge (tmp, n1, dst + n1, n2, dst);
Packit 549fdc
      }
Packit 549fdc
      break;
Packit 549fdc
    }
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
/* Sort src[0..n-1], using tmp[0..n-1] as temporary (scratch) storage.
Packit 549fdc
   The arrays src, tmp must not overlap. */
Packit 549fdc
STATIC void
Packit 549fdc
merge_sort_inplace (ELEMENT *src, size_t n, ELEMENT *tmp)
Packit 549fdc
{
Packit 549fdc
  switch (n)
Packit 549fdc
    {
Packit 549fdc
    case 0:
Packit 549fdc
    case 1:
Packit 549fdc
      /* Nothing to do.  */
Packit 549fdc
      return;
Packit 549fdc
    case 2:
Packit 549fdc
      /* Trivial case.  */
Packit 549fdc
      if (COMPARE (&src[0], &src[1]) <= 0)
Packit 549fdc
        {
Packit 549fdc
          /* src[0] <= src[1] */
Packit 549fdc
        }
Packit 549fdc
      else
Packit 549fdc
        {
Packit 549fdc
          ELEMENT t = src[0];
Packit 549fdc
          src[0] = src[1];
Packit 549fdc
          src[1] = t;
Packit 549fdc
        }
Packit 549fdc
      break;
Packit 549fdc
    case 3:
Packit 549fdc
      /* Simple case.  */
Packit 549fdc
      if (COMPARE (&src[0], &src[1]) <= 0)
Packit 549fdc
        {
Packit 549fdc
          if (COMPARE (&src[1], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[0] <= src[1] <= src[2] */
Packit 549fdc
            }
Packit 549fdc
          else if (COMPARE (&src[0], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[0] <= src[2] < src[1] */
Packit 549fdc
              ELEMENT t = src[1];
Packit 549fdc
              src[1] = src[2];
Packit 549fdc
              src[2] = t;
Packit 549fdc
            }
Packit 549fdc
          else
Packit 549fdc
            {
Packit 549fdc
              /* src[2] < src[0] <= src[1] */
Packit 549fdc
              ELEMENT t = src[0];
Packit 549fdc
              src[0] = src[2];
Packit 549fdc
              src[2] = src[1];
Packit 549fdc
              src[1] = t;
Packit 549fdc
            }
Packit 549fdc
        }
Packit 549fdc
      else
Packit 549fdc
        {
Packit 549fdc
          if (COMPARE (&src[0], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[1] < src[0] <= src[2] */
Packit 549fdc
              ELEMENT t = src[0];
Packit 549fdc
              src[0] = src[1];
Packit 549fdc
              src[1] = t;
Packit 549fdc
            }
Packit 549fdc
          else if (COMPARE (&src[1], &src[2]) <= 0)
Packit 549fdc
            {
Packit 549fdc
              /* src[1] <= src[2] < src[0] */
Packit 549fdc
              ELEMENT t = src[0];
Packit 549fdc
              src[0] = src[1];
Packit 549fdc
              src[1] = src[2];
Packit 549fdc
              src[2] = t;
Packit 549fdc
            }
Packit 549fdc
          else
Packit 549fdc
            {
Packit 549fdc
              /* src[2] < src[1] < src[0] */
Packit 549fdc
              ELEMENT t = src[0];
Packit 549fdc
              src[0] = src[2];
Packit 549fdc
              src[2] = t;
Packit 549fdc
            }
Packit 549fdc
        }
Packit 549fdc
      break;
Packit 549fdc
    default:
Packit 549fdc
      {
Packit 549fdc
        size_t n1 = n / 2;
Packit 549fdc
        size_t n2 = (n + 1) / 2;
Packit 549fdc
        /* Note: n1 + n2 = n, n1 <= n2.  */
Packit 549fdc
        /* Sort src[n1..n-1], scratching tmp[0..n2-1].  */
Packit 549fdc
        merge_sort_inplace (src + n1, n2, tmp);
Packit 549fdc
        /* Sort src[0..n1-1] into tmp[0..n1-1], scratching tmp[n1..2*n1-1].  */
Packit 549fdc
        merge_sort_fromto (src, tmp, n1, tmp + n1);
Packit 549fdc
        /* Merge the two half results.  */
Packit 549fdc
        merge (tmp, n1, src + n1, n2, src);
Packit 549fdc
      }
Packit 549fdc
      break;
Packit 549fdc
    }
Packit 549fdc
}
Packit 549fdc
Packit 549fdc
#undef ELEMENT
Packit 549fdc
#undef COMPARE
Packit 549fdc
#undef STATIC