LCOV - code coverage report
Current view: top level - glib - gqsort.c (source / functions) Coverage Total Hit
Test: unnamed Lines: 97.7 % 133 130
Test Date: 2025-01-07 05:22:06 Functions: 100.0 % 4 4
Branches: - 0 0

             Branch data     Line data    Source code
       1                 :             : /* GLIB - Library of useful routines for C programming
       2                 :             :  * Copyright (C) 1991, 1992, 1996, 1997,1999,2004 Free Software Foundation, Inc.
       3                 :             :  * Copyright (C) 2000 Eazel, Inc.
       4                 :             :  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
       5                 :             :  *
       6                 :             :  * SPDX-License-Identifier: LGPL-2.1-or-later
       7                 :             :  *
       8                 :             :  * This library is free software; you can redistribute it and/or
       9                 :             :  * modify it under the terms of the GNU Lesser General Public
      10                 :             :  * License as published by the Free Software Foundation; either
      11                 :             :  * version 2.1 of the License, or (at your option) any later version.
      12                 :             :  *
      13                 :             :  * This library is distributed in the hope that it will be useful,
      14                 :             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15                 :             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16                 :             :  * Lesser General Public License for more details.
      17                 :             :  *
      18                 :             :  * You should have received a copy of the GNU Lesser General Public
      19                 :             :  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
      20                 :             :  */
      21                 :             : 
      22                 :             : #include "config.h"
      23                 :             : 
      24                 :             : #include <limits.h>
      25                 :             : #include <stdlib.h>
      26                 :             : #include <string.h>
      27                 :             : #include "galloca.h"
      28                 :             : #include "gmem.h"
      29                 :             : 
      30                 :             : #include "gqsort.h"
      31                 :             : 
      32                 :             : #include "gtestutils.h"
      33                 :             : 
      34                 :             : /* This file was originally from stdlib/msort.c in gnu libc, just changed
      35                 :             :    to build inside glib and to not fall back to an unstable quicksort
      36                 :             :    for large arrays. */
      37                 :             : 
      38                 :             : /* An alternative to qsort, with an identical interface.
      39                 :             :    This file is part of the GNU C Library.
      40                 :             :    Copyright (C) 1992,95-97,99,2000,01,02,04,07 Free Software Foundation, Inc.
      41                 :             :    Written by Mike Haertel, September 1988.
      42                 :             : 
      43                 :             :    The GNU C Library is free software; you can redistribute it and/or
      44                 :             :    modify it under the terms of the GNU Lesser General Public
      45                 :             :    License as published by the Free Software Foundation; either
      46                 :             :    version 2.1 of the License, or (at your option) any later version.
      47                 :             : 
      48                 :             :    The GNU C Library is distributed in the hope that it will be useful,
      49                 :             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      50                 :             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      51                 :             :    Lesser General Public License for more details.
      52                 :             : 
      53                 :             :    You should have received a copy of the GNU Lesser General Public
      54                 :             :    License along with the GNU C Library; if not, see
      55                 :             :    <http://www.gnu.org/licenses/>.  */
      56                 :             : 
      57                 :             : 
      58                 :             : struct msort_param
      59                 :             : {
      60                 :             :   size_t s;
      61                 :             :   size_t var;
      62                 :             :   GCompareDataFunc cmp;
      63                 :             :   void *arg;
      64                 :             :   char *t;
      65                 :             : };
      66                 :             : 
      67                 :             : static void msort_with_tmp (const struct msort_param *p, void *b, size_t n);
      68                 :             : 
      69                 :             : static void
      70                 :      327139 : msort_with_tmp (const struct msort_param *p, void *b, size_t n)
      71                 :             : {
      72                 :             :   char *b1, *b2;
      73                 :             :   size_t n1, n2;
      74                 :      327139 :   char *tmp = p->t;
      75                 :      327139 :   const size_t s = p->s;
      76                 :      327139 :   GCompareDataFunc cmp = p->cmp;
      77                 :      327139 :   void *arg = p->arg;
      78                 :             : 
      79                 :      327139 :   if (n <= 1)
      80                 :      164341 :     return;
      81                 :             : 
      82                 :      162798 :   n1 = n / 2;
      83                 :      162798 :   n2 = n - n1;
      84                 :      162798 :   b1 = b;
      85                 :      162798 :   b2 = (char *) b + (n1 * p->s);
      86                 :             : 
      87                 :      162798 :   msort_with_tmp (p, b1, n1);
      88                 :      162798 :   msort_with_tmp (p, b2, n2);
      89                 :             : 
      90                 :      162798 :   switch (p->var)
      91                 :             :     {
      92                 :       99990 :     case 0:
      93                 :     1304411 :       while (n1 > 0 && n2 > 0)
      94                 :             :         {
      95                 :     1204421 :           if ((*cmp) (b1, b2, arg) <= 0)
      96                 :             :             {
      97                 :      591476 :               *(guint32 *) tmp = *(guint32 *) b1;
      98                 :      591476 :               b1 += sizeof (guint32);
      99                 :      591476 :               --n1;
     100                 :             :             }
     101                 :             :           else
     102                 :             :             {
     103                 :      612945 :               *(guint32 *) tmp = *(guint32 *) b2;
     104                 :      612945 :               b2 += sizeof (guint32);
     105                 :      612945 :               --n2;
     106                 :             :             }
     107                 :     1204421 :           tmp += sizeof (guint32);
     108                 :             :         }
     109                 :       99990 :       break;
     110                 :       52512 :     case 1:
     111                 :      659505 :       while (n1 > 0 && n2 > 0)
     112                 :             :         {
     113                 :      606993 :           if ((*cmp) (b1, b2, arg) <= 0)
     114                 :             :             {
     115                 :      298754 :               *(guint64 *) tmp = *(guint64 *) b1;
     116                 :      298754 :               b1 += sizeof (guint64);
     117                 :      298754 :               --n1;
     118                 :             :             }
     119                 :             :           else
     120                 :             :             {
     121                 :      308239 :               *(guint64 *) tmp = *(guint64 *) b2;
     122                 :      308239 :               b2 += sizeof (guint64);
     123                 :      308239 :               --n2;
     124                 :             :             }
     125                 :      606993 :           tmp += sizeof (guint64);
     126                 :             :         }
     127                 :       52512 :       break;
     128                 :          99 :     case 2:
     129                 :         455 :       while (n1 > 0 && n2 > 0)
     130                 :             :         {
     131                 :         356 :           guintptr *tmpl = (guintptr *) tmp;
     132                 :             :           guintptr *bl;
     133                 :             : 
     134                 :         356 :           tmp += s;
     135                 :         356 :           if ((*cmp) (b1, b2, arg) <= 0)
     136                 :             :             {
     137                 :           0 :               bl = (guintptr *) b1;
     138                 :           0 :               b1 += s;
     139                 :           0 :               --n1;
     140                 :             :             }
     141                 :             :           else
     142                 :             :             {
     143                 :         356 :               bl = (guintptr *) b2;
     144                 :         356 :               b2 += s;
     145                 :         356 :               --n2;
     146                 :             :             }
     147                 :        1424 :           while (tmpl < (guintptr *) tmp)
     148                 :        1068 :             *tmpl++ = *bl++;
     149                 :             :         }
     150                 :          99 :       break;
     151                 :        9999 :     case 3:
     152                 :      130539 :       while (n1 > 0 && n2 > 0)
     153                 :             :         {
     154                 :      120540 :           if ((*cmp) (*(const void **) b1, *(const void **) b2, arg) <= 0)
     155                 :             :             {
     156                 :       59217 :               *(void **) tmp = *(void **) b1;
     157                 :       59217 :               b1 += sizeof (void *);
     158                 :       59217 :               --n1;
     159                 :             :             }
     160                 :             :           else
     161                 :             :             {
     162                 :       61323 :               *(void **) tmp = *(void **) b2;
     163                 :       61323 :               b2 += sizeof (void *);
     164                 :       61323 :               --n2;
     165                 :             :             }
     166                 :      120540 :           tmp += sizeof (void *);
     167                 :             :         }
     168                 :        9999 :       break;
     169                 :         198 :     default:
     170                 :        1286 :       while (n1 > 0 && n2 > 0)
     171                 :             :         {
     172                 :        1088 :           if ((*cmp) (b1, b2, arg) <= 0)
     173                 :             :             {
     174                 :         550 :               memcpy (tmp, b1, s);
     175                 :         550 :               tmp += s;
     176                 :         550 :               b1 += s;
     177                 :         550 :               --n1;
     178                 :             :             }
     179                 :             :           else
     180                 :             :             {
     181                 :         538 :               memcpy (tmp, b2, s);
     182                 :         538 :               tmp += s;
     183                 :         538 :               b2 += s;
     184                 :         538 :               --n2;
     185                 :             :             }
     186                 :             :         }
     187                 :         198 :       break;
     188                 :             :     }
     189                 :             : 
     190                 :      162798 :   if (n1 > 0)
     191                 :       72629 :     memcpy (tmp, b1, n1 * s);
     192                 :      162798 :   memcpy (b, p->t, (n - n2) * s);
     193                 :             : }
     194                 :             : 
     195                 :             : 
     196                 :             : static void
     197                 :        1543 : msort_r (void *b, size_t n, size_t s, GCompareDataFunc cmp, void *arg)
     198                 :             : {
     199                 :        1543 :   size_t size = n * s;
     200                 :        1543 :   char *tmp = NULL;
     201                 :             :   struct msort_param p;
     202                 :             : 
     203                 :             :   /* For large object sizes use indirect sorting.  */
     204                 :        1543 :   if (s > 32)
     205                 :           1 :     size = 2 * n * sizeof (void *) + s;
     206                 :             : 
     207                 :        1543 :   if (size < 1024)
     208                 :             :     /* The temporary array is small, so put it on the stack.  */
     209                 :        1526 :     p.t = g_alloca (size);
     210                 :             :   else
     211                 :             :     {
     212                 :             :       /* It's large, so malloc it.  */
     213                 :          17 :       tmp = g_malloc (size);
     214                 :          17 :       p.t = tmp;
     215                 :             :     }
     216                 :             : 
     217                 :        1543 :   p.s = s;
     218                 :        1543 :   p.var = 4;
     219                 :        1543 :   p.cmp = cmp;
     220                 :        1543 :   p.arg = arg;
     221                 :             : 
     222                 :        1543 :   if (s > 32)
     223                 :             :     {
     224                 :             :       /* Indirect sorting.  */
     225                 :           1 :       char *ip = (char *) b;
     226                 :           1 :       void **tp = (void **) (p.t + n * sizeof (void *));
     227                 :           1 :       void **t = tp;
     228                 :           1 :       void *tmp_storage = (void *) (tp + n);
     229                 :             :       char *kp;
     230                 :             :       size_t i;
     231                 :             : 
     232                 :       10001 :       while ((void *) t < tmp_storage)
     233                 :             :         {
     234                 :       10000 :           *t++ = ip;
     235                 :       10000 :           ip += s;
     236                 :             :         }
     237                 :           1 :       p.s = sizeof (void *);
     238                 :           1 :       p.var = 3;
     239                 :           1 :       msort_with_tmp (&p, p.t + n * sizeof (void *), n);
     240                 :             : 
     241                 :             :       /* tp[0] .. tp[n - 1] is now sorted, copy around entries of
     242                 :             :          the original array.  Knuth vol. 3 (2nd ed.) exercise 5.2-10.  */
     243                 :       10001 :       for (i = 0, ip = (char *) b; i < n; i++, ip += s)
     244                 :       10000 :         if ((kp = tp[i]) != ip)
     245                 :             :           {
     246                 :           5 :             size_t j = i;
     247                 :           5 :             char *jp = ip;
     248                 :           5 :             memcpy (tmp_storage, ip, s);
     249                 :             : 
     250                 :             :             do
     251                 :             :               {
     252                 :        9993 :                 size_t k = (kp - (char *) b) / s;
     253                 :        9993 :                 tp[j] = jp;
     254                 :        9993 :                 memcpy (jp, kp, s);
     255                 :        9993 :                 j = k;
     256                 :        9993 :                 jp = kp;
     257                 :        9993 :                 kp = tp[k];
     258                 :             :               }
     259                 :        9993 :             while (kp != ip);
     260                 :             : 
     261                 :           5 :             tp[j] = jp;
     262                 :           5 :             memcpy (jp, tmp_storage, s);
     263                 :             :           }
     264                 :             :     }
     265                 :             :   else
     266                 :             :     {
     267                 :        1542 :       if ((s & (sizeof (guint32) - 1)) == 0
     268                 :        1540 :           && (gsize) (guintptr) b % G_ALIGNOF(guint32) == 0)
     269                 :             :         {
     270                 :        1540 :           if (s == sizeof (guint32))
     271                 :          11 :             p.var = 0;
     272                 :        1529 :           else if (s == sizeof (guint64)
     273                 :        1528 :                    && (gsize) (guintptr) b % G_ALIGNOF(guint64) == 0)
     274                 :        1528 :             p.var = 1;
     275                 :           1 :           else if ((s & (sizeof (void *) - 1)) == 0
     276                 :           1 :                    && (gsize) (guintptr) b % G_ALIGNOF(void *) == 0)
     277                 :           1 :             p.var = 2;
     278                 :             :         }
     279                 :        1542 :       msort_with_tmp (&p, b, n);
     280                 :             :     }
     281                 :        1543 :   g_free (tmp);
     282                 :        1543 : }
     283                 :             : 
     284                 :             : /**
     285                 :             :  * g_qsort_with_data:
     286                 :             :  * @pbase: (not nullable): start of array to sort
     287                 :             :  * @total_elems: elements in the array
     288                 :             :  * @size: size of each element
     289                 :             :  * @compare_func: (scope call): function to compare elements
     290                 :             :  * @user_data: data to pass to @compare_func
     291                 :             :  *
     292                 :             :  * This is just like the standard C [`qsort()`](man:qsort(3)) function, but
     293                 :             :  * the comparison routine accepts a user data argument
     294                 :             :  * (like [`qsort_r()`](man:qsort_r(3))).
     295                 :             :  *
     296                 :             :  * Unlike `qsort()`, this is guaranteed to be a stable sort (since GLib 2.32).
     297                 :             :  *
     298                 :             :  * Deprecated: 2.82: `total_elems` is too small to represent larger arrays; use
     299                 :             :  *   [func@GLib.sort_array] instead
     300                 :             :  */
     301                 :             : void
     302                 :           1 : g_qsort_with_data (gconstpointer    pbase,
     303                 :             :                    gint             total_elems,
     304                 :             :                    gsize            size,
     305                 :             :                    GCompareDataFunc compare_func,
     306                 :             :                    gpointer         user_data)
     307                 :             : {
     308                 :           1 :   g_sort_array (pbase, total_elems, size, compare_func, user_data);
     309                 :           1 : }
     310                 :             : 
     311                 :             : /**
     312                 :             :  * g_sort_array:
     313                 :             :  * @array: (not nullable) (array length=n_elements): start of array to sort
     314                 :             :  * @n_elements: number of elements in the array
     315                 :             :  * @element_size: size of each element
     316                 :             :  * @compare_func: (scope call): function to compare elements
     317                 :             :  * @user_data: data to pass to @compare_func
     318                 :             :  *
     319                 :             :  * This is just like the standard C [`qsort()`](man:qsort(3)) function, but
     320                 :             :  * the comparison routine accepts a user data argument
     321                 :             :  * (like [`qsort_r()`](man:qsort_r(3))).
     322                 :             :  *
     323                 :             :  * Unlike `qsort()`, this is guaranteed to be a stable sort.
     324                 :             :  *
     325                 :             :  * Since: 2.82
     326                 :             :  */
     327                 :             : void
     328                 :        1543 : g_sort_array (const void       *array,
     329                 :             :               size_t            n_elements,
     330                 :             :               size_t            element_size,
     331                 :             :               GCompareDataFunc  compare_func,
     332                 :             :               void             *user_data)
     333                 :             : {
     334                 :        1543 :   msort_r ((void *) array, n_elements, element_size, compare_func, user_data);
     335                 :        1543 : }
        

Generated by: LCOV version 2.0-1