Coverage Report

Created: 2026-03-04 06:18

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
237k
{
32
237k
  if(!node) return;
33
34
237k
  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
237k
  node_list_destroy(node->children);
42
237k
  node->children = NULL;
43
44
237k
  free(node);
45
237k
}
46
47
node_t node_create(node_t parent, void* data)
48
237k
{
49
237k
  int error = 0;
50
51
237k
  node_t node = (node_t)calloc(1, sizeof(struct node));
52
237k
  if (node == NULL) {
53
0
    return NULL;
54
0
  }
55
56
237k
  node->data = data;
57
237k
  node->next = NULL;
58
237k
  node->prev = NULL;
59
237k
  node->count = 0;
60
237k
  node->parent = NULL;
61
237k
  node->children = NULL;
62
63
  // Pass NULL to create a root node
64
237k
  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
237k
  return node;
75
237k
}
76
77
static int node_depth_from_root(node_t n)
78
235k
{
79
235k
  int d = 0;
80
235k
  while (n && n->parent) {
81
0
    d++;
82
0
    n = n->parent;
83
0
    if (d > NODE_MAX_DEPTH) return d; // early out
84
0
  }
85
235k
  return d;
86
235k
}
87
88
static int node_subtree_max_depth(node_t root)
89
235k
{
90
235k
  if (!root) return 0;
91
92
235k
  typedef struct { node_t n; int depth; } frame_t;
93
235k
  size_t cap = 64, sp = 0;
94
235k
  frame_t *st = (frame_t*)malloc(cap * sizeof(*st));
95
235k
  if (!st) return NODE_MAX_DEPTH + 1;
96
97
235k
  st[sp++] = (frame_t){ root, 0 };
98
235k
  int maxd = 0;
99
100
1.60M
  while (sp) {
101
1.36M
    frame_t f = st[--sp];
102
1.36M
    if (f.depth > maxd) maxd = f.depth;
103
1.36M
    if (maxd > NODE_MAX_DEPTH) break;
104
105
1.36M
    if (!f.n->children) continue;
106
107
1.20M
    for (node_t ch = node_first_child(f.n); ch; ch = node_next_sibling(ch)) {
108
1.12M
      if (sp == cap) {
109
1.83k
        cap *= 2;
110
1.83k
        frame_t *tmp = (frame_t*)realloc(st, cap * sizeof(*st));
111
1.83k
        if (!tmp) { maxd = NODE_MAX_DEPTH + 1; goto out; }
112
1.83k
        st = tmp;
113
1.83k
      }
114
1.12M
      st[sp++] = (frame_t){ ch, f.depth + 1 };
115
1.12M
    }
116
70.3k
  }
117
118
235k
out:
119
235k
  free(st);
120
235k
  return maxd;
121
235k
}
122
123
static int would_create_cycle(node_t parent, node_t child)
124
235k
{
125
  // if parent is anywhere in child's ancestor chain => cycle
126
470k
  for (node_t p = parent; p; p = p->parent) {
127
235k
    if (p == child) return 1;
128
235k
  }
129
235k
  return 0;
130
235k
}
131
132
int node_attach(node_t parent, node_t child)
133
235k
{
134
235k
  if (!parent || !child) return NODE_ERR_INVALID_ARG;
135
136
  // already parented?
137
235k
  if (child->parent) return NODE_ERR_PARENT;
138
139
  // self/cycle guard
140
235k
  if (parent == child) return NODE_ERR_CIRCULAR_REF;
141
235k
  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
235k
  int pd = node_depth_from_root(parent);
145
235k
  int cd = node_subtree_max_depth(child);
146
235k
  if (pd + 1 + cd > NODE_MAX_DEPTH) {
147
0
    return NODE_ERR_MAX_DEPTH;
148
0
  }
149
150
235k
  if (!parent->children) {
151
12.8k
    parent->children = node_list_create();
152
12.8k
    if (!parent->children) return NODE_ERR_NO_MEM;
153
12.8k
  }
154
235k
  int res = node_list_add(parent->children, child);
155
235k
  if (res == 0) {
156
235k
    child->parent = parent;
157
235k
    parent->count++;
158
235k
  }
159
235k
  return res;
160
235k
}
161
162
int node_detach(node_t parent, node_t child)
163
235k
{
164
235k
  if (!parent || !child) return NODE_ERR_INVALID_ARG;
165
235k
  if (!parent->children) return NODE_ERR_NOT_FOUND;
166
235k
  if (child->parent && child->parent != parent) return NODE_ERR_PARENT;
167
168
235k
  int node_index = node_list_remove(parent->children, child);
169
235k
  if (node_index >= 0) {
170
235k
    if (parent->count > 0) parent->count--;
171
235k
    child->parent = NULL;
172
235k
    child->prev = NULL;
173
235k
    child->next = NULL;
174
235k
  }
175
235k
  return node_index;
176
235k
}
177
178
int node_insert(node_t parent, unsigned int node_index, node_t child)
179
0
{
180
0
  if (!parent || !child) return NODE_ERR_INVALID_ARG;
181
182
  // already parented?
183
0
  if (child->parent) return NODE_ERR_PARENT;
184
185
  // self/cycle guard
186
0
  if (parent == child) return NODE_ERR_CIRCULAR_REF;
187
0
  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
0
  int pd = node_depth_from_root(parent);
191
0
  int cd = node_subtree_max_depth(child);
192
0
  if (pd + 1 + cd > NODE_MAX_DEPTH) {
193
0
    return NODE_ERR_MAX_DEPTH;
194
0
  }
195
196
0
  if (!parent->children) {
197
0
    parent->children = node_list_create();
198
0
    if (!parent->children) return NODE_ERR_NO_MEM;
199
0
  }
200
0
  int res = node_list_insert(parent->children, node_index, child);
201
0
  if (res == 0) {
202
0
    child->parent = parent;
203
0
    parent->count++;
204
0
  }
205
0
  return res;
206
0
}
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
0
{
239
0
  if (!node) return 0;
240
0
  return node->count;
241
0
}
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
544k
{
263
544k
  if (!node || !node->children) return NULL;
264
319k
  return node->children->begin;
265
544k
}
266
267
node_t node_prev_sibling(node_t node)
268
0
{
269
0
  if (!node) return NULL;
270
0
  return node->prev;
271
0
}
272
273
node_t node_next_sibling(node_t node)
274
1.12M
{
275
1.12M
  if (!node) return NULL;
276
1.12M
  return node->next;
277
1.12M
}
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
}