/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 | 1.30k | { |
46 | 1.30k | wmem_range_t *range; |
47 | 1.30k | const wmem_range_t *range_l; |
48 | 1.30k | const wmem_range_t *range_r; |
49 | 1.30k | uint64_t maxEdge = 0; |
50 | | |
51 | 1.30k | if(!node) { |
52 | 540 | return ; |
53 | 540 | } |
54 | | |
55 | 765 | range = (wmem_range_t *)node->key; |
56 | | |
57 | 765 | range_l = (node->left) ? (const wmem_range_t *) (node->left->key) : NULL; |
58 | 765 | range_r = (node->right) ? (const wmem_range_t *) (node->right->key) : NULL; |
59 | | |
60 | 765 | maxEdge = range->high; |
61 | | |
62 | 765 | if(range_r) { |
63 | 79 | maxEdge = MAX(maxEdge, range_r->max_edge) ; |
64 | 79 | } |
65 | 765 | if(range_l) { |
66 | 90 | maxEdge = MAX(maxEdge, range_l->max_edge) ; |
67 | 90 | } |
68 | | |
69 | | /* update the parent nodes only if a change happened (optimization) */ |
70 | 765 | if(range->max_edge != maxEdge) { |
71 | 641 | range->max_edge = maxEdge; |
72 | 641 | update_max_edge(node->parent); |
73 | 641 | } |
74 | 765 | } |
75 | | |
76 | | bool |
77 | | wmem_itree_range_overlap(const wmem_range_t *r1, const wmem_range_t *r2) |
78 | 55.7k | { |
79 | 55.7k | return (r1->low <= r2->high && r2->low <= r1->high); |
80 | 55.7k | } |
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 | 29 | static void update_edges_after_rotation(wmem_tree_node_t *node) { |
86 | 29 | if(node->left) update_max_edge(node->left); |
87 | 29 | if(node->right) update_max_edge(node->right); |
88 | 29 | } |
89 | | |
90 | | wmem_itree_t * |
91 | | wmem_itree_new(wmem_allocator_t *allocator) |
92 | 1.07k | { |
93 | 1.07k | wmem_itree_t *tree = wmem_tree_new(allocator); |
94 | 1.07k | tree->post_rotation_cb = &update_edges_after_rotation; |
95 | 1.07k | return tree; |
96 | 1.07k | } |
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 | 242 | { |
107 | 242 | if( ra->low == rb->low) { |
108 | 51 | return 0; |
109 | 51 | } |
110 | 191 | else if(ra->low < rb->low) { |
111 | 100 | return -1; |
112 | 100 | } |
113 | 91 | else { |
114 | 91 | return 1; |
115 | 91 | } |
116 | 242 | } |
117 | | |
118 | | |
119 | | void |
120 | | wmem_itree_insert(wmem_itree_t *tree, const uint64_t low, const uint64_t high, void *data) |
121 | 648 | { |
122 | 648 | wmem_tree_node_t *node; |
123 | 648 | wmem_range_t *range = (wmem_range_t *)wmem_new(tree->data_allocator, wmem_range_t); |
124 | | |
125 | 648 | ws_assert(low <= high); |
126 | 648 | range->low = low; |
127 | 648 | range->high = high; |
128 | 648 | range->max_edge = 0; |
129 | | |
130 | 648 | 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 | 648 | update_max_edge(node); |
134 | 648 | } |
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 | 162k | { |
140 | 162k | const wmem_range_t* current; |
141 | | |
142 | 162k | if(!node) { |
143 | 103k | return; |
144 | 103k | } |
145 | 58.9k | current = (wmem_range_t*)node->key; |
146 | | |
147 | | /* there is no child that can possibly match */ |
148 | 58.9k | if(requested.low > current->max_edge) { |
149 | 3.22k | return; |
150 | 3.22k | } |
151 | | |
152 | 55.7k | if(wmem_itree_range_overlap(current, &requested)) { |
153 | 37.8k | wmem_list_prepend(results, node->data); |
154 | 37.8k | } |
155 | | |
156 | 55.7k | wmem_itree_find_intervals_in_subtree(node->left, requested, results); |
157 | 55.7k | wmem_itree_find_intervals_in_subtree(node->right, requested, results); |
158 | 55.7k | } |
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 | 50.6k | { |
163 | 50.6k | wmem_list_t *results = NULL; |
164 | 50.6k | wmem_range_t requested = { low, high, 0 }; |
165 | 50.6k | results = wmem_list_new(allocator); |
166 | | |
167 | 50.6k | wmem_itree_find_intervals_in_subtree(tree->root, requested, results); |
168 | 50.6k | return results; |
169 | 50.6k | } |
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 | | */ |