Coverage Report

Created: 2026-11-12 07:01

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/wireshark/wsutil/wmem/wmem_interval_tree.c
Line
Count
Source
1
/* wmem_interval_tree.c
2
 * Implements an augmented interval tree
3
 * Based on the red-black tree implementation in epan/wmem.*
4
 * Copyright 2015, Matthieu coudron <matthieu.coudron@lip6.fr>
5
 *
6
 * Wireshark - Network traffic analyzer
7
 * By Gerald Combs <gerald@wireshark.org>
8
 * Copyright 1998 Gerald Combs
9
 *
10
 * SPDX-License-Identifier: GPL-2.0-or-later
11
 */
12
13
#include "config.h"
14
15
#include <inttypes.h>
16
#include <string.h>
17
#include <inttypes.h>
18
#include <stdio.h>
19
#include <glib.h>
20
21
#include "wmem-int.h"
22
#include "wmem_core.h"
23
#include "wmem_tree-int.h"
24
#include "wmem_strutl.h"
25
#include "wmem_interval_tree.h"
26
#include "wmem_user_cb.h"
27
28
static void
29
print_range(const void *value)
30
0
{
31
0
    const wmem_range_t *range = (const wmem_range_t *)value;
32
0
    if(!value) {
33
0
        return;
34
0
    }
35
0
    printf("Range: low=%" PRIu64 " high=%" PRIu64 " max_edge=%" PRIu64 "\n", range->low, range->high, range->max_edge);
36
0
}
37
38
/**
39
 * In an augmented interval tree, each node saves the maximum edge of its child subtrees
40
 * This function compares the children max_edge with the current max_edge
41
 * and propagates any change to the parent nodes.
42
 */
43
static void
44
update_max_edge(wmem_tree_node_t *node)
45
698
{
46
698
    wmem_range_t *range;
47
698
    const wmem_range_t *range_l;
48
698
    const wmem_range_t *range_r;
49
698
    uint64_t maxEdge = 0;
50
51
698
    if(!node) {
52
261
        return ;
53
261
    }
54
55
437
    range = (wmem_range_t *)node->key;
56
57
437
    range_l = (node->left) ? (const wmem_range_t *) (node->left->key) : NULL;
58
437
    range_r = (node->right) ? (const wmem_range_t *) (node->right->key) : NULL;
59
60
437
    maxEdge = range->high;
61
62
437
    if(range_r) {
63
89
        maxEdge = MAX(maxEdge, range_r->max_edge) ;
64
89
    }
65
437
    if(range_l) {
66
89
        maxEdge = MAX(maxEdge, range_l->max_edge) ;
67
89
    }
68
69
    /* update the parent nodes only if a change happened (optimization) */
70
437
    if(range->max_edge != maxEdge) {
71
356
        range->max_edge = maxEdge;
72
356
        update_max_edge(node->parent);
73
356
    }
74
437
}
75
76
bool
77
wmem_itree_range_overlap(const wmem_range_t *r1, const wmem_range_t *r2)
78
33.4k
{
79
33.4k
    return (r1->low <= r2->high && r2->low <= r1->high);
80
33.4k
}
81
82
83
/* after a rotation, some of the children nodes might (dis)appear, thus we need
84
 * to refresh children max_edge. Changes will propagate to parents */
85
23
static void update_edges_after_rotation(wmem_tree_node_t *node) {
86
23
    if(node->left)  update_max_edge(node->left);
87
23
    if(node->right)  update_max_edge(node->right);
88
23
}
89
90
wmem_itree_t *
91
wmem_itree_new(wmem_allocator_t *allocator)
92
601
{
93
601
    wmem_itree_t *tree      = wmem_tree_new(allocator);
94
601
    tree->post_rotation_cb  = &update_edges_after_rotation;
95
601
    return tree;
96
601
}
97
98
bool
99
wmem_itree_is_empty(wmem_itree_t *tree)
100
0
{
101
0
    return wmem_tree_is_empty(tree);
102
0
}
103
104
static int
105
wmem_tree_compare_ranges(const wmem_range_t *ra, const wmem_range_t *rb)
106
184
{
107
184
    if( ra->low == rb->low) {
108
28
        return 0;
109
28
    }
110
156
    else if(ra->low < rb->low) {
111
61
        return -1;
112
61
    }
113
95
    else {
114
95
        return 1;
115
95
    }
116
184
}
117
118
119
void
120
wmem_itree_insert(wmem_itree_t *tree, const uint64_t low, const uint64_t high, void *data)
121
332
{
122
332
    wmem_tree_node_t *node;
123
332
    wmem_range_t *range = (wmem_range_t *)wmem_new(tree->data_allocator, wmem_range_t);
124
125
332
    ws_assert(low <= high);
126
332
    range->low = low;
127
332
    range->high = high;
128
332
    range->max_edge = 0;
129
130
332
    node = wmem_tree_insert_node(tree, range, data, (compare_func)wmem_tree_compare_ranges);
131
132
    /* in absence of rotation, we still need to update max_edge */
133
332
    update_max_edge(node);
134
332
}
135
136
137
static void
138
wmem_itree_find_intervals_in_subtree(wmem_tree_node_t *node, wmem_range_t requested, wmem_list_t *results)
139
79.6k
{
140
79.6k
    const wmem_range_t* current;
141
142
79.6k
    if(!node) {
143
45.0k
        return;
144
45.0k
    }
145
34.5k
    current = (wmem_range_t*)node->key;
146
147
    /* there is no child that can possibly match */
148
34.5k
    if(requested.low > current->max_edge) {
149
1.07k
        return;
150
1.07k
    }
151
152
33.4k
    if(wmem_itree_range_overlap(current, &requested)) {
153
25.6k
        wmem_list_prepend(results, node->data);
154
25.6k
    }
155
156
33.4k
    wmem_itree_find_intervals_in_subtree(node->left, requested, results);
157
33.4k
    wmem_itree_find_intervals_in_subtree(node->right, requested, results);
158
33.4k
}
159
160
wmem_list_t *
161
wmem_itree_find_intervals(wmem_itree_t *tree, wmem_allocator_t *allocator, uint64_t low, uint64_t high)
162
12.7k
{
163
12.7k
    wmem_list_t *results = NULL;
164
12.7k
    wmem_range_t requested = { low, high, 0 };
165
12.7k
    results = wmem_list_new(allocator);
166
167
12.7k
    wmem_itree_find_intervals_in_subtree(tree->root, requested, results);
168
12.7k
    return results;
169
12.7k
}
170
171
172
void
173
wmem_print_itree(wmem_tree_t *tree)
174
0
{
175
    wmem_print_tree(tree, &print_range, NULL);
176
0
}
177
178
/*
179
 * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
180
 *
181
 * Local variables:
182
 * c-basic-offset: 4
183
 * tab-width: 8
184
 * indent-tabs-mode: nil
185
 * End:
186
 *
187
 * vi: set shiftwidth=4 tabstop=8 expandtab:
188
 * :indentSize=4:tabSize=8:noTabs=true:
189
 */