Coverage Report

Created: 2026-03-10 08:46

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/binutils-gdb/include/doubly-linked-list.h
Line
Count
Source
1
/* Manipulate doubly linked lists.
2
   Copyright (C) 2025-2026 Free Software Foundation, Inc.
3
4
   This program is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3 of the License, or
7
   (at your option) any later version.
8
9
   This program is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17
18
#ifndef _DOUBLY_LINKED_LIST_H
19
#define _DOUBLY_LINKED_LIST_H
20
21
/* Doubly linked list implementation enforcing typing.
22
23
   This implementation of doubly linked list tries to achieve the enforcement of
24
   typing similarly to C++ templates, but without encapsulation.
25
26
   All the functions are prefixed with the type of the value: "AType_xxx".
27
   Some functions are prefixed with "_AType_xxx" and are not part of the public
28
   API, so should not be used, except for _##LTYPE##_merge_sort with a caveat
29
   (see note above its definition).
30
31
   Each function (### is a placeholder for method name) has a macro for:
32
   (1) its invocation LINKED_LIST_###(LTYPE).
33
   (2) its prototype LINKED_LIST_DECL_###(A, A2, scope). To add in a header
34
       file, or a source file for forward declaration. 'scope' should be set
35
       respectively to 'extern', or 'static'.
36
   (3) its definition LINKED_LIST_DEFN_###(A, A2, scope). To add in a source
37
       file with the 'scope' set respectively to nothing, or 'static' depending
38
       on (2).
39
40
   Data structures requirements:
41
   - LTYPE corresponds to the node of a doubly linked list. It needs to define
42
     attributes 'prev' and 'next' which are pointers on the type of a node.
43
     For instance:
44
       struct my_list_node
45
       {
46
   T value;
47
   struct my_list_node *prev;
48
   struct my_list_node *next;
49
       };
50
   - LWRAPPERTYPE is a structure wrapping the nodes and others metadata (first,
51
     last, size).
52
 */
53
54

55
/* Mutative operations:
56
    - append
57
    - prepend
58
    - insert_before
59
    - pop_front
60
    - pop_back
61
    - remove
62
    - swap
63
   The header and body of each of those operation can be declared individually,
64
   or as a whole via LINKED_LIST_MUTATIVE_OPS_PROTOTYPE for the prototypes, and
65
   LINKED_LIST_MUTATIVE_OPS_DECL for the implementations.  */
66
67
/* Append the given node new_ to the exising list.
68
   Precondition: prev and next of new_ must be NULL.  */
69
38.6k
#define LINKED_LIST_APPEND(LTYPE)   LTYPE##_append
70
71
#define LINKED_LIST_DECL_APPEND(LWRAPPERTYPE, LTYPE, EXPORT)    \
72
  EXPORT void               \
73
  LTYPE##_append (LWRAPPERTYPE *wrapper, LTYPE *new_)
74
75
#define LINKED_LIST_DEFN_APPEND(LWRAPPERTYPE, LTYPE, EXPORT)    \
76
EXPORT void               \
77
38.6k
LTYPE##_append (LWRAPPERTYPE *wrapper, LTYPE *new_)     \
78
38.6k
{                 \
79
38.6k
  if (wrapper->last == NULL)           \
80
38.6k
    wrapper->first = new_;           \
81
38.6k
  else                  \
82
38.6k
    {                 \
83
38.2k
      new_->prev = wrapper->last;         \
84
38.2k
      wrapper->last->next = new_;         \
85
38.2k
    }                  \
86
38.6k
  wrapper->last = new_;             \
87
38.6k
  ++wrapper->size;              \
88
38.6k
}
89
90
/* Prepend the given node new_ to the existing list.
91
   Precondition: prev and next of new_ must be NULL.  */
92
#define LINKED_LIST_PREPEND(LTYPE)    LTYPE##_prepend
93
94
#define LINKED_LIST_DECL_PREPEND(LWRAPPERTYPE, LTYPE, EXPORT)   \
95
  EXPORT void               \
