Blame lib/mpsort.c

Packit Service 2723c6
/* Sort a vector of pointers to data.
Packit Service 2723c6
Packit Service 2723c6
   Copyright (C) 2007, 2009-2018 Free Software Foundation, Inc.
Packit Service 2723c6
Packit Service 2723c6
   This program is free software: you can redistribute it and/or modify
Packit Service 2723c6
   it under the terms of the GNU General Public License as published by
Packit Service 2723c6
   the Free Software Foundation; either version 3 of the License, or
Packit Service 2723c6
   (at your option) any later version.
Packit Service 2723c6
Packit Service 2723c6
   This program is distributed in the hope that it will be useful,
Packit Service 2723c6
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 2723c6
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service 2723c6
   GNU General Public License for more details.
Packit Service 2723c6
Packit Service 2723c6
   You should have received a copy of the GNU General Public License
Packit Service 2723c6
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Packit Service 2723c6
Packit Service 2723c6
/* Written by Paul Eggert.  */
Packit Service 2723c6
Packit Service 2723c6
#include <config.h>
Packit Service 2723c6
Packit Service 2723c6
#include "mpsort.h"
Packit Service 2723c6
Packit Service 2723c6
#include <string.h>
Packit Service 2723c6
Packit Service 2723c6
/* The type of qsort-style comparison functions.  */
Packit Service 2723c6
Packit Service 2723c6
typedef int (*comparison_function) (void const *, void const *);
Packit Service 2723c6
Packit Service 2723c6
static void mpsort_with_tmp (void const **restrict, size_t,
Packit Service 2723c6
                             void const **restrict, comparison_function);
Packit Service 2723c6
Packit Service 2723c6
/* Sort a vector BASE containing N pointers, placing the sorted array
Packit Service 2723c6
   into TMP.  Compare pointers with CMP.  N must be at least 2.  */
Packit Service 2723c6
Packit Service 2723c6
static void
Packit Service 2723c6
mpsort_into_tmp (void const **restrict base, size_t n,
Packit Service 2723c6
                 void const **restrict tmp,
Packit Service 2723c6
                 comparison_function cmp)
Packit Service 2723c6
{
Packit Service 2723c6
  size_t n1 = n / 2;
Packit Service 2723c6
  size_t n2 = n - n1;
Packit Service 2723c6
  size_t a = 0;
Packit Service 2723c6
  size_t alim = n1;
Packit Service 2723c6
  size_t b = n1;
Packit Service 2723c6
  size_t blim = n;
Packit Service 2723c6
  void const *ba;
Packit Service 2723c6
  void const *bb;
Packit Service 2723c6
Packit Service 2723c6
  mpsort_with_tmp (base + n1, n2, tmp, cmp);
Packit Service 2723c6
  mpsort_with_tmp (base, n1, tmp, cmp);
Packit Service 2723c6
Packit Service 2723c6
  ba = base[a];
Packit Service 2723c6
  bb = base[b];
Packit Service 2723c6
Packit Service 2723c6
  for (;;)
Packit Service 2723c6
    if (cmp (ba, bb) <= 0)
Packit Service 2723c6
      {
Packit Service 2723c6
        *tmp++ = ba;
Packit Service 2723c6
        a++;
Packit Service 2723c6
        if (a == alim)
Packit Service 2723c6
          {
Packit Service 2723c6
            a = b;
Packit Service 2723c6
            alim = blim;
Packit Service 2723c6
            break;
Packit Service 2723c6
          }
Packit Service 2723c6
        ba = base[a];
Packit Service 2723c6
      }
Packit Service 2723c6
    else
Packit Service 2723c6
      {
Packit Service 2723c6
        *tmp++ = bb;
Packit Service 2723c6
        b++;
Packit Service 2723c6
        if (b == blim)
Packit Service 2723c6
          break;
Packit Service 2723c6
        bb = base[b];
Packit Service 2723c6
      }
Packit Service 2723c6
Packit Service 2723c6
  memcpy (tmp, base + a, (alim - a) * sizeof *base);
Packit Service 2723c6
}
Packit Service 2723c6
Packit Service 2723c6
/* Sort a vector BASE containing N pointers, in place.  Use TMP
Packit Service 2723c6
   (containing N / 2 pointers) for temporary storage.  Compare
Packit Service 2723c6
   pointers with CMP.  */
