Coverage Report

Created: 2026-08-14 07:19

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/gl/gl_array_list.c
Line
Count
Source
1
/* Sequential list data type implemented by an array.
2
   Copyright (C) 2006-2026 Free Software Foundation, Inc.
3
   Written by Bruno Haible <bruno@clisp.org>, 2006.
4
5
   This file is free software: you can redistribute it and/or modify
6
   it under the terms of the GNU Lesser General Public License as
7
   published by the Free Software Foundation; either version 2.1 of the
8
   License, or (at your option) any later version.
9
10
   This file is distributed in the hope that it will be useful,
11
   but WITHOUT ANY WARRANTY; without even the implied warranty of
12
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
   GNU Lesser General Public License for more details.
14
15
   You should have received a copy of the GNU Lesser General Public License
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
17
18
#include <config.h>
19
20
/* Specification.  */
21
#include "gl_array_list.h"
22
23
#include <stdint.h>
24
#include <stdlib.h>
25
/* Get memcpy.  */
26
#include <string.h>
27
28
/* Checked size_t computations.  */
29
#include "xsize.h"
30
31
/* -------------------------- gl_list_t Data Type -------------------------- */
32
33
/* Concrete gl_list_impl type, valid for this file only.  */
34
struct gl_list_impl
35
{
36
  struct gl_list_impl_base base;
37
  size_t count;
38
  /* An array of ALLOCATED elements, of which the first COUNT are used.
39
     0 <= COUNT <= ALLOCATED.  */
40
  const void **elements
41
    _GL_ATTRIBUTE_COUNTED_BY (count);
42
  size_t allocated;
43
};
44
45
/* struct gl_list_node_impl doesn't exist here.  The pointers are actually
46
   indices + 1.  */
47
0
#define INDEX_TO_NODE(index) (gl_list_node_t)(uintptr_t)(size_t)((index) + 1)
48
0
#define NODE_TO_INDEX(node) ((uintptr_t)(node) - 1)
49
50
static gl_list_t
51
gl_array_nx_create_empty (gl_list_implementation_t implementation,
52
                          gl_listelement_equals_fn equals_fn,
53
                          gl_listelement_hashcode_fn hashcode_fn,
54
                          gl_listelement_dispose_fn dispose_fn,
55
                          bool allow_duplicates)