96
  LTYPE##_prepend (LWRAPPERTYPE *wrapper, LTYPE *new_)
97
98
#define LINKED_LIST_DEFN_PREPEND(LWRAPPERTYPE, LTYPE, EXPORT)   \
99
EXPORT void               \
100
0
LTYPE##_prepend (LWRAPPERTYPE *wrapper, LTYPE *new_)      \
101
0
{                 \
102
0
  if (wrapper->first == NULL)           \
103
0
    wrapper->last = new_;           \
104
0
  else                  \
105
0
    {                 \
106
0
      new_->next = wrapper->first;          \
107
0
      wrapper->first->prev = new_;          \
108
0
    }                  \
109
0
  wrapper->first = new_;            \
110
0
  ++wrapper->size;              \
111
0
}
112
113
/* Insert the given node new_ before 'where' in the existing list.
114
   If where == NULL, the insertion is equivalent to an append.
115
   If where == first, the insertion is equivalent to a prepend.  */
116
0
#define LINKED_LIST_INSERT_BEFORE(LTYPE)  LTYPE##_insert_before
117
118
#define LINKED_LIST_DECL_INSERT_BEFORE(LWRAPPERTYPE, LTYPE, EXPORT) \
119
  EXPORT void               \
120
  LTYPE##_insert_before (LWRAPPERTYPE *wrapper,       \
121
       LTYPE *new_,         \
122
       LTYPE *where)
123
124
#define LINKED_LIST_DEFN_INSERT_BEFORE(LWRAPPERTYPE, LTYPE, EXPORT) \
125
EXPORT void               \
126
LTYPE##_insert_before (LWRAPPERTYPE *wrapper,       \
127
           LTYPE *new_,         \
128
0
           LTYPE *where)          \
129
0
{                 \
130
0
  if (where == wrapper->first)           \
131
0
    LTYPE##_prepend (wrapper, new_);         \
132
0
  else if (where == NULL)           \
133
0
    LTYPE##_append (wrapper, new_);          \
134
0
  else                  \
135
0
    {                 \
136
0
      where->prev->next = new_;           \
137
0
      new_->prev = where->prev;           \
138
0
      where->prev = new_;           \
139
0
      new_->next = where;           \
140
0
      ++wrapper->size;              \
141
0
    }                  \
142
0
}
143
144
/* Pop the first node of the list.  */
145
#define LINKED_LIST_POP_FRONT(LTYPE)    LTYPE##_pop_front
146
147
#define LINKED_LIST_DECL_POP_FRONT(LWRAPPERTYPE, LTYPE, EXPORT)   \
148
  EXPORT LTYPE *              \
149
  LTYPE##_pop_front (LWRAPPERTYPE *wrapper)
150
151
#define LINKED_LIST_DEFN_POP_FRONT(LWRAPPERTYPE, LTYPE, EXPORT)   \
152
EXPORT LTYPE *                \
153
224
LTYPE##_pop_front (LWRAPPERTYPE *wrapper)       \
154
224
{                 \
155
224
  LTYPE *front_node = wrapper->first;         \
156
224
  if (front_node != NULL)           \
157
224
    {                 \
158
224
      wrapper->first = front_node->next;        \
159
224
      if (wrapper->last == front_node)         \
160
224
  wrapper->last = NULL;           \
161
224
      else                \
162
224
  {               \
163
81
    front_node->next->prev = NULL;        \
164
81
    front_node->next = NULL;          \
165
81
  }                \
166
224
      front_node->next = NULL;            \
167
224
      --wrapper->size;              \
168
224
    }                 \
169
224
  return front_node;              \
170
224
}
171
172
/* Pop the last node of the list.  */
173
#define LINKED_LIST_POP_BACK(LTYPE)   LTYPE##_pop_back
174
175
#define LINKED_LIST_DECL_POP_BACK(LWRAPPERTYPE, LTYPE, EXPORT)    \
176
  EXPORT LTYPE *              \
177
  LTYPE##_pop_back (LWRAPPERTYPE *wrapper)
