Coverage Report

Created: 2026-03-31 07:20

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