Coverage Report

Created: 2026-11-12 06:28

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) {(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
      const void **contents_copy =
99
0
        (const void **) malloc (count * sizeof (const void *));
100
0
      if (contents_copy == NULL)
101
0
        goto fail;
102
0
      memcpy (contents_copy, contents, count * sizeof (const void *));
103
0
      list->elements = contents_copy;
104
0
    }
105
0
  else
106
0
    list->elements = NULL;
107
0
  list->count = count;
108
0
  list->allocated = count;
109
110
0
  return list;
111
112
0
 fail:
113
0
  free (list);
114
0
  return NULL;
115
0
}
116
117
static size_t _GL_ATTRIBUTE_PURE
118
gl_array_size (gl_list_t list)
119
0
{
120
0
  return list->count;
121
0
}
122
123
static const void * _GL_ATTRIBUTE_PURE
124
gl_array_node_value (gl_list_t list, gl_list_node_t node)
125
0
{
126
0
  uintptr_t index = NODE_TO_INDEX (node);
127
0
  if (!(index < list->count))
128
    /* Invalid argument.  */
129
0
    abort ();
130
0
  return list->elements[index];
131
0
}
132
133
static int
134
gl_array_node_nx_set_value (gl_list_t list, gl_list_node_t node,
135
                            const void *elt)
136
0
{
137
0
  uintptr_t index = NODE_TO_INDEX (node);
138
0
  if (!(index < list->count))
139
    /* Invalid argument.  */
140
0
    abort ();
141
0
  list->elements[index] = elt;
142
0
  return 0;
143
0
}
144
145
static gl_list_node_t _GL_ATTRIBUTE_PURE
146
gl_array_next_node (gl_list_t list, gl_list_node_t node)
147
0
{
148
0
  uintptr_t index = NODE_TO_INDEX (node);
149
0
  if (!(index < list->count))
150
    /* Invalid argument.  */
151
0
    abort ();
152
0
  index++;
153
0
  if (index < list->count)
154
0
    return INDEX_TO_NODE (index);
155
0
  else
156
0
    return NULL;
157
0
}
158
159
static gl_list_node_t _GL_ATTRIBUTE_PURE
160
gl_array_previous_node (gl_list_t list, gl_list_node_t node)
161
0
{
162
0
  uintptr_t index = NODE_TO_INDEX (node);
163
0
  if (!(index < list->count))
164
    /* Invalid argument.  */
165
0
    abort ();
166
0
  if (index > 0)
167
0
    return INDEX_TO_NODE (index - 1);
168
0
  else
169
0
    return NULL;
170
0
}
171
172
static gl_list_node_t _GL_ATTRIBUTE_PURE
173
gl_array_first_node (gl_list_t list)
174
0
{
175
0
  if (list->count > 0)
176
0
    return INDEX_TO_NODE (0);
177
0
  else
178
0
    return NULL;
179
0
}
180
181
static gl_list_node_t _GL_ATTRIBUTE_PURE
182
gl_array_last_node (gl_list_t list)
183
0
{
184
0
  if (list->count > 0)
185
0
    return INDEX_TO_NODE (list->count - 1);
186
0
  else
187
0
    return NULL;
188
0
}
189
190
static const void * _GL_ATTRIBUTE_PURE
191
gl_array_get_at (gl_list_t list, size_t position)
192
0
{
193
0
  size_t count = list->count;
194
195
0
  if (!(position < count))
196
    /* Invalid argument.  */
197
0
    abort ();
198
0
  return list->elements[position];
199
0
}
200
201
static gl_list_node_t
202
gl_array_nx_set_at (gl_list_t list, size_t position, const void *elt)
203
0
{
204
0
  size_t count = list->count;
205
206
0
  if (!(position < count))
207
    /* Invalid argument.  */
208
0
    abort ();
209
0
  list->elements[position] = elt;
210
0
  return INDEX_TO_NODE (position);
211
0
}
212
213
static size_t _GL_ATTRIBUTE_PURE
214
gl_array_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
215
                          const void *elt)
216
  _GL_LIST_INVOKES_FN_PTR