56
0
{
57
0
  struct gl_list_impl *list =
58
0
    (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
59
60
0
  if (list == NULL)
61
0
    return NULL;
62
63
0
  list->base.vtable = implementation;
64
0
  list->base.equals_fn = equals_fn;
65
0
  list->base.hashcode_fn = hashcode_fn;
66
0
  list->base.dispose_fn = dispose_fn;
67
0
  list->base.allow_duplicates = allow_duplicates;
68
0
  list->elements = NULL;
69
0
  list->count = 0;
70
0
  list->allocated = 0;
71
72
0
  return list;
73
0
}
74
75
static gl_list_t
76
gl_array_nx_create (gl_list_implementation_t implementation,
77
                    gl_listelement_equals_fn equals_fn,
78
                    gl_listelement_hashcode_fn hashcode_fn,
79
                    gl_listelement_dispose_fn dispose_fn,
80
                    bool allow_duplicates,
81
                    size_t count, const void **contents)
82
0
{
83
0
  struct gl_list_impl *list =
84
0
    (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
85
86
0
  if (list == NULL)
87
0
    return NULL;
88
89
0
  list->base.vtable = implementation;
90
0
  list->base.equals_fn = equals_fn;
91
0
  list->base.hashcode_fn = hashcode_fn;
92
0
  list->base.dispose_fn = dispose_fn;
93
0
  list->base.allow_duplicates = allow_duplicates;
94
0
  if (count > 0)
95
0
    {
96
0
      if (size_overflow_p (xtimes (count, sizeof (const void *))))
97
0
        goto fail;
98
0
      list->elements = (const void **) malloc (count * sizeof (const void *));
99
0
      if (list->elements == NULL)
100
0
        goto fail;
101
0
      memcpy (list->elements, contents, count * sizeof (const void *));
102
0
    }
103
0
  else
104
0
    list->elements = NULL;
105
0
  list->count = count;
106
0
  list->allocated = count;
107
108
0
  return list;
109
110
0
 fail:
111
0
  free (list);
112
0
  return NULL;
113
0
}
114
115
static size_t _GL_ATTRIBUTE_PURE
116
gl_array_size (gl_list_t list)
117
0
{
118
0
  return list->count;
119
0
}
120
121
static const void * _GL_ATTRIBUTE_PURE
122
gl_array_node_value (gl_list_t list, gl_list_node_t node)
123
0
{
124
0
  uintptr_t index = NODE_TO_INDEX (node);
125
0
  if (!(index < list->count))
126
    /* Invalid argument.  */
127
0
    abort ();
128
0
  return list->elements[index];
129
0
}
130
131
static int
132
gl_array_node_nx_set_value (gl_list_t list, gl_list_node_t node,
133
                            const void *elt)
134
0
{
135
0
  uintptr_t index = NODE_TO_INDEX (node);
136
0
  if (!(index < list->count))
137
    /* Invalid argument.  */
138
0
    abort ();
139
0
  list->elements[index] = elt;
140
0
  return 0;
141
0
}
142
143
static gl_list_node_t _GL_ATTRIBUTE_PURE
144
gl_array_next_node (gl_list_t list, gl_list_node_t node)
145
0
{
146
0
  uintptr_t index = NODE_TO_INDEX (node);
147
0
  if (!(index < list->count))
148
    /* Invalid argument.  */
149
0
    abort ();
150
0
  index++;
151
0
  if (index < list->count)
152
0
    return INDEX_TO_NODE (index);
153
0
  else
154
0
    return NULL;
155
0
}
156
157
static gl_list_node_t _GL_ATTRIBUTE_PURE
158
gl_array_previous_node (gl_list_t list, gl_list_node_t node)
159
0
{
160
0
  uintptr_t index = NODE_TO_INDEX (node);
161
0
  if (!(index < list->count))
162
    /* Invalid argument.  */
163
0
    abort ();
164
0
  if (index > 0)
165
0
    return INDEX_TO_NODE (index - 1);
166
0
  else
167
0
    return NULL;
168
0
}
169
170
static gl_list_node_t _GL_ATTRIBUTE_PURE
171
gl_array_first_node (gl_list_t list)
172
0
{
173
0
  if (list->count > 0)
174
0
    return INDEX_TO_NODE (0);
175
0
  else
176
0
    return NULL;
177
0
}
178
179
static gl_list_node_t _GL_ATTRIBUTE_PURE
180
gl_array_last_node (gl_list_t list)
181
0
{
182
0
  if (list->count > 0)
183
0
    return INDEX_TO_NODE (list->count - 1);
184
0
  else
185
0
    return NULL;
186
0
}
187
188
static const void * _GL_ATTRIBUTE_PURE
189
gl_array_get_at (gl_list_t list, size_t position)
190
0
{
191
0
  size_t count = list->count;
192
193
0
  if (!(position < count))
194
    /* Invalid argument.  */
195
0
    abort ();
196
0
  return list->elements[position];
197
0
}
198
199
static gl_list_node_t
200
gl_array_nx_set_at (gl_list_t list, size_t position, const void *elt)
201
0
{
202
0
  size_t count = list->count;
203
204
0
  if (!(position < count))
205
    /* Invalid argument.  */
206
0
    abort ();
207
0
  list->elements[position] = elt;
208
0
  return INDEX_TO_NODE (position);
209
0
}
210
211
static size_t _GL_ATTRIBUTE_PURE
212
gl_array_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
213
                          const void *elt)
214
0
{
215
0
  size_t count = list->count;
216
217
0
  if (!(start_index <= end_index && end_index <= count))
218
    /* Invalid arguments.  */
219
0
    abort ();
220
221
0
  if (start_index < end_index)
222
0
    {
223
0
      gl_listelement_equals_fn equals = list->base.equals_fn;
224
0
      if (equals != NULL)
225
0
        {
226
0
          for (size_t i = start_index;;)
227
0
            {
228
0
              if (equals (elt, list->elements[i]))
229
0
                return i;
230
0
              i++;
231
0
              if (i == end_index)
232
0
                break;
233
0
            }
234
0
        }
235
0
      else
236
0
        {
237
0
          for (size_t i = start_index;;)
238
0
            {
239
0
              if (elt == list->elements[i])
240
0
                return i;
241
0
              i++;
242
0
              if (i == end_index)
243
0
                break;
244
0
            }
245
0
        }
246
0
    }
247
0
  return (size_t)(-1);
248
0
}
249
250
static gl_list_node_t _GL_ATTRIBUTE_PURE
251
gl_array_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
252
                         const void *elt)
