Coverage Report

Created: 2026-11-12 07:51

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gnutls/gl/gl_anylinked_list2.h
Line
Count
Source
1
/* Sequential list data type implemented by a linked list.
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
/* Common code of gl_linked_list.c and gl_linkedhash_list.c.  */
19
20
/* If the symbol SIGNAL_SAFE_LIST is defined, the code is compiled in such
21
   a way that a gl_list_t data structure may be used from within a signal
22
   handler.  The operations allowed in the signal handler are:
23
     gl_list_iterator, gl_list_iterator_next, gl_list_iterator_free.
24
   The list and node fields that are therefore accessed from the signal handler
25
   are:
26
     list->root, node->next, node->value.
27
   We are careful to make modifications to these fields only in an order
28
   that maintains the consistency of the list data structure at any moment,
29
   and we use 'volatile' assignments to prevent the compiler from reordering
30
   such assignments.  */
31
#ifdef SIGNAL_SAFE_LIST
32
# define ASYNCSAFE(type) *(type volatile *)&
33
#else
34
# define ASYNCSAFE(type)
35
#endif
36
37
/* -------------------------- gl_list_t Data Type -------------------------- */
38
39
static gl_list_t
40
gl_linked_nx_create_empty (gl_list_implementation_t implementation,
41
                           gl_listelement_equals_fn equals_fn,
42
                           gl_listelement_hashcode_fn hashcode_fn,
43
                           gl_listelement_dispose_fn dispose_fn,
44
                           bool allow_duplicates)