217
0
{
218
0
  size_t count = list->count;
219
220
0
  if (!(start_index <= end_index && end_index <= count))
221
    /* Invalid arguments.  */
222
0
    abort ();
223
224
0
  if (start_index < end_index)
225
0
    {
226
0
      gl_listelement_equals_fn equals = list->base.equals_fn;
227
0
      if (equals != NULL)
228
0
        {
229
0
          for (size_t i = start_index;;)
230
0
            {
231
0
              if (equals (elt, list->elements[i]))
232
0
                return i;
233
0
              i++;
234
0
              if (i == end_index)
235
0
                break;
236
0
            }
237
0
        }
238
0
      else
239
0
        {
240
0
          for (size_t i = start_index;;)
241
0
            {
242
0
              if (elt == list->elements[i])
243
0
                return i;
244
0
              i++;
245
0
              if (i == end_index)
246
0
                break;
247
0
            }
248
0
        }
249
0
    }
250
0
  return (size_t)(-1);
251
0
}
252
253
static gl_list_node_t _GL_ATTRIBUTE_PURE
254
gl_array_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
255
                         const void *elt)
256
0
{
257
0
  size_t index = gl_array_indexof_from_to (list, start_index, end_index, elt);
258
0
  return INDEX_TO_NODE (index);
259
0
}
260
261
/* Ensure that list->allocated > list->count.
262
   Return 0 upon success, -1 upon out-of-memory.  */
263
static int
264
grow (gl_list_t list)
265
0
{
266
0
  size_t new_allocated = xtimes (list->allocated, 2);
267
0
  new_allocated = xsum (new_allocated, 1);
268
0
  size_t memory_size = xtimes (new_allocated, sizeof (const void *));
269
0
  if (size_overflow_p (memory_size))
270
    /* Overflow, would lead to out of memory.  */
271
0
    return -1;
272
0
  const void **memory = (const void **) realloc (list->elements, memory_size);
273
0
  if (memory == NULL)
274
    /* Out of memory.  */
275
0
    return -1;
276
0
  list->elements = memory;
277
0
  list->allocated = new_allocated;
278
0
  return 0;
279
0
}
280
281
static gl_list_node_t
282
gl_array_nx_add_first (gl_list_t list, const void *elt)
283
0
{
284
0
  size_t count = list->count;
285
286
0
  if (count == list->allocated)
287
0
    if (grow (list) < 0)
288
0
      return NULL;
289
0
  const void **elements = list->elements;
290
0
  list->count = count + 1;
291
0
  for (size_t i = count; i > 0; i--)
292
0
    elements[i] = elements[i - 1];
293
0
  elements[0] = elt;
294
0
  return INDEX_TO_NODE (0);
295
0
}
296
297
static gl_list_node_t
298
gl_array_nx_add_last (gl_list_t list, const void *elt)
299
0
{
300
0
  size_t count = list->count;
301
302
0
  if (count == list->allocated)
303
0
    if (grow (list) < 0)
304
0
      return NULL;
305
0
  list->count = count + 1;
306
0
  list->elements[count] = elt;
307
0
  return INDEX_TO_NODE (count);
308
0
}
309
310
static gl_list_node_t
311
gl_array_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
312
0
{
313
0
  size_t count = list->count;
314
0
  uintptr_t index = NODE_TO_INDEX (node);
315
316
0
  if (!(index < count))
317
    /* Invalid argument.  */
318
0
    abort ();
319
0
  size_t position = index;
320
0
  if (count == list->allocated)
321
0
    if (grow (list) < 0)
322
0
      return NULL;
323
0
  const void **elements = list->elements;
324
0
  list->count = count + 1;
325
0
  for (size_t i = count; i > position; i--)
326
0
    elements[i] = elements[i - 1];
327
0
  elements[position] = elt;
328
0
  return INDEX_TO_NODE (position);
329
0
}
330
331
static gl_list_node_t
332
gl_array_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
333
0
{
334
0
  size_t count = list->count;
335
0
  uintptr_t index = NODE_TO_INDEX (node);
336
337
0
  if (!(index < count))
338
    /* Invalid argument.  */
339
0
    abort ();
340
0
  size_t position = index + 1;
341
0
  if (count == list->allocated)
342
0
    if (grow (list) < 0)
343
0
      return NULL;
344
0
  const void **elements = list->elements;
345
0
  list->count = count + 1;
346
0
  for (size_t i = count; i > position; i--)
347
0
    elements[i] = elements[i - 1];
348
0
  elements[position] = elt;
349
0
  return INDEX_TO_NODE (position);
350
0
}
351
352
static gl_list_node_t
353
gl_array_nx_add_at (gl_list_t list, size_t position, const void *elt)
354
0
{
355
0
  size_t count = list->count;
356
357
0
  if (!(position <= count))
358
    /* Invalid argument.  */
359
0
    abort ();
360
0
  if (count == list->allocated)
361
0
    if (grow (list) < 0)
362
0
      return NULL;
363
0
  const void **elements = list->elements;
364
0
  list->count = count + 1;
365
0
  for (size_t i = count; i > position; i--)
366
0
    elements[i] = elements[i - 1];
367
0
  elements[position] = elt;
368
0
  return INDEX_TO_NODE (position);
369
0
}
370
371
static bool
372
gl_array_remove_node (gl_list_t list, gl_list_node_t node)
373
  _GL_LIST_INVOKES_FN_PTR
