Coverage Report

Created: 2026-01-13 06:56

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/frr/lib/linklist.c
Line
Count
Source
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/* Generic linked list routine.
3
 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
4
 */
5
6
#include <zebra.h>
7
#include <stdlib.h>
8
9
#include "linklist.h"
10
#include "memory.h"
11
#include "libfrr_trace.h"
12
13
8
DEFINE_MTYPE_STATIC(LIB, LINK_LIST, "Link List");
14
8
DEFINE_MTYPE_STATIC(LIB, LINK_NODE, "Link Node");
15
8
16
8
/* these *do not* cleanup list nodes and referenced data, as the functions
17
8
 * do - these macros simply {de,at}tach a listnode from/to a list.
18
8
 */
19
8
20
8
/* List node attach macro.  */
21
8
#define LISTNODE_ATTACH(L, N)                                                  \
22
8
  do {                                                                   \
23
0
    (N)->prev = (L)->tail;                                         \
24
0
    (N)->next = NULL;                                              \
25
0
    if ((L)->head == NULL)                                         \
26
0
      (L)->head = (N);                                       \
27
0
    else                                                           \
28
0
      (L)->tail->next = (N);                                 \
29
0
    (L)->tail = (N);                                               \
30
0
    (L)->count++;                                                  \
31
0
  } while (0)
32
33
/* List node detach macro.  */
34
#define LISTNODE_DETACH(L, N)                                                  \
35
0
  do {                                                                   \
36
0
    if ((N)->prev)                                                 \
37
0
      (N)->prev->next = (N)->next;                           \
38
0
    else                                                           \
39
0
      (L)->head = (N)->next;                                 \
40
0
    if ((N)->next)                                                 \
41
0
      (N)->next->prev = (N)->prev;                           \
42
0
    else                                                           \
43
0
      (L)->tail = (N)->prev;                                 \
44
0
    (L)->count--;                                                  \
45
0
  } while (0)
46
47
struct list *list_new(void)
48
86.6k
{
49
86.6k
  return XCALLOC(MTYPE_LINK_LIST, sizeof(struct list));
50
86.6k
}
51
52
/* Free list. */
53
static void list_free_internal(struct list *l)
54
84.5k
{
55
84.5k
  XFREE(MTYPE_LINK_LIST, l);
56
84.5k
}
57
58
59
/* Allocate new listnode.  Internal use only. */
60
static struct listnode *listnode_new(struct list *list, void *val)
61
332k
{
62
332k
  struct listnode *node;
63
64
  /* if listnode memory is managed by the app then the val
65
   * passed in is the listnode
66
   */
67
332k
  if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) {
68
0
    node = val;
69
0
    node->prev = node->next = NULL;
70
332k
  } else {
71
332k
    node = XCALLOC(MTYPE_LINK_NODE, sizeof(struct listnode));
72
332k
    node->data = val;
73
332k
  }
74
332k
  return node;
