Coverage Report

Created: 2026-09-01 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libplist/libcnary/node.c
Line
Count
Source
1
/*
2
 * node.c
3
 *
4
 *  Created on: Mar 7, 2011
5
 *      Author: posixninja
6
 *
7
 * Copyright (c) 2011 Joshua Hill. All Rights Reserved.
8
 *
9
 * This library is free software; you can redistribute it and/or
10
 * modify it under the terms of the GNU Lesser General Public
11
 * License as published by the Free Software Foundation; either
12
 * version 2.1 of the License, or (at your option) any later version.
13
 *
14
 * This library is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17
 * Lesser General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU Lesser General Public
20
 * License along with this library; if not, write to the Free Software
21
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22
 */
23
#include <stdio.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "node.h"
28
#include "node_list.h"
29
30
void node_destroy(node_t node)
31
49.3k
{
32
49.3k
  if(!node) return;
33
34
49.3k
  if (node->children && node->children->count > 0) {
35
0
    node_t ch;
36
0
    while ((ch = node->children->begin)) {
37
0
      node_list_remove(node->children, ch);
38
0
      node_destroy(ch);
39
0
    }
40
0
  }
41
49.3k
  node_list_destroy(node->children);
42
49.3k
  node->children = NULL;
43
44
49.3k
  free(node);
45
49.3k
}
46
47
node_t node_create(node_t parent, void* data)
48
49.4k
{
49
49.4k
  int error = 0;
50
51
49.4k
  node_t node = (node_t)calloc(1, sizeof(struct node));
52
49.4k
  if (node == NULL) {
53
0
    return NULL;
54
0
  }
55
56
49.4k
  node->data = data;
57
49.4k
  node->next = NULL;
58
49.4k
  node->prev = NULL;
59
49.4k
  node->count = 0;
60
49.4k
  node->parent = NULL;
61
49.4k
  node->children = NULL;
62
63
  // Pass NULL to create a root node
64
49.4k
  if (parent != NULL) {
65
    // This is a child node so attach it to it's parent
66
0
    error = node_attach(parent, node);
67
0
    if (error < 0) {
68
      // Unable to attach nodes
69
0
      node_destroy(node);
70
0
      return NULL;
71
0
    }
72
0
  }
73
74
49.4k
  return node;
75
49.4k
}
76
77
static int node_depth_from_root(node_t n)
78
41.5k
{
79
41.5k
  int d = 0;
80
3.93M
  while (n && n->parent) {
81
3.89M
    d++;
82
3.89M
    n = n->parent;
83
3.89M
    if (d > NODE_MAX_DEPTH) return d; // early out
84
3.89M
  }
85
41.5k
  return d;
86
41.5k
}
87
88
static int node_subtree_max_depth(node_t root)
89
41.5k
{
90
41.5k
  if (!root) return 0;
91
92
41.5k
  typedef struct { node_t n; int depth; } frame_t;
93
41.5k
  size_t cap = 64, sp = 0;
94
41.5k
  frame_t *st = (frame_t*)malloc(cap * sizeof(*st));
95
41.5k
  if (!st) return NODE_MAX_DEPTH + 1;
96
97
41.5k
  st[sp++] = (frame_t){ root, 0 };
98
41.5k
  int maxd = 0;
99
100
83.1k
  while (sp) {
101
41.5k
    frame_t f = st[--sp];
102
41.5k
    if (f.depth > maxd) maxd = f.depth;
103
41.5k
    if (maxd > NODE_MAX_DEPTH) break;
104
105
41.5k
    if (!f.n->children) continue;
106
107
0
    for (node_t ch = node_first_child(f.n); ch; ch = node_next_sibling(ch)) {
108
0
      if (sp == cap) {
109
0
        cap *= 2;
110
0
        frame_t *tmp = (frame_t*)realloc(st, cap * sizeof(*st));
111
0
        if (!tmp) { maxd = NODE_MAX_DEPTH + 1; goto out; }
112
0
        st = tmp;
113
0
      }
114
0
      st[sp++] = (frame_t){ ch, f.depth + 1 };
115
0
    }
116
0
  }
117
118
41.5k
out:
119
41.5k
  free(st);
120
41.5k
  return maxd;
121
41.5k
}
122
123
static int would_create_cycle(node_t parent, node_t child)
124
41.5k
{
125
  // if parent is anywhere in child's ancestor chain => cycle
126
3.97M
  for (node_t p = parent; p; p = p->parent) {
127
3.93M
    if (p == child) return 1;
128
3.93M
  }
129
41.5k
  return 0;
130
41.5k
}
131
132
int node_attach(node_t parent, node_t child)
133
39.8k
{
134
39.8k
  if (!parent || !child) return NODE_ERR_INVALID_ARG;
135
136
  // already parented?
137
39.8k
  if (child->parent) return NODE_ERR_PARENT;
138
139
  // self/cycle guard
140
39.8k
  if (parent == child) return NODE_ERR_CIRCULAR_REF;
141
39.8k
  if (would_create_cycle(parent, child)) return NODE_ERR_CIRCULAR_REF;
142
143
  // depth guard: depth(parent)+1+max_depth(child_subtree) <= NODE_MAX_DEPTH
144
39.8k
  int pd = node_depth_from_root(parent);
145
39.8k
  int cd = node_subtree_max_depth(child);
146
39.8k
  if (pd + 1 + cd > NODE_MAX_DEPTH) {
147
100
    return NODE_ERR_MAX_DEPTH;
148
100
  }
149
150
39.7k
  if (!parent->children) {
151
19.0k
    parent->children = node_list_create();
152
19.0k
    if (!parent->children) return NODE_ERR_NO_MEM;
153
19.0k
  }
154
39.7k
  int res = node_list_add(parent->children, child);
155
39.7k
  if (res == 0) {
156
39.7k
    child->parent = parent;
157
39.7k
    parent->count++;
158
39.7k
  }
159
39.7k
  return res;
160
39.7k
}
161
162
int node_detach(node_t parent, node_t child)
163
41.4k
{
164
41.4k
  if (!parent || !child) return NODE_ERR_INVALID_ARG;
165
41.4k
  if (!parent->children) return NODE_ERR_NOT_FOUND;
166
41.4k
  if (child->parent && child->parent != parent) return NODE_ERR_PARENT;
167
168
41.4k
  int node_index = node_list_remove(parent->children, child);
169
41.4k
  if (node_index >= 0) {
170
41.4k
    if (parent->count > 0) parent->count--;
171
41.4k
    child->parent = NULL;
172
41.4k
    child->prev = NULL;
173
41.4k
    child->next = NULL;
174
41.4k
  }
175
41.4k
  return node_index;
176
41.4k
}
177
178
int node_insert(node_t parent, unsigned int node_index, node_t child)
179
1.78k
{
180
1.78k
  if (!parent || !child) return NODE_ERR_INVALID_ARG;
181
182
  // already parented?
183
1.78k
  if (child->parent) return NODE_ERR_PARENT;
184
185
  // self/cycle guard
186
1.78k
  if (parent == child) return NODE_ERR_CIRCULAR_REF;
187
1.78k
  if (would_create_cycle(parent, child)) return NODE_ERR_CIRCULAR_REF;
188
189
  // depth guard: depth(parent)+1+max_depth(child_subtree) <= NODE_MAX_DEPTH
190
1.78k
  int pd = node_depth_from_root(parent);
191
1.78k
  int cd = node_subtree_max_depth(child);
192
1.78k
  if (pd + 1 + cd > NODE_MAX_DEPTH) {
193
0
    return NODE_ERR_MAX_DEPTH;
194
0
  }
195
196
1.78k
  if (!parent->children) {
197
0
    parent->children = node_list_create();
198
0
    if (!parent->children) return NODE_ERR_NO_MEM;
199
0
  }
200
1.78k
  int res = node_list_insert(parent->children, node_index, child);
201
1.78k
  if (res == 0) {
202
1.78k
    child->parent = parent;
203
1.78k
    parent->count++;
204
1.78k
  }
205
1.78k
  return res;
206
1.78k
}
207
208
static void _node_debug(node_t node, unsigned int depth)
209
0
{
210
0
  unsigned int i = 0;
211
0
  node_t current = NULL;
212
0
  for(i = 0; i < depth; i++) {
213
0
    printf("\t");
214
0
  }
215
0
  if(!node->parent) {
216
0
    printf("ROOT\n");
217
0
  }
218
219
0
  if(!node->children && node->parent) {
220
0
    printf("LEAF\n");
221
0
  } else {
222
0
    if(node->parent) {
223
0
      printf("NODE\n");
224
0
    }
225
0
    for (current = node_first_child(node); current; current = node_next_sibling(current)) {
226
0
      _node_debug(current, depth+1);
227
0
    }
228
0
  }
229
230
0
}
231
232
void node_debug(node_t node)
233
0
{
234
0
  _node_debug(node, 0);
235
0
}
236
237
unsigned int node_n_children(node_t node)
238
1.11k
{
239
1.11k
  if (!node) return 0;
240
1.11k
  return node->count;
241
1.11k
}
242
243
node_t node_nth_child(node_t node, unsigned int n)
244
0
{
245
0
  if (!node || !node->children || !node->children->begin) return NULL;
246
0
  unsigned int node_index = 0;
247
0
  int found = 0;
248
0
  node_t ch;
249
0
  for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
250
0
    if (node_index++ == n) {
251
0
      found = 1;
252
0
      break;
253
0
    }
254
0
  }