374
0
{
375
0
  size_t count = list->count;
376
0
  uintptr_t index = NODE_TO_INDEX (node);
377
378
0
  if (!(index < count))
379
    /* Invalid argument.  */
380
0
    abort ();
381
0
  size_t position = index;
382
0
  const void **elements = list->elements;
383
0
  if (list->base.dispose_fn != NULL)
384
0
    list->base.dispose_fn (elements[position]);
385
0
  for (size_t i = position + 1; i < count; i++)
386
0
    elements[i - 1] = elements[i];
387
0
  list->count = count - 1;
388
0
  return true;
389
0
}
390
391
static bool
392
gl_array_remove_at (gl_list_t list, size_t position)
393
  _GL_LIST_INVOKES_FN_PTR
394
0
{
395
0
  size_t count = list->count;
396
397
0
  if (!(position < count))
398
    /* Invalid argument.  */
399
0
    abort ();
400
0
  const void **elements = list->elements;
401
0
  if (list->base.dispose_fn != NULL)
402
0
    list->base.dispose_fn (elements[position]);
403
0
  for (size_t i = position + 1; i < count; i++)
404
0
    elements[i - 1] = elements[i];
405
0
  list->count = count - 1;
406
0
  return true;
407
0
}
408
409
static bool
410
gl_array_remove (gl_list_t list, const void *elt)
411
0
{
412
0
  size_t position = gl_array_indexof_from_to (list, 0, list->count, elt);
413
0
  if (position == (size_t)(-1))
414
0
    return false;
415
0
  else
416
0
    return gl_array_remove_at (list, position);
417
0
}
418
419
static void
420
gl_array_list_free (gl_list_t list)
421
  _GL_LIST_INVOKES_FN_PTR
422
0
{
423
0
  if (list->elements != NULL)
424
0
    {
425
0
      if (list->base.dispose_fn != NULL)
426
0
        {
427
0
          size_t count = list->count;
428
429
0
          if (count > 0)
430
0
            {
431
0
              gl_listelement_dispose_fn dispose = list->base.dispose_fn;
432
0
              const void **elements = list->elements;
433
434
0
              do
435
0
                dispose (*elements++);
436
0
              while (--count > 0);
437
0
            }
438
0
        }
439
0
      free (list->elements);
440
0
    }
441
0
  free (list);
442
0
}
443
444
/* --------------------- gl_list_iterator_t Data Type --------------------- */
445
446
static gl_list_iterator_t _GL_ATTRIBUTE_PURE
447
gl_array_iterator (gl_list_t list)
448
0
{
449
0
  gl_list_iterator_t result;
450
451
0
  result.vtable = list->base.vtable;
452
0
  result.list = list;
453
0
  result.count = list->count;
454
0
  result.p = list->elements + 0;
455
0
  result.q = list->elements + list->count;
456
#if defined GCC_LINT || defined lint
457
  result.i = 0;
458
  result.j = 0;
459
#endif
460
461
0
  return result;
462
0
}
463
464
static gl_list_iterator_t _GL_ATTRIBUTE_PURE
465
gl_array_iterator_from_to (gl_list_t list, size_t start_index, size_t end_index)
466
0
{
467
0
  gl_list_iterator_t result;
468
469
0
  if (!(start_index <= end_index && end_index <= list->count))
470
    /* Invalid arguments.  */
471
0
    abort ();
472
0
  result.vtable = list->base.vtable;
473
0
  result.list = list;
474
0
  result.count = list->count;
475
0
  result.p = list->elements + start_index;
476
0
  result.q = list->elements + end_index;
477
#if defined GCC_LINT || defined lint
478
  result.i = 0;
479
  result.j = 0;
480
#endif
481
482
0
  return result;
483
0
}
484
485
static bool
486
gl_array_iterator_next (gl_list_iterator_t *iterator,
487
                        const void **eltp, gl_list_node_t *nodep)