253
0
{
254
0
  size_t index = gl_array_indexof_from_to (list, start_index, end_index, elt);
255
0
  return INDEX_TO_NODE (index);
256
0
}
257
258
/* Ensure that list->allocated > list->count.
259
   Return 0 upon success, -1 upon out-of-memory.  */
260
static int
261
grow (gl_list_t list)
262
0
{
263
0
  size_t new_allocated = xtimes (list->allocated, 2);
264
0
  new_allocated = xsum (new_allocated, 1);
265
0
  size_t memory_size = xtimes (new_allocated, sizeof (const void *));
266
0
  if (size_overflow_p (memory_size))
267
    /* Overflow, would lead to out of memory.  */
268
0
    return -1;
269
0
  const void **memory = (const void **) realloc (list->elements, memory_size);
270
0
  if (memory == NULL)
271
    /* Out of memory.  */
272
0
    return -1;
273
0
  list->elements = memory;
274
0
  list->allocated = new_allocated;
275
0
  return 0;
276
0
}
277
278
static gl_list_node_t
279
gl_array_nx_add_first (gl_list_t list, const void *elt)
280
0
{
281
0
  size_t count = list->count;
282
283
0
  if (count == list->allocated)
284
0
    if (grow (list) < 0)
285
0
      return NULL;
286
0
  const void **elements = list->elements;
287
0
  list->count = count + 1;
288
0
  for (size_t i = count; i > 0; i--)
289
0
    elements[i] = elements[i - 1];
290
0
  elements[0] = elt;
291
0
  return INDEX_TO_NODE (0);
292
0
}
293
294
static gl_list_node_t
295
gl_array_nx_add_last (gl_list_t list, const void *elt)
296
0
{
297
0
  size_t count = list->count;
298
299
0
  if (count == list->allocated)
300
0
    if (grow (list) < 0)
301
0
      return NULL;
302
0
  list->count = count + 1;
303
0
  list->elements[count] = elt;
304
0
  return INDEX_TO_NODE (count);
305
0
}
306
307
static gl_list_node_t
308
gl_array_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
309
0
{
310
0
  size_t count = list->count;
311
0
  uintptr_t index = NODE_TO_INDEX (node);
312
313
0
  if (!(index < count))
314
    /* Invalid argument.  */
315
0
    abort ();
316
0
  size_t position = index;
317
0
  if (count == list->allocated)
318
0
    if (grow (list) < 0)
319
0
      return NULL;
320
0
  const void **elements = list->elements;
321
0
  list->count = count + 1;
322
0
  for (size_t i = count; i > position; i--)
323
0
    elements[i] = elements[i - 1];
324
0
  elements[position] = elt;
325
0
  return INDEX_TO_NODE (position);
326
0
}
327
328
static gl_list_node_t
329
gl_array_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
330
0
{
331
0
  size_t count = list->count;
332
0
  uintptr_t index = NODE_TO_INDEX (node);
333
334
0
  if (!(index < count))
335
    /* Invalid argument.  */
336
0
    abort ();
337
0
  size_t position = index + 1;
338
0
  if (count == list->allocated)
339
0
    if (grow (list) < 0)
340
0
      return NULL;
341
0
  const void **elements = list->elements;
342
0
  list->count = count + 1;
343
0
  for (size_t i = count; i > position; i--)
344
0
    elements[i] = elements[i - 1];
345
0
  elements[position] = elt;
346
0
  return INDEX_TO_NODE (position);
347
0
}
348
349
static gl_list_node_t
350
gl_array_nx_add_at (gl_list_t list, size_t position, const void *elt)
351
0
{
352
0
  size_t count = list->count;
353
354
0
  if (!(position <= count))
355
    /* Invalid argument.  */
356
0
    abort ();
357
0
  if (count == list->allocated)
358
0
    if (grow (list) < 0)
359
0
      return NULL;
360
0
  const void **elements = list->elements;
361
0
  list->count = count + 1;
362
0
  for (size_t i = count; i > position; i--)
363
0
    elements[i] = elements[i - 1];
364
0
  elements[position] = elt;
365
0
  return INDEX_TO_NODE (position);
366
0
}
367
368
static bool
369
gl_array_remove_node (gl_list_t list, gl_list_node_t node)
370
0
{
371
0
  size_t count = list->count;
372
0
  uintptr_t index = NODE_TO_INDEX (node);
373
374
0
  if (!(index < count))
375
    /* Invalid argument.  */
376
0
    abort ();
377
0
  size_t position = index;
378
0
  const void **elements = list->elements;
379
0
  if (list->base.dispose_fn != NULL)
380
0
    list->base.dispose_fn (elements[position]);
381
0
  for (size_t i = position + 1; i < count; i++)
382
0
    elements[i - 1] = elements[i];
383
0
  list->count = count - 1;
384
0
  return true;
385
0
}
386
387
static bool
388
gl_array_remove_at (gl_list_t list, size_t position)
389
0
{
390
0
  size_t count = list->count;
391
392
0
  if (!(position < count))
393
    /* Invalid argument.  */
394
0
    abort ();
395
0
  const void **elements = list->elements;
396
0
  if (list->base.dispose_fn != NULL)
397
0
    list->base.dispose_fn (elements[position]);
398
0
  for (size_t i = position + 1; i < count; i++)
399
0
    elements[i - 1] = elements[i];
400
0
  list->count = count - 1;
401
0
  return true;
402
0
}
403
404
static bool
405
gl_array_remove (gl_list_t list, const void *elt)
406
0
{
407
0
  size_t position = gl_array_indexof_from_to (list, 0, list->count, elt);
408
0
  if (position == (size_t)(-1))
409
0
    return false;
410
0
  else
411
0
    return gl_array_remove_at (list, position);
412
0
}
413
414
static void
415
gl_array_list_free (gl_list_t list)
416
0
{
417
0
  if (list->elements != NULL)
418
0
    {
419
0
      if (list->base.dispose_fn != NULL)
420
0
        {
421
0
          size_t count = list->count;
422
423
0
          if (count > 0)
424
0
            {
425
0
              gl_listelement_dispose_fn dispose = list->base.dispose_fn;
426
0
              const void **elements = list->elements;
427
428
0
              do
429
0
                dispose (*elements++);
430
0
              while (--count > 0);
431
0
            }
432
0
        }
433
0
      free (list->elements);
434
0
    }
435
0
  free (list);
436
0
}
437
438
/* --------------------- gl_list_iterator_t Data Type --------------------- */
439
440
static gl_list_iterator_t _GL_ATTRIBUTE_PURE
441
gl_array_iterator (gl_list_t list)
442
0
{
443
0
  gl_list_iterator_t result;
444
445
0
  result.vtable = list->base.vtable;
446
0
  result.list = list;
447
0
  result.count = list->count;
448
0
  result.p = list->elements + 0;
449
0
  result.q = list->elements + list->count;
450
#if defined GCC_LINT || defined lint
451
  result.i = 0;
452
  result.j = 0;
453
#endif
454
455
0
  return result;
456
0
}
457
458
static gl_list_iterator_t _GL_ATTRIBUTE_PURE
459
gl_array_iterator_from_to (gl_list_t list, size_t start_index, size_t end_index)
460
0
{
461
0
  gl_list_iterator_t result;
462
463
0
  if (!(start_index <= end_index && end_index <= list->count))
464
    /* Invalid arguments.  */
465
0
    abort ();
466
0
  result.vtable = list->base.vtable;
467
0
  result.list = list;
468
0
  result.count = list->count;
469
0
  result.p = list->elements + start_index;
470
0
  result.q = list->elements + end_index;
471
#if defined GCC_LINT || defined lint
472
  result.i = 0;
473
  result.j = 0;
474
#endif
475
476
0
  return result;
477
0
}
478
479
static bool
480
gl_array_iterator_next (gl_list_iterator_t *iterator,
481
                        const void **eltp, gl_list_node_t *nodep)