255
0
  if (!found) {
256
0
    return NULL;
257
0
  }
258
0
  return ch;
259
0
}
260
261
node_t node_first_child(node_t node)
262
95.4k
{
263
95.4k
  if (!node || !node->children) return NULL;
264
64.0k
  return node->children->begin;
265
95.4k
}
266
267
node_t node_prev_sibling(node_t node)
268
1.78k
{
269
1.78k
  if (!node) return NULL;
270
1.78k
  return node->prev;
271
1.78k
}
272
273
node_t node_next_sibling(node_t node)
274
141k
{
275
141k
  if (!node) return NULL;
276
141k
  return node->next;
277
141k
}
278
279
int node_child_position(node_t parent, node_t child)
280
0
{
281
0
  if (!parent || !parent->children || !parent->children->begin || !child) return NODE_ERR_INVALID_ARG;
282
0
  int node_index = 0;
283
0
  int found = 0;
284
0
  node_t ch;
285
0
  for (ch = node_first_child(parent); ch; ch = node_next_sibling(ch)) {
286
0
    if (ch == child) {
287
0
      found = 1;
288
0
      break;
289
0
    }
290
0
    node_index++;
291
0
  }
292
0
  if (!found) {
293
0
    return NODE_ERR_NOT_FOUND;
294
0
  }
295
0
  return node_index;
296
0
}
297
298
node_t node_copy_deep(node_t node, copy_func_t copy_func)
299
0
{
300
0
  if (!node) return NULL;
301
0
  void *data = NULL;
302
0
  if (copy_func) {
303
0
    data = copy_func(node->data);
304
0
  }
305
0
  node_t copy = node_create(NULL, data);
306
0
  if (!copy) return NULL;
307
0
  node_t ch;
308
0
  for (ch = node_first_child(node); ch; ch = node_next_sibling(ch)) {
309
0
    node_t cc = node_copy_deep(ch, copy_func);
310
0
    if (!cc) {
311
0
      node_destroy(copy);
312
0
      return NULL;
313
0
    }
314
0
    if (node_attach(copy, cc) < 0) {
315
0
                        node_destroy(cc);
316
0
      node_destroy(copy);
317
0
      return NULL;
318
0
    }
319
0
  }
320
0
  return copy;
321
0
}