488
0
{
489
0
  gl_list_t list = iterator->list;
490
0
  if (iterator->count != list->count)
491
0
    {
492
0
      if (iterator->count != list->count + 1)
493
        /* Concurrent modifications were done on the list.  */
494
0
        abort ();
495
      /* The last returned element was removed.  */
496
0
      iterator->count--;
497
0
      iterator->p = (const void **) iterator->p - 1;
498
0
      iterator->q = (const void **) iterator->q - 1;
499
0
    }
500
0
  if (iterator->p < iterator->q)
501
0
    {
502
0
      const void **p = (const void **) iterator->p;
503
0
      *eltp = *p;
504
0
      if (nodep != NULL)
505
0
        *nodep = INDEX_TO_NODE (p - list->elements);
506
0
      iterator->p = p + 1;
507
0
      return true;
508
0
    }
509
0
  else
510
0
    return false;
511
0
}
512
513
static void
514
gl_array_iterator_free (gl_list_iterator_t *_GL_UNNAMED (iterator))
515
0
{
516
0
}
517
518
/* ---------------------- Sorted gl_list_t Data Type ---------------------- */
519
520
static size_t _GL_ATTRIBUTE_PURE
521
gl_array_sortedlist_indexof_from_to (gl_list_t list,
522
                                     gl_listelement_compar_fn compar,
523
                                     size_t low, size_t high,
524
                                     const void *elt)
525
  _GL_LIST_INVOKES_FN_PTR
526
0
{
527
0
  if (!(low <= high && high <= list->count))
528
    /* Invalid arguments.  */
529
0
    abort ();
530
0
  if (low < high)
531
0
    {
532
      /* At each loop iteration, low < high; for indices < low the values
533
         are smaller than ELT; for indices >= high the values are greater
534
         than ELT.  So, if the element occurs in the list, it is at
535
         low <= position < high.  */
536
0
      do
537
0
        {
538
0
          size_t mid = low + (high - low) / 2; /* low <= mid < high */
539
0
          int cmp = compar (list->elements[mid], elt);
540
541
0
          if (cmp < 0)
542
0
            low = mid + 1;
543
0
          else if (cmp > 0)
544
0
            high = mid;
545
0
          else /* cmp == 0 */
546
0
            {
547
              /* We have an element equal to ELT at index MID.  But we need
548
                 the minimal such index.  */
549
0
              high = mid;
550
              /* At each loop iteration, low <= high and
551
                   compar (list->elements[high], elt) == 0,
552
                 and we know that the first occurrence of the element is at
553
                 low <= position <= high.  */
554
0
              while (low < high)
555
0
                {
556
0
                  size_t mid2 = low + (high - low) / 2; /* low <= mid2 < high */
557
0
                  int cmp2 = compar (list->elements[mid2], elt);
558
559
0
                  if (cmp2 < 0)
560
0
                    low = mid2 + 1;
561
0
                  else if (cmp2 > 0)
562
                    /* The list was not sorted.  */
563
0
                    abort ();
564
0
                  else /* cmp2 == 0 */
565
0
                    {
566
0
                      if (mid2 == low)
567
0
                        break;
568
0
                      high = mid2 - 1;
569
0
                    }
570
0
                }
571
0
              return low;
572
0
            }
573
0
        }
574
0
      while (low < high);
575
      /* Here low == high.  */
576
0
    }
577
0
  return (size_t)(-1);
578
0
}
579
580
static size_t _GL_ATTRIBUTE_PURE
581
gl_array_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
582
                             const void *elt)