178
179
#define LINKED_LIST_DEFN_POP_BACK(LWRAPPERTYPE, LTYPE, EXPORT)    \
180
EXPORT LTYPE *                \
181
0
LTYPE##_pop_back (LWRAPPERTYPE *wrapper)        \
182
0
{                 \
183
0
  LTYPE *back_node = wrapper->last;         \
184
0
  if (back_node != NULL)           \
185
0
    {                 \
186
0
      wrapper->last = back_node->prev;          \
187
0
      if (wrapper->first == back_node)         \
188
0
  wrapper->first = NULL;           \
189
0
      else                \
190
0
  {               \
191
0
    back_node->prev->next = NULL;         \
192
0
    back_node->prev = NULL;         \
193
0
  }                \
194
0
      back_node->prev = NULL;           \
195
0
      --wrapper->size;              \
196
0
    }                 \
197
0
  return back_node;             \
198
0
}
199
200
/* Remove the given node from the existing list, and return the previous
201
   node.  */
202
224
#define LINKED_LIST_REMOVE(LTYPE)   LTYPE##_remove
203
204
#define LINKED_LIST_DECL_REMOVE(LWRAPPERTYPE, LTYPE, EXPORT)    \
205
  EXPORT LTYPE *              \
206
  LTYPE##_remove (LWRAPPERTYPE *wrapper, LTYPE *node)
207
208
#define LINKED_LIST_DEFN_REMOVE(LWRAPPERTYPE, LTYPE, EXPORT)    \
209
EXPORT LTYPE *                \
210
224
LTYPE##_remove (LWRAPPERTYPE *wrapper, LTYPE *node)     \
211
224
{                 \
212
224
  LTYPE *previous = NULL;           \
213
224
                  \
214
224
  if (node->prev != NULL)           \
215
224
    {                 \
216
0
      node->prev->next = node->next;          \
217
0
      if (node->next == NULL)           \
218
0
  wrapper->last = node->prev;         \
219
0
      else                \
220
0
  node->next->prev = node->prev;         \
221
0
      previous = node->prev;            \
222
0
      node->next = NULL;            \
223
0
      node->prev = NULL;            \
224
0
      --wrapper->size;              \
225
0
    }                  \
226
224
  else                  \
227
224
    LTYPE##_pop_front (wrapper);         \
228
224
                  \
229
224
  return previous;              \
230
224
}
231
232
/* Swap two nodes in a list.  */
233
#define LINKED_LIST_SWAP(LTYPE)     LTYPE##_swap
234
235
#define LINKED_LIST_DECL_SWAP(LWRAPPERTYPE, LTYPE, EXPORT)    \
236
  EXPORT void               \
237
  LTYPE##_swap (LWRAPPERTYPE *wrapper, LTYPE *node1, LTYPE *node2)
238
239
#define LINKED_LIST_DEFN_SWAP(LWRAPPERTYPE, LTYPE, EXPORT)    \
240
EXPORT void               \
241
0
LTYPE##_swap (LWRAPPERTYPE *wrapper, LTYPE *node1, LTYPE *node2)  \
242
0
{                 \
243
0
  LTYPE *prev1 = node1->prev;           \
244
0
  LTYPE *next1 = node1->next;           \
245
0
  LTYPE *prev2 = node2->prev;           \
246
0
  LTYPE *next2 = node2->next;           \
247
0
                  \
248
0
  if (prev1 != NULL)             \
249
0
    prev1->next = node2;           \
250
0
  else                  \
251
0
    wrapper->first = node2;           \
252
0
  if (prev2 != NULL)             \
253
0
    prev2->next = node1;           \
254
0
  else                  \
255
0
    wrapper->first = node1;           \
256
0
                  \
257
0
  if (next1 != NULL)             \
258
0
    next1->prev = node2;           \
259
0
  else                  \
260
0
    wrapper->last = node2;           \
261
0
  if (next2 != NULL)             \
262
0
    next2->prev = node1;           \
263
0
  else                  \
264
0
    wrapper->last = node1;           \
265
0
                  \
266
0
  {                 \
267
0
    LTYPE *temp = node1->next;            \
268
0
    node1->next = node2->next;            \
269
0
    node2->next = temp;             \
270
0
  }                 \
271
0
  {                 \
272
0
    LTYPE *temp = node1->prev;            \
273
0
    node1->prev = node2->prev;            \
274
0
    node2->prev = temp;             \
275
0
  }                 \
276
0
}
277
278
/* Swap two lists, i.e. swap two wrappers.  */
279
0
#define LINKED_LIST_SWAP_LISTS(LWRAPPERTYPE)  LWRAPPERTYPE##_swap_lists
280
281
#define LINKED_LIST_DECL_SWAP_LISTS(LWRAPPERTYPE, LTYPE, EXPORT)  \
282
  EXPORT void               \