75
332k
}
76
77
/* Free listnode. */
78
static void listnode_free(struct list *list, struct listnode *node)
79
323k
{
80
323k
  if (!(list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP))
81
323k
    XFREE(MTYPE_LINK_NODE, node);
82
323k
}
83
84
struct listnode *listnode_add(struct list *list, void *val)
85
239k
{
86
239k
  frrtrace(2, frr_libfrr, list_add, list, val);
87
88
239k
  struct listnode *node;
89
90
239k
  assert(val != NULL);
91
92
239k
  node = listnode_new(list, val);
93
94
239k
  node->prev = list->tail;
95
96
239k
  if (list->head == NULL)
97
16.0k
    list->head = node;
98
223k
  else
99
223k
    list->tail->next = node;
100
239k
  list->tail = node;
101
102
239k
  list->count++;
103
104
239k
  return node;
105
239k
}
106
107
void listnode_add_head(struct list *list, void *val)
108
0
{
109
0
  struct listnode *node;
110
111
0
  assert(val != NULL);
112
113
0
  node = listnode_new(list, val);
114
115
0
  node->next = list->head;
116
117
0
  if (list->head == NULL) {
118
0
    list->head = node;
119
0
    list->tail = node;
120
0
  } else
121
0
    list->head->prev = node;
122
0
  list->head = node;
123
124
0
  list->count++;
125
0
}
126
127
bool listnode_add_sort_nodup(struct list *list, void *val)
128
0
{
129
0
  struct listnode *n;
130
0
  struct listnode *new;
131
0
  int ret;
132
0
  void *data;
133
134
0
  assert(val != NULL);
135
136
0
  if (list->flags & LINKLIST_FLAG_NODE_MEM_BY_APP) {
137
0
    n = val;
138
0
    data = n->data;
139
0
  } else {
140
0
    data = val;
141
0
  }
142
143
0
  if (list->cmp) {
144
0
    for (n = list->head; n; n = n->next) {
145
0
      ret = (*list->cmp)(data, n->data);
146
0
      if (ret < 0) {
147
0
        new = listnode_new(list, val);
148
149
0
        new->next = n;
150
0
        new->prev = n->prev;
151
152
0
        if (n->prev)
153
0
          n->prev->next = new;
154
0
        else
155
0
          list->head = new;
156
0
        n->prev = new;
157
0
        list->count++;
158
0
        return true;
159
0
      }
160
      /* found duplicate return false */
161
0
      if (ret == 0)
162
0
        return false;
163
0
    }
164
0
  }
165
166
0
  new = listnode_new(list, val);
167
168
0
  LISTNODE_ATTACH(list, new);
169
170
0
  return true;
171
0
}
172
173
struct list *list_dup(struct list *list)
174
0
{
175
0
  struct list *dup;
176
0
  struct listnode *node;
177
0
  void *data;
178
179
0
  assert(list);
180
181
0
  dup = list_new();
182
0
  dup->cmp = list->cmp;
183
0
  dup->del = list->del;
184
0
  for (ALL_LIST_ELEMENTS_RO(list, node, data))
185
0
    listnode_add(dup, data);
186
187
0
  return dup;
188
0
}
189
190
void listnode_add_sort(struct list *list, void *val)
191
93.2k
{
192
93.2k
  struct listnode *n;
193
93.2k
  struct listnode *new;
194
195
93.2k
  assert(val != NULL);
196
197
93.2k
  new = listnode_new(list, val);
198
93.2k
  val = new->data;
199
200
93.2k
  if (list->cmp) {
201
373k
    for (n = list->head; n; n = n->next) {
202
308k
      if ((*list->cmp)(val, n->data) < 0) {
203
28.4k
        new->next = n;
204
28.4k
        new->prev = n->prev;
205
206
28.4k
        if (n->prev)
207
14.7k
          n->prev->next = new;
208
13.7k
        else
209
13.7k
          list->head = new;
210
28.4k
        n->prev = new;
211
28.4k
        list->count++;
212
28.4k
        return;
213
28.4k
      }
214
308k
    }
215
93.2k
  }
216
217
64.8k
  new->prev = list->tail;
218
219
64.8k
  if (list->tail)
220
505
    list->tail->next = new;
221
64.3k
  else
222
64.3k
    list->head = new;
223
224
64.8k
  list->tail = new;
225
64.8k
  list->count++;
226
64.8k
}
227
228
struct listnode *listnode_add_after(struct list *list, struct listnode *pp,
229
            void *val)
230
0
{
231
0
  struct listnode *nn;
232
233
0
  assert(val != NULL);
234
235
0
  nn = listnode_new(list, val);
236
237
0
  if (pp == NULL) {
238
0
    if (list->head)
239
0
      list->head->prev = nn;
240
0
    else
241
0
      list->tail = nn;
242
243
0
    nn->next = list->head;
244
0
    nn->prev = pp;
245
246
0
    list->head = nn;
247
0
  } else {
248
0
    if (pp->next)
249
0
      pp->next->prev = nn;
250
0
    else
251
0
      list->tail = nn;
252
253
0
    nn->next = pp->next;
254
0
    nn->prev = pp;
255
256
0
    pp->next = nn;
257
0
  }
258
0
  list->count++;
259
0
  return nn;
260
0
}
261
262
struct listnode *listnode_add_before(struct list *list, struct listnode *pp,
263
             void *val)