482
0
{
483
0
  gl_list_t list = iterator->list;
484
0
  if (iterator->count != list->count)
485
0
    {
486
0
      if (iterator->count != list->count + 1)
487
        /* Concurrent modifications were done on the list.  */
488
0
        abort ();
489
      /* The last returned element was removed.  */
490
0
      iterator->count--;
491
0
      iterator->p = (const void **) iterator->p - 1;
492
0
      iterator->q = (const void **) iterator->q - 1;
493
0
    }
494
0
  if (iterator->p < iterator->q)
495
0
    {
496
0
      const void **p = (const void **) iterator->p;
497
0
      *eltp = *p;
498
0
      if (nodep != NULL)
499
0
        *nodep = INDEX_TO_NODE (p - list->elements);
500
0
      iterator->p = p + 1;
501
0
      return true;
502
0
    }
503
0
  else
504
0
    return false;
505
0
}
506
507
static void
508
gl_array_iterator_free (gl_list_iterator_t *_GL_UNNAMED (iterator))
509
0
{
510
0
}
511
512
/* ---------------------- Sorted gl_list_t Data Type ---------------------- */
513
514
static size_t _GL_ATTRIBUTE_PURE
515
gl_array_sortedlist_indexof_from_to (gl_list_t list,
516
                                     gl_listelement_compar_fn compar,
517
                                     size_t low, size_t high,
518
                                     const void *elt)