283
  LWRAPPERTYPE##_swap_lists (LWRAPPERTYPE *left_w, LWRAPPERTYPE *right_w)
284
285
#define LINKED_LIST_DEFN_SWAP_LISTS(LWRAPPERTYPE, LTYPE, EXPORT)  \
286
EXPORT void               \
287
0
LWRAPPERTYPE##_swap_lists (LWRAPPERTYPE *left_w, LWRAPPERTYPE *right_w) \
288
0
{                 \
289
0
  {                 \
290
0
    LTYPE *temp = left_w->first;          \
291
0
    left_w->first = right_w->first;         \
292
0
    right_w->first = temp;            \
293
0
  }                 \
294
0
  {                 \
295
0
    LTYPE *temp = left_w->last;           \
296
0
    left_w->last = right_w->last;         \
297
0
    right_w->last = temp;           \
298
0
  }                 \
299
0
  {                 \
300
0
    unsigned int temp = left_w->size;         \
301
0
    left_w->size = right_w->size;         \
302
0
    right_w->size = temp;           \
303
0
  }                 \
304
0
}
Unexecuted instantiation: obj_attr_subsection_v2_t_swap_lists
Unexecuted instantiation: obj_attr_subsection_list_t_swap_lists
305
306
/* Note: all the mutative operations below also update the data in the wrapper,
307
   i.e. first, last and size.  */
308
#define LINKED_LIST_MUTATIVE_OPS_PROTOTYPE(LWRAPPERTYPE, LTYPE, EXPORT) \
309
  LINKED_LIST_DECL_APPEND(LWRAPPERTYPE, LTYPE, EXPORT);     \
310
  LINKED_LIST_DECL_PREPEND(LWRAPPERTYPE, LTYPE, EXPORT);    \
311
  LINKED_LIST_DECL_INSERT_BEFORE(LWRAPPERTYPE, LTYPE, EXPORT);    \
312
  LINKED_LIST_DECL_POP_FRONT(LWRAPPERTYPE, LTYPE, EXPORT);    \
313
  LINKED_LIST_DECL_POP_BACK(LWRAPPERTYPE, LTYPE, EXPORT);   \
314
  LINKED_LIST_DECL_REMOVE(LWRAPPERTYPE, LTYPE, EXPORT);     \
315
  LINKED_LIST_DECL_SWAP(LWRAPPERTYPE, LTYPE, EXPORT);     \
316
  LINKED_LIST_DECL_SWAP_LISTS(LWRAPPERTYPE, LTYPE, EXPORT)
317
318
#define LINKED_LIST_MUTATIVE_OPS_DECL(LWRAPPERTYPE, LTYPE, EXPORT)  \
319
  LINKED_LIST_DEFN_APPEND(LWRAPPERTYPE, LTYPE, EXPORT)      \
320
  LINKED_LIST_DEFN_PREPEND(LWRAPPERTYPE, LTYPE, EXPORT)     \
321
  LINKED_LIST_DEFN_INSERT_BEFORE(LWRAPPERTYPE, LTYPE, EXPORT)   \
322
  LINKED_LIST_DEFN_POP_FRONT(LWRAPPERTYPE, LTYPE, EXPORT)   \
323
  LINKED_LIST_DEFN_POP_BACK(LWRAPPERTYPE, LTYPE, EXPORT)    \