264
0
{
265
0
  struct listnode *nn;
266
267
0
  assert(val != NULL);
268
269
0
  nn = listnode_new(list, val);
270
271
0
  if (pp == NULL) {
272
0
    if (list->tail)
273
0
      list->tail->next = nn;
274
0
    else
275
0
      list->head = nn;
276
277
0
    nn->prev = list->tail;
278
0
    nn->next = pp;
279
280
0
    list->tail = nn;
281
0
  } else {
282
0
    if (pp->prev)
283
0
      pp->prev->next = nn;
284
0
    else
285
0
      list->head = nn;
286
287
0
    nn->prev = pp->prev;
288
0
    nn->next = pp;
289
290
0
    pp->prev = nn;
291
0
  }
292
0
  list->count++;
293
0
  return nn;
294
0
}
295
296
void listnode_move_to_tail(struct list *l, struct listnode *n)
297
0
{
298
0
  LISTNODE_DETACH(l, n);
299
0
  LISTNODE_ATTACH(l, n);
300
0
}
301
302
void listnode_delete(struct list *list, const void *val)
303
320k
{
304
320k
  frrtrace(2, frr_libfrr, list_remove, list, val);
305
306
320k
  struct listnode *node = listnode_lookup(list, val);
307
308
320k
  if (node)
309
320k
    list_delete_node(list, node);
310
320k
}
311
312
void *listnode_head(struct list *list)
313
0
{
314
0
  struct listnode *node;
315
316
0
  assert(list);
317
0
  node = list->head;
318
319
0
  if (node)
320
0
    return node->data;
321
0
  return NULL;
322
0
}
323
324
void list_delete_all_node(struct list *list)
325
84.5k
{
326
84.5k
  struct listnode *node;
327
84.5k
  struct listnode *next;
328
329
84.5k
  assert(list);
330
87.6k
  for (node = list->head; node; node = next) {
331
3.10k
    next = node->next;
332
3.10k
    if (*list->del)
333
3.10k
      (*list->del)(node->data);
334
3.10k
    listnode_free(list, node);
335
3.10k
  }
336
84.5k
  list->head = list->tail = NULL;
337
84.5k
  list->count = 0;
338
84.5k
}
339
340
void list_delete(struct list **list)
341
84.5k
{
342
84.5k
  assert(*list);
343
84.5k
  list_delete_all_node(*list);
344
84.5k
  list_free_internal(*list);
345
84.5k
  *list = NULL;
346
84.5k
}
347
348
struct listnode *listnode_lookup(struct list *list, const void *data)
349
370k
{
350
370k
  struct listnode *node;
351
352
370k
  assert(list);
353
14.5M
  for (node = listhead(list); node; node = listnextnode(node))
354
14.5M
    if (data == listgetdata(node))
355
348k
      return node;
356
22.6k
  return NULL;
357
370k
}
358
359
struct listnode *listnode_lookup_nocheck(struct list *list, void *data)
360
0
{
361
0
  if (!list)
362
0
    return NULL;
363
0
  return listnode_lookup(list, data);
364
0
}
365
366
void list_delete_node(struct list *list, struct listnode *node)
367
320k
{
368
320k
  frrtrace(2, frr_libfrr, list_delete_node, list, node);
369
370
320k
  if (node->prev)
371
142k
    node->prev->next = node->next;
372
178k
  else
373
178k
    list->head = node->next;
374
320k
  if (node->next)
375
175k
    node->next->prev = node->prev;
376
145k
  else
377
145k
    list->tail = node->prev;
378
320k
  list->count--;
379
320k
  listnode_free(list, node);
380
320k
}
381
382
void list_sort(struct list *list, int (*cmp)(const void **, const void **))
383
0
{
384
0
  frrtrace(1, frr_libfrr, list_sort, list);
385
386
0
  struct listnode *ln, *nn;
387
0
  int i = -1;
388
0
  void *data;
389
0
  size_t n = list->count;
390
0
  void **items;
391
0
  int (*realcmp)(const void *, const void *) =
392
0
    (int (*)(const void *, const void *))cmp;
393
394
0
  if (!n)
395
0
    return;
396
397
0
  items = XCALLOC(MTYPE_TMP, (sizeof(void *)) * n);
398
399
0
  for (ALL_LIST_ELEMENTS(list, ln, nn, data)) {
400
0
    items[++i] = data;
401
0
    list_delete_node(list, ln);
402
0
  }
403
404
0
  qsort(items, n, sizeof(void *), realcmp);
405
406
0
  for (unsigned int j = 0; j < n; ++j)
407
0
    listnode_add(list, items[j]);
408
409
0
  XFREE(MTYPE_TMP, items);
410
0
}
411
412
struct listnode *listnode_add_force(struct list **list, void *val)
413
0
{
414
0
  if (*list == NULL)
415
0
    *list = list_new();
416
0
  return listnode_add(*list, val);
417
0
}
418
419
void **list_to_array(struct list *list, void **arr, size_t arrlen)
420
0
{
421
0
  struct listnode *ln;
422
0
  void *vp;
423
0
  size_t idx = 0;
424
425
0
  for (ALL_LIST_ELEMENTS_RO(list, ln, vp)) {
426
0
    arr[idx++] = vp;
427
0
    if (idx == arrlen)
428
0
      break;
429
0
  }
430
431
0
  return arr;
432
0
}