583
0
{
584
0
  return gl_array_sortedlist_indexof_from_to (list, compar, 0, list->count,
585
0
                                              elt);
586
0
}
587
588
static gl_list_node_t _GL_ATTRIBUTE_PURE
589
gl_array_sortedlist_search_from_to (gl_list_t list,
590
                                    gl_listelement_compar_fn compar,
591
                                    size_t low, size_t high,
592
                                    const void *elt)
593
0
{
594
0
  size_t index =
595
0
    gl_array_sortedlist_indexof_from_to (list, compar, low, high, elt);
596
0
  return INDEX_TO_NODE (index);
597
0
}
598
599
static gl_list_node_t _GL_ATTRIBUTE_PURE
600
gl_array_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
601
                            const void *elt)
602
0
{
603
0
  size_t index =
604
0
    gl_array_sortedlist_indexof_from_to (list, compar, 0, list->count, elt);
605
0
  return INDEX_TO_NODE (index);
606
0
}
607
608
static gl_list_node_t
609
gl_array_sortedlist_nx_add (gl_list_t list, gl_listelement_compar_fn compar,
610
                            const void *elt)
611
  _GL_LIST_INVOKES_FN_PTR
612
0
{
613
0
  size_t count = list->count;
614
0
  size_t low = 0;
615
0
  size_t high = count;
616
617
  /* At each loop iteration, low <= high; for indices < low the values are
618
     smaller than ELT; for indices >= high the values are greater than ELT.  */
619
0
  while (low < high)
620
0
    {
621
0
      size_t mid = low + (high - low) / 2; /* low <= mid < high */
622
0
      int cmp = compar (list->elements[mid], elt);
623
624
0
      if (cmp < 0)
625
0
        low = mid + 1;
626
0
      else if (cmp > 0)
627
0
        high = mid;
628
0
      else /* cmp == 0 */
629
0
        {
630
0
          low = mid;
631
0
          break;
632
0
        }
633
0
    }
634
0
  return gl_array_nx_add_at (list, low, elt);
635
0
}
636
637
static bool
638
gl_array_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
639
                            const void *elt)
640
0
{
641
0
  size_t index = gl_array_sortedlist_indexof (list, compar, elt);
642
0
  if (index == (size_t)(-1))
643
0
    return false;
644
0
  else
645
0
    return gl_array_remove_at (list, index);
646
0
}
647
648
649
const struct gl_list_implementation gl_array_list_implementation =
650
  {
651
    gl_array_nx_create_empty,
652
    gl_array_nx_create,
653
    gl_array_size,
654
    gl_array_node_value,
655
    gl_array_node_nx_set_value,
656
    gl_array_next_node,
657
    gl_array_previous_node,
658
    gl_array_first_node,
659
    gl_array_last_node,
660
    gl_array_get_at,
661
    gl_array_nx_set_at,
662
    gl_array_search_from_to,
663
    gl_array_indexof_from_to,
664
    gl_array_nx_add_first,
665
    gl_array_nx_add_last,
666
    gl_array_nx_add_before,
667
    gl_array_nx_add_after,
668
    gl_array_nx_add_at,
669
    gl_array_remove_node,
670
    gl_array_remove_at,
671
    gl_array_remove,
672
    gl_array_list_free,
673
    gl_array_iterator,
674
    gl_array_iterator_from_to,
675
    gl_array_iterator_next,
676
    gl_array_iterator_free,
677
    gl_array_sortedlist_search,
678
    gl_array_sortedlist_search_from_to,
679
    gl_array_sortedlist_indexof,
680
    gl_array_sortedlist_indexof_from_to,
681
    gl_array_sortedlist_nx_add,
682
    gl_array_sortedlist_remove
683
  };