Coverage Report

Created: 2026-03-31 07:20

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