519
0
{
520
0
  if (!(low <= high && high <= list->count))
521
    /* Invalid arguments.  */
522
0
    abort ();
523
0
  if (low < high)
524
0
    {
525
      /* At each loop iteration, low < high; for indices < low the values
526
         are smaller than ELT; for indices >= high the values are greater
527
         than ELT.  So, if the element occurs in the list, it is at
528
         low <= position < high.  */
529
0
      do
530
0
        {
531
0
          size_t mid = low + (high - low) / 2; /* low <= mid < high */
532
0
          int cmp = compar (list->elements[mid], elt);
533
534
0
          if (cmp < 0)
535
0
            low = mid + 1;
536
0
          else if (cmp > 0)
537
0
            high = mid;
538
0
          else /* cmp == 0 */
539
0
            {
540
              /* We have an element equal to ELT at index MID.  But we need
541
                 the minimal such index.  */
542
0
              high = mid;
543
              /* At each loop iteration, low <= high and
544
                   compar (list->elements[high], elt) == 0,
545
                 and we know that the first occurrence of the element is at
546
                 low <= position <= high.  */
547
0
              while (low < high)
548
0
                {
549
0
                  size_t mid2 = low + (high - low) / 2; /* low <= mid2 < high */
550
0
                  int cmp2 = compar (list->elements[mid2], elt);
551
552
0
                  if (cmp2 < 0)
553
0
                    low = mid2 + 1;
554
0
                  else if (cmp2 > 0)
555
                    /* The list was not sorted.  */
556
0
                    abort ();
557
0
                  else /* cmp2 == 0 */
558
0
                    {
559
0
                      if (mid2 == low)
560
0
                        break;
561
0
                      high = mid2 - 1;
562
0
                    }
563
0
                }
564
0
              return low;
565
0
            }
566
0
        }
567
0
      while (low < high);
568
      /* Here low == high.  */
569
0
    }
570
0
  return (size_t)(-1);
571
0
}
572
573
static size_t _GL_ATTRIBUTE_PURE
574
gl_array_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
575
                             const void *elt)