324
  LINKED_LIST_DEFN_REMOVE(LWRAPPERTYPE, LTYPE, EXPORT)      \
325
  LINKED_LIST_DEFN_SWAP(LWRAPPERTYPE, LTYPE, EXPORT);     \
326
  LINKED_LIST_DEFN_SWAP_LISTS(LWRAPPERTYPE, LTYPE, EXPORT)
327
328

329
/* Sorting.  */
330
331
#define LINKED_LIST_MERGE_SORT_(LTYPE)  LTYPE##_merge_sort_
332
333
0
#define LINKED_LIST_MERGE_SORT(LTYPE) LTYPE##_merge_sort
334
335
#define LINKED_LIST_MERGE_SORT_PROTOTYPE_(LTYPE, EXPORT)    \
336
  EXPORT LTYPE *              \
337
  LTYPE##_merge_sort_ (LTYPE *node,         \
338
           int (*fn_cmp) (const LTYPE *, const LTYPE *))
339
340
#define LINKED_LIST_MERGE_SORT_PROTOTYPE(LWRAPPERTYPE, LTYPE, EXPORT) \
341
  EXPORT void               \
342
  LTYPE##_merge_sort (LWRAPPERTYPE *wrapper,        \
343
          int (*fn_cmp) (const LTYPE *, const LTYPE *))
344
345
/* Note: all the functions and macros below starting with "_" should be
346
   considered private.  */
347
348
/* Compute the middle element of the list based on the turtle and hare
349
   approach, i.e. the hare runs twice faster than the turtle.  */
350
#define _MERGE_SORT_IMPL_COMPUTE_TURTLE(LTYPE)        \
351
static inline LTYPE *             \
352
0
LTYPE##_merge_sort_compute_turtle_ (LTYPE *node)      \
353
0
{                 \
354
0
  if (node == NULL)             \
355
0
    return node;             \
356
0
                  \
357
0
  LTYPE *turtle = node, *hare = node->next;       \
358
0
  while (hare != NULL && hare->next != NULL)       \
359
0
    {                 \
360
0
      turtle = turtle->next;            \
361
0
      hare = hare->next->next;            \
362
0
    }                  \
363
0
  return turtle;              \
364
0
}
365
366
/* Append n at the end of l_out, and return the next node after n.
367
   l_out and l_last should be ideally encapsulated into a list structure
368
   but this is overkill for what we need here.  */
369
#define _MERGE_SORT_IMPL_OUT_APPEND(LTYPE)        \
370
static inline LTYPE *             \
371
LTYPE##_merge_sort_out_append_ (LTYPE **l_out, LTYPE **l_last,    \
372
0
        LTYPE *n)       \
373
0
{                 \
374
0
  if (*l_last == NULL)             \
375
0
    {                 \
376
0
      *l_last = n;              \
377
0
      *l_out = n;             \
378
0
      n->prev = NULL;             \
379
0
    }                  \
380
0
  else                  \
381
0
    {                 \
382
0
      (*l_last)->next = n;            \
383
0
      n->prev = *l_last;            \
384
0
      *l_last = n;              \
385
0
    }                  \
386
0
                  \
387
0
  return n->next;             \
388
0
}
389
390
/* Merge two sorted lists together.
391
   The returned value corresponds to the first element of the list.
392
   Note: both input lists are invalidated after the call.  */
393
#define _MERGE_SORT_IMPL_MERGE(LTYPE)         \
394
static inline LTYPE *             \
395
LTYPE##_merge_sort_merge_ (LTYPE *l_left, LTYPE *l_right,   \
396
0
         int (*fn_cmp) (const LTYPE *, const LTYPE *))\