Packit Service 2723c6
Packit Service 2723c6
static void
Packit Service 2723c6
mpsort_with_tmp (void const **restrict base, size_t n,
Packit Service 2723c6
                 void const **restrict tmp,
Packit Service 2723c6
                 comparison_function cmp)
Packit Service 2723c6
{
Packit Service 2723c6
  if (n <= 2)
Packit Service 2723c6
    {
Packit Service 2723c6
      if (n == 2)
Packit Service 2723c6
        {
Packit Service 2723c6
          void const *p0 = base[0];
Packit Service 2723c6
          void const *p1 = base[1];
Packit Service 2723c6
          if (! (cmp (p0, p1) <= 0))
Packit Service 2723c6
            {
Packit Service 2723c6
              base[0] = p1;
Packit Service 2723c6
              base[1] = p0;
Packit Service 2723c6
            }
Packit Service 2723c6
        }
Packit Service 2723c6
    }
Packit Service 2723c6
  else
Packit Service 2723c6
    {
Packit Service 2723c6
      size_t n1 = n / 2;
Packit Service 2723c6
      size_t n2 = n - n1;
Packit Service 2723c6
      size_t i;
Packit Service 2723c6
      size_t t = 0;
Packit Service 2723c6
      size_t tlim = n1;
Packit Service 2723c6
      size_t b = n1;
Packit Service 2723c6
      size_t blim = n;
Packit Service 2723c6
      void const *bb;
Packit Service 2723c6
      void const *tt;
Packit Service 2723c6
Packit Service 2723c6
      mpsort_with_tmp (base + n1, n2, tmp, cmp);
Packit Service 2723c6
Packit Service 2723c6
      if (n1 < 2)
Packit Service 2723c6
        tmp[0] = base[0];
Packit Service 2723c6
      else
Packit Service 2723c6
        mpsort_into_tmp (base, n1, tmp, cmp);
Packit Service 2723c6
Packit Service 2723c6
      tt = tmp[t];
Packit Service 2723c6
      bb = base[b];
Packit Service 2723c6
Packit Service 2723c6
      for (i = 0; ; )
Packit Service 2723c6
        if (cmp (tt, bb) <= 0)
Packit Service 2723c6
          {
Packit Service 2723c6
            base[i++] = tt;
Packit Service 2723c6
            t++;
Packit Service 2723c6
            if (t == tlim)
Packit Service 2723c6
              break;
Packit Service 2723c6
            tt = tmp[t];
Packit Service 2723c6
          }
Packit Service 2723c6
        else
Packit Service 2723c6
          {
Packit Service 2723c6
            base[i++] = bb;
Packit Service 2723c6
            b++;
Packit Service 2723c6
            if (b == blim)
Packit Service 2723c6
              {
Packit Service 2723c6
                memcpy (base + i, tmp + t, (tlim - t) * sizeof *base);
Packit Service 2723c6
                break;
Packit Service 2723c6
              }
Packit Service 2723c6
            bb = base[b];
Packit Service 2723c6
          }
Packit Service 2723c6
    }
Packit Service 2723c6
}
Packit Service 2723c6
Packit Service 2723c6
/* Sort a vector BASE containing N pointers, in place.  BASE must
Packit Service 2723c6
   contain enough storage to hold N + N / 2 vectors; the trailing
Packit Service 2723c6
   vectors are used for temporaries.  Compare pointers with CMP.  */
Packit Service 2723c6
Packit Service 2723c6
void
Packit Service 2723c6
mpsort (void const **base, size_t n, comparison_function cmp)
Packit Service 2723c6
{
Packit Service 2723c6
  mpsort_with_tmp (base, n, base + n, cmp);
Packit Service 2723c6
}