45
36
{
46
36
  struct gl_list_impl *list =
47
36
    (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
48
49
36
  if (list == NULL)
50
0
    return NULL;
51
52
36
  list->base.vtable = implementation;
53
36
  list->base.equals_fn = equals_fn;
54
36
  list->base.hashcode_fn = hashcode_fn;
55
36
  list->base.dispose_fn = dispose_fn;
56
36
  list->base.allow_duplicates = allow_duplicates;
57
36
#if WITH_HASHTABLE
58
36
  list->table_size = 11;
59
36
  list->table =
60
36
    (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
61
36
  if (list->table == NULL)
62
0
    goto fail;
63
36
#endif
64
36
  list->root.next = &list->root;
65
36
  list->root.prev = &list->root;
66
36
  list->count = 0;
67
68
36
  return list;
69
70
0
#if WITH_HASHTABLE
71
0
 fail:
72
0
  free (list);
73
0
  return NULL;
74
36
#endif
75
36
}
76
77
static gl_list_t
78
gl_linked_nx_create (gl_list_implementation_t implementation,
79
                     gl_listelement_equals_fn equals_fn,
80
                     gl_listelement_hashcode_fn hashcode_fn,
81
                     gl_listelement_dispose_fn dispose_fn,
82
                     bool allow_duplicates,
83
                     size_t count, const void **contents)
84
  _GL_LIST_INVOKES_FN_PTR
85
0
{
86
0
  struct gl_list_impl *list =
87
0
    (struct gl_list_impl *) malloc (sizeof (struct gl_list_impl));
88
0
  gl_list_node_t tail;
89
90
0
  if (list == NULL)
91
0
    return NULL;
92
93
0
  list->base.vtable = implementation;
94
0
  list->base.equals_fn = equals_fn;
95
0
  list->base.hashcode_fn = hashcode_fn;
96
0
  list->base.dispose_fn = dispose_fn;
97
0
  list->base.allow_duplicates = allow_duplicates;
98
0
#if WITH_HASHTABLE
99
0
  {
100
0
    size_t estimate = xsum (count, count / 2); /* 1.5 * count */
101
0
    if (estimate < 10)
102
0
      estimate = 10;
103
0
    list->table_size = next_prime (estimate);
104
0
    if (size_overflow_p (xtimes (list->table_size, sizeof (gl_hash_entry_t))))
105
0
      goto fail1;
106
0
    list->table =
107
0
      (gl_hash_entry_t *) calloc (list->table_size, sizeof (gl_hash_entry_t));
108
0
    if (list->table == NULL)
109
0
      goto fail1;
110
0
  }
111
0
#endif
112
0
  list->count = count;
113
0
  tail = &list->root;
114
0
  for (; count > 0; contents++, count--)
115
0
    {
116
0
      gl_list_node_t node =
117
0
        (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
118
119
0
      if (node == NULL)
120
0
        goto fail2;
121
122
0
      node->value = *contents;
123
0
#if WITH_HASHTABLE
124
0
      node->h.hashcode =
125
0
        (list->base.hashcode_fn != NULL
126
0
         ? list->base.hashcode_fn (node->value)
127
0
         : (size_t) {(uintptr_t) node->value});
128
129
      /* Add node to the hash table.  */
130
0
      if (add_to_bucket (list, node) < 0)
131
0
        {
132
0
          free (node);
133
0
          goto fail2;
134
0
        }
135
0
#endif
136
137
      /* Add node to the list.  */
138
0
      node->prev = tail;
139
0
      tail->next = node;
140
0
      tail = node;
141
0
    }
142
0
  tail->next = &list->root;
143
0
  list->root.prev = tail;
144
145
0
  return list;
146
147
0
 fail2:
148
0
  for (gl_list_node_t node = tail; node != &list->root; )
149
0
    {
150
0
      gl_list_node_t prev = node->prev;
151
152
0
      free (node);
153
0
      node = prev;
154
0
    }
155
0
#if WITH_HASHTABLE
156
0
  free (list->table);
157
0
 fail1:
158
0
#endif
159
0
  free (list);
160
0
  return NULL;
161
0
}
162
163
static size_t _GL_ATTRIBUTE_PURE
164
gl_linked_size (gl_list_t list)
165
0
{
166
0
  return list->count;
167
0
}
168
169
static const void * _GL_ATTRIBUTE_PURE
170
gl_linked_node_value (gl_list_t _GL_UNNAMED (list), gl_list_node_t node)
171
0
{
172
0
  return node->value;
173
0
}
174
175
static int
176
gl_linked_node_nx_set_value (_GL_ATTRIBUTE_MAYBE_UNUSED gl_list_t list,
177
                             gl_list_node_t node,
178
                             const void *elt)
179
  _GL_LIST_INVOKES_FN_PTR
180
0
{
181
0
#if WITH_HASHTABLE
182
0
  if (elt != node->value)
183
0
    {
184
0
      size_t new_hashcode =
185
0
        (list->base.hashcode_fn != NULL
186
0
         ? list->base.hashcode_fn (elt)
187
0
         : (size_t) {(uintptr_t) elt});
188
189
0
      if (new_hashcode != node->h.hashcode)
190
0
        {
191
0
          remove_from_bucket (list, node);
192
0
          node->value = elt;
193
0
          node->h.hashcode = new_hashcode;
194
0
          if (add_to_bucket (list, node) < 0)
195
0
            {
196
              /* Out of memory.  We removed node from a bucket but cannot add
197
                 it to another bucket.  In order to avoid inconsistencies, we
198
                 must remove node entirely from the list.  */
199
0
              gl_list_node_t before_removed = node->prev;
200
0
              gl_list_node_t after_removed = node->next;
201
0
              ASYNCSAFE(gl_list_node_t) before_removed->next = after_removed;
202
0
              after_removed->prev = before_removed;
203
0
              list->count--;
204
0
              free (node);
205
0
              return -1;
206
0
            }
207
0
        }
208
0
      else
209
0
        node->value = elt;
210
0
    }
211
#else
212
  node->value = elt;
213
#endif
214
0
  return 0;
215
0
}
216
217
static gl_list_node_t _GL_ATTRIBUTE_PURE
218
gl_linked_next_node (gl_list_t list, gl_list_node_t node)
219
0
{
220
0
  return (node->next != &list->root ? node->next : NULL);
221
0
}
222
223
static gl_list_node_t _GL_ATTRIBUTE_PURE
224
gl_linked_previous_node (gl_list_t list, gl_list_node_t node)
225
0
{
226
0
  return (node->prev != &list->root ? node->prev : NULL);
227
0
}
228
229
static gl_list_node_t _GL_ATTRIBUTE_PURE
230
gl_linked_first_node (gl_list_t list)
231
0
{
232
0
  if (list->count > 0)
233
0
    return list->root.next;
234
0
  else
235
0
    return NULL;
236
0
}
237
238
static gl_list_node_t _GL_ATTRIBUTE_PURE
239
gl_linked_last_node (gl_list_t list)
240
0
{
241
0
  if (list->count > 0)
242
0
    return list->root.prev;
243
0
  else
244
0
    return NULL;
245
0
}
246
247
static const void * _GL_ATTRIBUTE_PURE
248
gl_linked_get_at (gl_list_t list, size_t position)
249
0
{
250
0
  size_t count = list->count;
251
252
0
  if (!(position < count))
253
    /* Invalid argument.  */
254
0
    abort ();
255
  /* Here we know count > 0.  */
256
0
  gl_list_node_t node;
257
0
  if (position <= ((count - 1) / 2))
258
0
    {
259
0
      node = list->root.next;
260
0
      for (; position > 0; position--)
261
0
        node = node->next;
262
0
    }
263
0
  else
264
0
    {
265
0
      position = count - 1 - position;
266
0
      node = list->root.prev;
267
0
      for (; position > 0; position--)
268
0
        node = node->prev;
269
0
    }
270
0
  return node->value;
271
0
}
272
273
static gl_list_node_t
274
gl_linked_nx_set_at (gl_list_t list, size_t position, const void *elt)
275
  _GL_LIST_INVOKES_FN_PTR
276
0
{
277
0
  size_t count = list->count;
278
279
0
  if (!(position < count))
280
    /* Invalid argument.  */
281
0
    abort ();
282
  /* Here we know count > 0.  */
283
0
  gl_list_node_t node;
284
0
  if (position <= ((count - 1) / 2))
285
0
    {
286
0
      node = list->root.next;
287
0
      for (; position > 0; position--)
288
0
        node = node->next;
289
0
    }
290
0
  else
291
0
    {
292
0
      position = count - 1 - position;
293
0
      node = list->root.prev;
294
0
      for (; position > 0; position--)
295
0
        node = node->prev;
296
0
    }
297
0
#if WITH_HASHTABLE
298
0
  if (elt != node->value)
299
0
    {
300
0
      size_t new_hashcode =
301
0
        (list->base.hashcode_fn != NULL
302
0
         ? list->base.hashcode_fn (elt)
303
0
         : (size_t) {(uintptr_t) elt});
304
305
0
      if (new_hashcode != node->h.hashcode)
306
0
        {
307
0
          remove_from_bucket (list, node);
308
0
          node->value = elt;
309
0
          node->h.hashcode = new_hashcode;
310
0
          if (add_to_bucket (list, node) < 0)
311
0
            {
312
              /* Out of memory.  We removed node from a bucket but cannot add
313
                 it to another bucket.  In order to avoid inconsistencies, we
314
                 must remove node entirely from the list.  */
315
0
              gl_list_node_t before_removed = node->prev;
316
0
              gl_list_node_t after_removed = node->next;
317
0
              ASYNCSAFE(gl_list_node_t) before_removed->next = after_removed;
318
0
              after_removed->prev = before_removed;
319
0
              list->count--;
320
0
              free (node);
321
0
              return NULL;
322
0
            }
323
0
        }
324
0
      else
325
0
        node->value = elt;
326
0
    }
327
#else
328
  node->value = elt;
329
#endif
330
0
  return node;
331
0
}
332
333
static gl_list_node_t _GL_ATTRIBUTE_PURE
334
gl_linked_search_from_to (gl_list_t list, size_t start_index, size_t end_index,
335
                          const void *elt)
336
  _GL_LIST_INVOKES_FN_PTR
337
0
{
338
0
  size_t count = list->count;
339
340
0
  if (!(start_index <= end_index && end_index <= count))
341
    /* Invalid arguments.  */
342
0
    abort ();
343
0
  {
344
0
#if WITH_HASHTABLE
345
0
    size_t hashcode =
346
0
      (list->base.hashcode_fn != NULL
347
0
       ? list->base.hashcode_fn (elt)
348
0
       : (size_t) {(uintptr_t) elt});
349
0
    size_t bucket = hashcode % list->table_size;
350
0
    gl_listelement_equals_fn equals = list->base.equals_fn;
351
352
0
    if (!list->base.allow_duplicates)
353
0
      {
354
        /* Look for the first match in the hash bucket.  */
355
0
        gl_list_node_t found = NULL;
356
357
0
        for (gl_list_node_t node = (gl_list_node_t) list->table[bucket];
358
0
             node != NULL;
359
0
             node = (gl_list_node_t) node->h.hash_next)
360
0
          if (node->h.hashcode == hashcode
361
0
              && (equals != NULL
362
0
                  ? equals (elt, node->value)
363
0
                  : elt == node->value))
364
0
            {
365
0
              found = node;
366
0
              break;
367
0
            }
368
0
        if (start_index > 0)
369
          /* Look whether found's index is < start_index.  */
370
0
          for (gl_list_node_t node = list->root.next; ; node = node->next)
371
0
            {
372
0
              if (node == found)
373
0
                return NULL;
374
0
              if (--start_index == 0)
375
0
                break;
376
0
            }
377
0
        if (end_index < count)
378
          /* Look whether found's index is >= end_index.  */
379
0
          {
380
0
            end_index = count - end_index;
381
0
            for (gl_list_node_t node = list->root.prev; ; node = node->prev)
382
0
              {
383
0
                if (node == found)
384
0
                  return NULL;
385
0
                if (--end_index == 0)
386
0
                  break;
387
0
              }
388
0
          }
389
0
        return found;
390
0
      }
391
0
    else
392
0
      {
393
        /* Look whether there is more than one match in the hash bucket.  */
394
0
        bool multiple_matches = false;
395
0
        gl_list_node_t first_match = NULL;
396
397
0
        for (gl_list_node_t node = (gl_list_node_t) list->table[bucket];
398
0
             node != NULL;
399
0
             node = (gl_list_node_t) node->h.hash_next)
400
0
          if (node->h.hashcode == hashcode
401
0
              && (equals != NULL
402
0
                  ? equals (elt, node->value)
403
0
                  : elt == node->value))
404
0
            {
405
0
              if (first_match == NULL)
406
0
                first_match = node;
407
0
              else
408
0
                {
409
0
                  multiple_matches = true;
410
0
                  break;
411
0
                }
412
0
            }
413
0
        if (multiple_matches)
414
0
          {
415
            /* We need the match with the smallest index.  But we don't have
416
               a fast mapping node -> index.  So we have to walk the list.  */
417
0
            end_index -= start_index;
418
0
            gl_list_node_t node = list->root.next;
419
0
            for (; start_index > 0; start_index--)
420
0
              node = node->next;
421
422
0
            for (;
423
0
                 end_index > 0;
424
0
                 node = node->next, end_index--)
425
0
              if (node->h.hashcode == hashcode
426
0
                  && (equals != NULL
427
0
                      ? equals (elt, node->value)
428
0
                      : elt == node->value))
429
0
                return node;
430
            /* The matches must have all been at indices < start_index or
431
               >= end_index.  */
432
0
            return NULL;
433
0
          }
434
0
        else
435
0
          {
436
0
            if (start_index > 0)
437
              /* Look whether first_match's index is < start_index.  */
438
0
              for (gl_list_node_t node = list->root.next; node != &list->root; node = node->next)
439
0
                {
440
0
                  if (node == first_match)
441
0
                    return NULL;
442
0
                  if (--start_index == 0)
443
0
                    break;
444
0
                }
445
0
            if (end_index < list->count)
446
              /* Look whether first_match's index is >= end_index.  */
447
0
              {
448
0
                end_index = list->count - end_index;
449
0
                for (gl_list_node_t node = list->root.prev; ; node = node->prev)
450
0
                  {
451
0
                    if (node == first_match)
452
0
                      return NULL;
453
0
                    if (--end_index == 0)
454
0
                      break;
455
0
                  }
456
0
              }
457
0
            return first_match;
458
0
          }
459
0
      }
460
#else
461
    end_index -= start_index;
462
463
    gl_list_node_t node = list->root.next;
464
    for (; start_index > 0; start_index--)
465
      node = node->next;
466
467
    gl_listelement_equals_fn equals = list->base.equals_fn;
468
    if (equals != NULL)
469
      {
470
        for (; end_index > 0; node = node->next, end_index--)
471
          if (equals (elt, node->value))
472
            return node;
473
      }
474
    else
475
      {
476
        for (; end_index > 0; node = node->next, end_index--)
477
          if (elt == node->value)
478
            return node;
479
      }
480
    return NULL;
481
#endif
482
0
  }
483
0
}
484
485
static size_t _GL_ATTRIBUTE_PURE
486
gl_linked_indexof_from_to (gl_list_t list, size_t start_index, size_t end_index,
487
                           const void *elt)
488
  _GL_LIST_INVOKES_FN_PTR
489
0
{
490
0
  size_t count = list->count;
491
492
0
  if (!(start_index <= end_index && end_index <= count))
493
    /* Invalid arguments.  */
494
0
    abort ();
495
0
  {
496
0
#if WITH_HASHTABLE
497
    /* Here the hash table doesn't help much.  It only allows us to minimize
498
       the number of equals() calls, by looking up first the node and then
499
       its index.  */
500
0
    size_t hashcode =
501
0
      (list->base.hashcode_fn != NULL
502
0
       ? list->base.hashcode_fn (elt)
503
0
       : (size_t) {(uintptr_t) elt});
504
0
    size_t bucket = hashcode % list->table_size;
505
0
    gl_listelement_equals_fn equals = list->base.equals_fn;
506
507
    /* First step: Look up the node.  */
508
0
    gl_list_node_t node;
509
0
    if (!list->base.allow_duplicates)
510
0
      {
511
        /* Look for the first match in the hash bucket.  */
512
0
        for (node = (gl_list_node_t) list->table[bucket];
513
0
             node != NULL;
514
0
             node = (gl_list_node_t) node->h.hash_next)
515
0
          if (node->h.hashcode == hashcode
516
0
              && (equals != NULL
517
0
                  ? equals (elt, node->value)
518
0
                  : elt == node->value))
519
0
            break;
520
0
      }
521
0
    else
522
0
      {
523
        /* Look whether there is more than one match in the hash bucket.  */
524
0
        bool multiple_matches = false;
525
0
        gl_list_node_t first_match = NULL;
526
527
0
        for (node = (gl_list_node_t) list->table[bucket];
528
0
             node != NULL;
529
0
             node = (gl_list_node_t) node->h.hash_next)
530
0
          if (node->h.hashcode == hashcode
531
0
              && (equals != NULL
532
0
                  ? equals (elt, node->value)
533
0
                  : elt == node->value))
534
0
            {
535
0
              if (first_match == NULL)
536
0
                first_match = node;
537
0
              else
538
0
                {
539
0
                  multiple_matches = true;
540
0
                  break;
541
0
                }
542
0
            }
543
0
        if (multiple_matches)
544
0
          {
545
            /* We need the match with the smallest index.  But we don't have
546
               a fast mapping node -> index.  So we have to walk the list.  */
547
0
            size_t index = start_index;
548
0
            node = list->root.next;
549
0
            for (; start_index > 0; start_index--)
550
0
              node = node->next;
551
552
0
            for (;
553
0
                 index < end_index;
554
0
                 node = node->next, index++)
555
0
              if (node->h.hashcode == hashcode
556
0
                  && (equals != NULL
557
0
                      ? equals (elt, node->value)
558
0
                      : elt == node->value))
559
0
                return index;
560
            /* The matches must have all been at indices < start_index or
561
               >= end_index.  */
562
0
            return (size_t)(-1);
563
0
          }
564
0
        node = first_match;
565
0
      }
566
567
    /* Second step: Look up the index of the node.  */
568
0
    if (node == NULL)
569
0
      return (size_t)(-1);
570
0
    else
571
0
      {
572
0
        size_t index = 0;
573
0
        for (; node->prev != &list->root; node = node->prev)
574
0
          index++;
575
576
0
        if (index >= start_index && index < end_index)
577
0
          return index;
578
0
        else
579
0
          return (size_t)(-1);
580
0
      }
581
#else
582
    size_t index = start_index;
583
584
    gl_list_node_t node = list->root.next;
585
    for (; start_index > 0; start_index--)
586
      node = node->next;
587
588
    gl_listelement_equals_fn equals = list->base.equals_fn;
589
    if (equals != NULL)
590
      {
591
        for (;
592
             index < end_index;
593
             node = node->next, index++)
594
          if (equals (elt, node->value))
595
            return index;
596
      }
597
    else
598
      {
599
        for (;
600
             index < end_index;
601
             node = node->next, index++)
602
          if (elt == node->value)
603
            return index;
604
      }
605
    return (size_t)(-1);
606
#endif
607
0
  }
608
0
}
609
610
static gl_list_node_t
611
gl_linked_nx_add_first (gl_list_t list, const void *elt)
612
  _GL_LIST_INVOKES_FN_PTR
613
0
{
614
0
  gl_list_node_t node =
615
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
616
617
0
  if (node == NULL)
618
0
    return NULL;
619
620
0
  ASYNCSAFE(const void *) node->value = elt;
621
0
#if WITH_HASHTABLE
622
0
  node->h.hashcode =
623
0
    (list->base.hashcode_fn != NULL
624
0
     ? list->base.hashcode_fn (node->value)
625
0
     : (size_t) {(uintptr_t) node->value});
626
627
  /* Add node to the hash table.  */
628
0
  if (add_to_bucket (list, node) < 0)
629
0
    {
630
0
      free (node);
631
0
      return NULL;
632
0
    }
633
0
#endif
634
635
  /* Add node to the list.  */
636
0
  node->prev = &list->root;
637
0
  ASYNCSAFE(gl_list_node_t) node->next = list->root.next;
638
0
  node->next->prev = node;
639
0
  ASYNCSAFE(gl_list_node_t) list->root.next = node;
640
0
  list->count++;
641
642
0
#if WITH_HASHTABLE
643
0
  hash_resize_after_add (list);
644
0
#endif
645
646
0
  return node;
647
0
}
648
649
static gl_list_node_t
650
gl_linked_nx_add_last (gl_list_t list, const void *elt)
651
  _GL_LIST_INVOKES_FN_PTR
652
0
{
653
0
  gl_list_node_t node =
654
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
655
656
0
  if (node == NULL)
657
0
    return NULL;
658
659
0
  ASYNCSAFE(const void *) node->value = elt;
660
0
#if WITH_HASHTABLE
661
0
  node->h.hashcode =
662
0
    (list->base.hashcode_fn != NULL
663
0
     ? list->base.hashcode_fn (node->value)
664
0
     : (size_t) {(uintptr_t) node->value});
665
666
  /* Add node to the hash table.  */
667
0
  if (add_to_bucket (list, node) < 0)
668
0
    {
669
0
      free (node);
670
0
      return NULL;
671
0
    }
672
0
#endif
673
674
  /* Add node to the list.  */
675
0
  ASYNCSAFE(gl_list_node_t) node->next = &list->root;
676
0
  node->prev = list->root.prev;
677
0
  ASYNCSAFE(gl_list_node_t) node->prev->next = node;
678
0
  list->root.prev = node;
679
0
  list->count++;
680
681
0
#if WITH_HASHTABLE
682
0
  hash_resize_after_add (list);
683
0
#endif
684
685
0
  return node;
686
0
}
687
688
static gl_list_node_t
689
gl_linked_nx_add_before (gl_list_t list, gl_list_node_t node, const void *elt)
690
  _GL_LIST_INVOKES_FN_PTR
691
0
{
692
0
  gl_list_node_t new_node =
693
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
694
695
0
  if (new_node == NULL)
696
0
    return NULL;
697
698
0
  ASYNCSAFE(const void *) new_node->value = elt;
699
0
#if WITH_HASHTABLE
700
0
  new_node->h.hashcode =
701
0
    (list->base.hashcode_fn != NULL
702
0
     ? list->base.hashcode_fn (new_node->value)
703
0
     : (size_t) {(uintptr_t) new_node->value});
704
705
  /* Add new_node to the hash table.  */
706
0
  if (add_to_bucket (list, new_node) < 0)
707
0
    {
708
0
      free (new_node);
709
0
      return NULL;
710
0
    }
711
0
#endif
712
713
  /* Add new_node to the list.  */
714
0
  ASYNCSAFE(gl_list_node_t) new_node->next = node;
715
0
  new_node->prev = node->prev;
716
0
  ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
717
0
  node->prev = new_node;
718
0
  list->count++;
719
720
0
#if WITH_HASHTABLE
721
0
  hash_resize_after_add (list);
722
0
#endif
723
724
0
  return new_node;
725
0
}
726
727
static gl_list_node_t
728
gl_linked_nx_add_after (gl_list_t list, gl_list_node_t node, const void *elt)
729
  _GL_LIST_INVOKES_FN_PTR
730
0
{
731
0
  gl_list_node_t new_node =
732
0
    (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
733
734
0
  if (new_node == NULL)
735
0
    return NULL;
736
737
0
  ASYNCSAFE(const void *) new_node->value = elt;
738
0
#if WITH_HASHTABLE
739
0
  new_node->h.hashcode =
740
0
    (list->base.hashcode_fn != NULL
741
0
     ? list->base.hashcode_fn (new_node->value)
742
0
     : (size_t) {(uintptr_t) new_node->value});
743
744
  /* Add new_node to the hash table.  */
745
0
  if (add_to_bucket (list, new_node) < 0)
746
0
    {
747
0
      free (new_node);
748
0
      return NULL;
749
0
    }
750
0
#endif
751
752
  /* Add new_node to the list.  */
753
0
  new_node->prev = node;
754
0
  ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
755
0
  new_node->next->prev = new_node;
756
0
  ASYNCSAFE(gl_list_node_t) node->next = new_node;
757
0
  list->count++;
758
759
0
#if WITH_HASHTABLE
760
0
  hash_resize_after_add (list);
761
0
#endif
762
763
0
  return new_node;
764
0
}
765
766
static gl_list_node_t
767
gl_linked_nx_add_at (gl_list_t list, size_t position, const void *elt)
768
  _GL_LIST_INVOKES_FN_PTR
769
0
{
770
0
  size_t count = list->count;
771
0
  gl_list_node_t new_node;
772
773
0
  if (!(position <= count))
774
    /* Invalid argument.  */
775
0
    abort ();
776
777
0
  new_node = (struct gl_list_node_impl *) malloc (sizeof (struct gl_list_node_impl));
778
0
  if (new_node == NULL)
779
0
    return NULL;
780
781
0
  ASYNCSAFE(const void *) new_node->value = elt;
782
0
#if WITH_HASHTABLE
783
0
  new_node->h.hashcode =
784
0
    (list->base.hashcode_fn != NULL
785
0
     ? list->base.hashcode_fn (new_node->value)
786
0
     : (size_t) {(uintptr_t) new_node->value});
787
788
  /* Add new_node to the hash table.  */
789
0
  if (add_to_bucket (list, new_node) < 0)
790
0
    {
791
0
      free (new_node);
792
0
      return NULL;
793
0
    }
794
0
#endif
795
796
  /* Add new_node to the list.  */
797
0
  if (position <= (count / 2))
798
0
    {
799
0
      gl_list_node_t node = &list->root;
800
0
      for (; position > 0; position--)
801
0
        node = node->next;
802
803
0
      new_node->prev = node;
804
0
      ASYNCSAFE(gl_list_node_t) new_node->next = node->next;
805
0
      new_node->next->prev = new_node;
806
0
      ASYNCSAFE(gl_list_node_t) node->next = new_node;
807
0
    }
808
0
  else
809
0
    {
810
0
      position = count - position;
811
812
0
      gl_list_node_t node = &list->root;
813
0
      for (; position > 0; position--)
814
0
        node = node->prev;
815
816
0
      ASYNCSAFE(gl_list_node_t) new_node->next = node;
817
0
      new_node->prev = node->prev;
818
0
      ASYNCSAFE(gl_list_node_t) new_node->prev->next = new_node;
819
0
      node->prev = new_node;
820
0
    }
821
0
  list->count++;
822
823
0
#if WITH_HASHTABLE
824
0
  hash_resize_after_add (list);
825
0
#endif
826
827
0
  return new_node;
828
0
}
829
830
static bool
831
gl_linked_remove_node (gl_list_t list, gl_list_node_t node)
832
  _GL_LIST_INVOKES_FN_PTR
833
0
{
834
0
#if WITH_HASHTABLE
835
  /* Remove node from the hash table.  */
836
0
  remove_from_bucket (list, node);
837
0
#endif
838
839
  /* Remove node from the list.  */
840
0
  gl_list_node_t prev = node->prev;
841
0
  gl_list_node_t next = node->next;
842
843
0
  ASYNCSAFE(gl_list_node_t) prev->next = next;
844
0
  next->prev = prev;
845
0
  list->count--;
846
847
0
  if (list->base.dispose_fn != NULL)
848
0
    list->base.dispose_fn (node->value);
849
0
  free (node);
850
0
  return true;
851
0
}
852
853
static bool
854
gl_linked_remove_at (gl_list_t list, size_t position)
855
  _GL_LIST_INVOKES_FN_PTR
856
0
{
857
0
  size_t count = list->count;
858
859
0
  if (!(position < count))
860
    /* Invalid argument.  */
861
0
    abort ();
862
  /* Here we know count > 0.  */
863
0
  gl_list_node_t removed_node;
864
0
  if (position <= ((count - 1) / 2))
865
0
    {
866
0
      gl_list_node_t node = &list->root;
867
0
      for (; position > 0; position--)
868
0
        node = node->next;
869
870
0
      removed_node = node->next;
871
0
      gl_list_node_t after_removed = node->next->next;
872
0
      ASYNCSAFE(gl_list_node_t) node->next = after_removed;
873
0
      after_removed->prev = node;
874
0
    }
875
0
  else
876
0
    {
877
0
      position = count - 1 - position;
878
879
0
      gl_list_node_t node = &list->root;
880
0
      for (; position > 0; position--)
881
0
        node = node->prev;
882
883
0
      removed_node = node->prev;
884
0
      gl_list_node_t before_removed = node->prev->prev;
885
0
      node->prev = before_removed;
886
0
      ASYNCSAFE(gl_list_node_t) before_removed->next = node;
887
0
    }
888
0
#if WITH_HASHTABLE
889
0
  remove_from_bucket (list, removed_node);
890
0
#endif
891
0
  list->count--;
892
893
0
  if (list->base.dispose_fn != NULL)
894
0
    list->base.dispose_fn (removed_node->value);
895
0
  free (removed_node);
896
0
  return true;
897
0
}
898
899
static bool
900
gl_linked_remove (gl_list_t list, const void *elt)
901
0
{
902
0
  gl_list_node_t node = gl_linked_search_from_to (list, 0, list->count, elt);
903
904
0
  if (node != NULL)
905
0
    return gl_linked_remove_node (list, node);
906
0
  else
907
0
    return false;
908
0
}
909
910
static void
911
gl_linked_list_free (gl_list_t list)
912
  _GL_LIST_INVOKES_FN_PTR
913
0
{
914
0
  gl_listelement_dispose_fn dispose = list->base.dispose_fn;
915
916
0
  for (gl_list_node_t node = list->root.next; node != &list->root; )
917
0
    {
918
0
      gl_list_node_t next = node->next;
919
0
      if (dispose != NULL)
920
0
        dispose (node->value);
921
0
      free (node);
922
0
      node = next;
923
0
    }
924
0
#if WITH_HASHTABLE
925
0
  free (list->table);
926
0
#endif
927
0
  free (list);
928
0
}
929
930
/* --------------------- gl_list_iterator_t Data Type --------------------- */
931
932
static gl_list_iterator_t _GL_ATTRIBUTE_PURE
933
gl_linked_iterator (gl_list_t list)
934
0
{
935
0
  gl_list_iterator_t result;
936
937
0
  result.vtable = list->base.vtable;
938
0
  result.list = list;
939
0
  result.p = list->root.next;
940
0
  result.q = &list->root;
941
#if defined GCC_LINT || defined lint
942
  result.i = 0;
943
  result.j = 0;
944
  result.count = 0;
945
#endif
946
947
0
  return result;
948
0
}
949
950
static gl_list_iterator_t _GL_ATTRIBUTE_PURE
951
gl_linked_iterator_from_to (gl_list_t list,
952
                            size_t start_index, size_t end_index)
953
0
{
954
0
  gl_list_iterator_t result;
955
0
  size_t n1, n2, n3;
956
957
0
  if (!(start_index <= end_index && end_index <= list->count))
958
    /* Invalid arguments.  */
959
0
    abort ();
960
0
  result.vtable = list->base.vtable;
961
0
  result.list = list;
962
0
  n1 = start_index;
963
0
  n2 = end_index - start_index;
964
0
  n3 = list->count - end_index;
965
  /* Find the maximum among n1, n2, n3, so as to reduce the number of
966
     loop iterations to n1 + n2 + n3 - max(n1,n2,n3).  */
967
0
  if (n1 > n2 && n1 > n3)
968
0
    {
969
      /* n1 is the maximum, use n2 and n3.  */
970
0
      gl_list_node_t node = &list->root;
971
0
      for (size_t i = n3; i > 0; i--)
972
0
        node = node->prev;
973
0
      result.q = node;
974
975
0
      for (size_t i = n2; i > 0; i--)
976
0
        node = node->prev;
977
0
      result.p = node;
978
0
    }
979
0
  else if (n2 > n3)
980
0
    {
981
      /* n2 is the maximum, use n1 and n3.  */
982
0
      gl_list_node_t node = list->root.next;
983
0
      for (size_t i = n1; i > 0; i--)
984
0
        node = node->next;
985
0
      result.p = node;
986
987
0
      node = &list->root;
988
0
      for (size_t i = n3; i > 0; i--)
989
0
        node = node->prev;
990
0
      result.q = node;
991
0
    }
992
0
  else
993
0
    {
994
      /* n3 is the maximum, use n1 and n2.  */
995
0
      gl_list_node_t node = list->root.next;
996
0
      for (size_t i = n1; i > 0; i--)
997
0
        node = node->next;
998
0
      result.p = node;
999
1000
0
      for (size_t i = n2; i > 0; i--)
1001
0
        node = node->next;
1002
0
      result.q = node;
1003
0
    }
1004
1005
#if defined GCC_LINT || defined lint
1006
  result.i = 0;
1007
  result.j = 0;
1008
  result.count = 0;
1009
#endif
1010
1011
0
  return result;
1012
0
}
1013
1014
static bool
1015
gl_linked_iterator_next (gl_list_iterator_t *iterator,
1016
                         const void **eltp, gl_list_node_t *nodep)
1017
0
{
1018
0
  if (iterator->p != iterator->q)
1019
0
    {
1020
0
      gl_list_node_t node = (gl_list_node_t) iterator->p;
1021
0
      *eltp = node->value;
1022
0
      if (nodep != NULL)
1023
0
        *nodep = node;
1024
0
      iterator->p = node->next;
1025
0
      return true;
1026
0
    }
1027
0
  else
1028
0
    return false;
1029
0
}
1030
1031
static void
1032
gl_linked_iterator_free (gl_list_iterator_t *_GL_UNNAMED (iterator))
1033
0
{
1034
0
}
1035
1036
/* ---------------------- Sorted gl_list_t Data Type ---------------------- */
1037
1038
static gl_list_node_t _GL_ATTRIBUTE_PURE
1039
gl_linked_sortedlist_search (gl_list_t list, gl_listelement_compar_fn compar,
1040
                             const void *elt)
1041
  _GL_LIST_INVOKES_FN_PTR
1042
0
{
1043
0
  for (gl_list_node_t node = list->root.next; node != &list->root; node = node->next)
1044
0
    {
1045
0
      int cmp = compar (node->value, elt);
1046
1047
0
      if (cmp > 0)
1048
0
        break;
1049
0
      if (cmp == 0)
1050
0
        return node;
1051
0
    }
1052
0
  return NULL;
1053
0
}
1054
1055
static gl_list_node_t _GL_ATTRIBUTE_PURE
1056
gl_linked_sortedlist_search_from_to (gl_list_t list,
1057
                                     gl_listelement_compar_fn compar,
1058
                                     size_t low, size_t high,
1059
                                     const void *elt)
1060
  _GL_LIST_INVOKES_FN_PTR
1061
0
{
1062
0
  size_t count = list->count;
1063
1064
0
  if (!(low <= high && high <= list->count))
1065
    /* Invalid arguments.  */
1066
0
    abort ();
1067
1068
0
  high -= low;
1069
0
  if (high > 0)
1070
0
    {
1071
      /* Here we know low < count.  */
1072
0
      size_t position = low;
1073
1074
0
      gl_list_node_t node;
1075
0
      if (position <= ((count - 1) / 2))
1076
0
        {
1077
0
          node = list->root.next;
1078
0
          for (; position > 0; position--)
1079
0
            node = node->next;
1080
0
        }
1081
0
      else
1082
0
        {
1083
0
          position = count - 1 - position;
1084
0
          node = list->root.prev;
1085
0
          for (; position > 0; position--)
1086
0
            node = node->prev;
1087
0
        }
1088
1089
0
      do
1090
0
        {
1091
0
          int cmp = compar (node->value, elt);
1092
1093
0
          if (cmp > 0)
1094
0
            break;
1095
0
          if (cmp == 0)
1096
0
            return node;
1097
0
          node = node->next;
1098
0
        }
1099
0
      while (--high > 0);
1100
0
    }
1101
0
  return NULL;
1102
0
}
1103
1104
static size_t _GL_ATTRIBUTE_PURE
1105
gl_linked_sortedlist_indexof (gl_list_t list, gl_listelement_compar_fn compar,
1106
                              const void *elt)
1107
  _GL_LIST_INVOKES_FN_PTR
1108
0
{
1109
0
  gl_list_node_t node;
1110
0
  size_t index;
1111
1112
0
  for (node = list->root.next, index = 0;
1113
0
       node != &list->root;
1114
0
       node = node->next, index++)
1115
0
    {
1116
0
      int cmp = compar (node->value, elt);
1117
1118
0
      if (cmp > 0)
1119
0
        break;
1120
0
      if (cmp == 0)
1121
0
        return index;
1122
0
    }
1123
0
  return (size_t)(-1);
1124
0
}
1125
1126
static size_t _GL_ATTRIBUTE_PURE
1127
gl_linked_sortedlist_indexof_from_to (gl_list_t list,
1128
                                      gl_listelement_compar_fn compar,
1129
                                      size_t low, size_t high,
1130
                                      const void *elt)
1131
  _GL_LIST_INVOKES_FN_PTR
1132
0
{
1133
0
  size_t count = list->count;
1134
1135
0
  if (!(low <= high && high <= list->count))
1136
    /* Invalid arguments.  */
1137
0
    abort ();
1138
1139
0
  high -= low;
1140
0
  if (high > 0)
1141
0
    {
1142
      /* Here we know low < count.  */
1143
0
      size_t index = low;
1144
0
      size_t position = low;
1145
1146
0
      gl_list_node_t node;
1147
0
      if (position <= ((count - 1) / 2))
1148
0
        {
1149
0
          node = list->root.next;
1150
0
          for (; position > 0; position--)
1151
0
            node = node->next;
1152
0
        }
1153
0
      else
1154
0
        {
1155
0
          position = count - 1 - position;
1156
0
          node = list->root.prev;
1157
0
          for (; position > 0; position--)
1158
0
            node = node->prev;
1159
0
        }
1160
1161
0
      do
1162
0
        {
1163
0
          int cmp = compar (node->value, elt);
1164
1165
0
          if (cmp > 0)
1166
0
            break;
1167
0
          if (cmp == 0)
1168
0
            return index;
1169
0
          node = node->next;
1170
0
          index++;
1171
0
        }
1172
0
      while (--high > 0);
1173
0
    }
1174
0
  return (size_t)(-1);
1175
0
}
1176
1177
static gl_list_node_t
1178
gl_linked_sortedlist_nx_add (gl_list_t list, gl_listelement_compar_fn compar,
1179
                             const void *elt)
1180
  _GL_LIST_INVOKES_FN_PTR
1181
0
{
1182
0
  for (gl_list_node_t node = list->root.next; node != &list->root; node = node->next)
1183
0
    if (compar (node->value, elt) >= 0)
1184
0
      return gl_linked_nx_add_before (list, node, elt);
1185
0
  return gl_linked_nx_add_last (list, elt);
1186
0
}
1187
1188
static bool
1189
gl_linked_sortedlist_remove (gl_list_t list, gl_listelement_compar_fn compar,
1190
                             const void *elt)
1191
  _GL_LIST_INVOKES_FN_PTR
1192
0
{
1193
0
  for (gl_list_node_t node = list->root.next; node != &list->root; node = node->next)
1194
0
    {
1195
0
      int cmp = compar (node->value, elt);
1196
1197
0
      if (cmp > 0)
1198
0
        break;
1199
0
      if (cmp == 0)
1200
0
        return gl_linked_remove_node (list, node);
1201
0
    }
1202
0
  return false;
1203
0
}