576
0
{
577
0
  return gl_array_sortedlist_indexof_from_to (list, compar, 0, list->count,
578
0
                                              elt);
579
0
}
580
581
static gl_list_node_t _GL_ATTRIBUTE_PURE
582
gl_array_sortedlist_search_from_to (gl_list_t list,
583
                                    gl_listelement_compar_fn compar,
584
                                    size_t low, size_t high,
585
                                    const void *elt)
586
0
{
587
0
  size_t index =
588
0
    gl_array_sortedlist_indexof_from_to (list, compar, low, high, elt);
589
0
  return INDEX_TO_NODE (index);
590
0
}
591
592
static gl_list_node_t _GL_ATTRIBUTE_PURE
593
gl_array_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
594
                            const void *elt)
595
0
{
596
0
  size_t index =
597
0
    gl_array_sortedlist_indexof_from_to (list, compar, 0, list->count, elt);
598
0
  return INDEX_TO_NODE (index);
599
0
}
600
601
static gl_list_node_t
602
gl_array_sortedlist_nx_add (gl_list_t list, gl_listelement_compar_fn compar,
603
                            const void *elt)
604
0
{
605
0
  size_t count = list->count;
606
0
  size_t low = 0;
607
0
  size_t high = count;
608
609
  /* At each loop iteration, low <= high; for indices < low the values are
610
     smaller than ELT; for indices >= high the values are greater than ELT.  */
611
0
  while (low < high)
612
0
    {
613
0
      size_t mid = low + (high - low) / 2; /* low <= mid < high */
614
0
      int cmp = compar (list->elements[mid], elt);
615
616
0
      if (cmp < 0)
617
0
        low = mid + 1;
618
0
      else if (cmp > 0)
619
0
        high = mid;
620
0
      else /* cmp == 0 */
621
0
        {
622
0
          low = mid;
623
0
          break;
624
0
        }
625
0
    }
626
0
  return gl_array_nx_add_at (list, low, elt);
627
0
}
628
629
static bool
630
gl_array_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
631
                            const void *elt)
632
0
{
633
0
  size_t index = gl_array_sortedlist_indexof (list, compar, elt);
634
0
  if (index == (size_t)(-1))
635
0
    return false;
636
0
  else
637
0
    return gl_array_remove_at (list, index);
638
0
}
639
640
641
const struct gl_list_implementation gl_array_list_implementation =
642
  {
643
    gl_array_nx_create_empty,
644
    gl_array_nx_create,
645
    gl_array_size,
646
    gl_array_node_value,
647
    gl_array_node_nx_set_value,
648
    gl_array_next_node,
649
    gl_array_previous_node,
650
    gl_array_first_node,
651
    gl_array_last_node,
652
    gl_array_get_at,
653
    gl_array_nx_set_at,
654
    gl_array_search_from_to,
655
    gl_array_indexof_from_to,
656
    gl_array_nx_add_first,
657
    gl_array_nx_add_last,
658
    gl_array_nx_add_before,
659
    gl_array_nx_add_after,
660
    gl_array_nx_add_at,
661
    gl_array_remove_node,
662
    gl_array_remove_at,
663
    gl_array_remove,
664
    gl_array_list_free,
665
    gl_array_iterator,
666
    gl_array_iterator_from_to,
667
    gl_array_iterator_next,
668
    gl_array_iterator_free,
669
    gl_array_sortedlist_search,
670
    gl_array_sortedlist_search_from_to,
671
    gl_array_sortedlist_indexof,
672
    gl_array_sortedlist_indexof_from_to,
673
    gl_array_sortedlist_nx_add,
674
    gl_array_sortedlist_remove
675
  };