397
0
{                 \
398
0
  if (l_left == NULL)             \
399
0
    return l_right;             \
400
0
  else if (l_right == NULL)           \
401
0
    return l_left;             \
402
0
                  \
403
0
  LTYPE *l_out = NULL, *l_last = NULL;          \
404
0
                  \
405
0
  LTYPE *l_l = l_left, *l_r = l_right;          \
406
0
  while (l_l != NULL && l_r != NULL)         \
407
0
    {                 \
408
0
      int cmp = fn_cmp (l_l, l_r);          \
409
0
      if (cmp <= 0)             \
410
0
  l_l = LTYPE##_merge_sort_out_append_ (&l_out, &l_last, l_l); \
411
0
      else                \
412
0
  l_r = LTYPE##_merge_sort_out_append_ (&l_out, &l_last, l_r); \
413
0
    }                 \
414
0
                  \
415
0
  LTYPE *l_remaining = (l_l != NULL) ? l_l : l_r;     \
416
0
  while (l_remaining != NULL)           \
417
0
    l_remaining =             \
418
0
      LTYPE##_merge_sort_out_append_ (&l_out, &l_last, l_remaining); \
419
0
                  \
420
0
  return l_out;               \
421
0
}
422
423
/* Merge sort implementation taking the first node of the list to sort,
424
   and the comparison function. Returns the first node of the sorted list.
425
   Note: use this if you don't care about updating the information in the
426
   wrapper.  */
427
#define _MERGE_SORT_DEFN_SORT(LTYPE, EXPORT)        \
428
EXPORT LTYPE *                \
429
LTYPE##_merge_sort_ (LTYPE *node,         \
430
0
         int (*fn_cmp)(const LTYPE *, const LTYPE *)) \
431
0
{                 \
432
0
  if (node == NULL)             \
433
0
    return NULL;             \
434
0
  else if (node->next == NULL)           \
435
0
    return node;             \
436
0
                  \
437
0
  LTYPE *left_end = LTYPE##_merge_sort_compute_turtle_ (node);   \
438
0
  LTYPE *left_begin = node;           \
439
0
  LTYPE *right_begin = left_end->next;          \
440
0
  /* break the list. */             \
441
0
  left_end->next = NULL;            \
442
0
  right_begin->prev = NULL;           \
443
0
                  \
444
0
  left_begin = LTYPE##_merge_sort_ (left_begin, fn_cmp);    \
445
0
  right_begin = LTYPE##_merge_sort_ (right_begin, fn_cmp);   \
446
0
  return LTYPE##_merge_sort_merge_ (left_begin, right_begin, fn_cmp); \
447
0
}
448
449
/* Merge sort wrapper that the end-user should be using as it updates the
450
   first and last metadata of the list in wrapper as well.
451
   If the user does not want to pay the cost of the update of the data,
452
   it can directly use _##LTYPE##_merge_sort_merge.  */
453
#define _MERGE_SORT_DEFN_WRAPPER_SORT(LWRAPPERTYPE, LTYPE, EXPORT)  \
454
EXPORT void               \
455
LTYPE##_merge_sort (LWRAPPERTYPE *wrapper,        \
456
0
        int (*fn_cmp) (const LTYPE *, const LTYPE *)) \
457
0
{                 \
458
0
  wrapper->first = LTYPE##_merge_sort_ (wrapper->first, fn_cmp);  \
459
0
                  \
460
0
  if (wrapper->first == NULL || wrapper->first->next == NULL)   \
461
0
    wrapper->last = wrapper->first;         \
462
0
  else                  \
463
0
    for (LTYPE *node = wrapper->first;          \
464
0
   node != NULL;             \
465
0
   node = node->next)           \
466
0
      wrapper->last = node;           \
467
0
}
468
469
#define LINKED_LIST_MERGE_SORT_DECL(LWRAPPERTYPE, LTYPE, EXPORT)  \
470
  _MERGE_SORT_IMPL_COMPUTE_TURTLE(LTYPE)        \
471
  _MERGE_SORT_IMPL_OUT_APPEND(LTYPE)          \
472
  _MERGE_SORT_IMPL_MERGE(LTYPE)           \
473
  _MERGE_SORT_DEFN_SORT(LTYPE, EXPORT)          \
474
  _MERGE_SORT_DEFN_WRAPPER_SORT(LWRAPPERTYPE, LTYPE, EXPORT)
475
476
#endif /* _DOUBLY_LINKED_LIST_H */