Blame lib/unistring/array-mergesort.h

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