Coverage Report

Created: 2026-01-09 07:21

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