yading@11
|
1 /*
|
yading@11
|
2 * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
|
yading@11
|
3 *
|
yading@11
|
4 * This file is part of FFmpeg.
|
yading@11
|
5 *
|
yading@11
|
6 * FFmpeg is free software; you can redistribute it and/or
|
yading@11
|
7 * modify it under the terms of the GNU Lesser General Public
|
yading@11
|
8 * License as published by the Free Software Foundation; either
|
yading@11
|
9 * version 2.1 of the License, or (at your option) any later version.
|
yading@11
|
10 *
|
yading@11
|
11 * FFmpeg is distributed in the hope that it will be useful,
|
yading@11
|
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
yading@11
|
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
yading@11
|
14 * Lesser General Public License for more details.
|
yading@11
|
15 *
|
yading@11
|
16 * You should have received a copy of the GNU Lesser General Public
|
yading@11
|
17 * License along with FFmpeg; if not, write to the Free Software
|
yading@11
|
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
yading@11
|
19 */
|
yading@11
|
20
|
yading@11
|
21 #include "log.h"
|
yading@11
|
22 #include "mem.h"
|
yading@11
|
23 #include "tree.h"
|
yading@11
|
24
|
yading@11
|
25 typedef struct AVTreeNode {
|
yading@11
|
26 struct AVTreeNode *child[2];
|
yading@11
|
27 void *elem;
|
yading@11
|
28 int state;
|
yading@11
|
29 } AVTreeNode;
|
yading@11
|
30
|
yading@11
|
31 const int av_tree_node_size = sizeof(AVTreeNode);
|
yading@11
|
32
|
yading@11
|
33 struct AVTreeNode *av_tree_node_alloc(void)
|
yading@11
|
34 {
|
yading@11
|
35 return av_mallocz(sizeof(struct AVTreeNode));
|
yading@11
|
36 }
|
yading@11
|
37
|
yading@11
|
38 void *av_tree_find(const AVTreeNode *t, void *key,
|
yading@11
|
39 int (*cmp)(void *key, const void *b), void *next[2])
|
yading@11
|
40 {
|
yading@11
|
41 if (t) {
|
yading@11
|
42 unsigned int v = cmp(key, t->elem);
|
yading@11
|
43 if (v) {
|
yading@11
|
44 if (next) next[v >> 31] = t->elem;
|
yading@11
|
45 return av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next);
|
yading@11
|
46 } else {
|
yading@11
|
47 if (next) {
|
yading@11
|
48 av_tree_find(t->child[0], key, cmp, next);
|
yading@11
|
49 av_tree_find(t->child[1], key, cmp, next);
|
yading@11
|
50 }
|
yading@11
|
51 return t->elem;
|
yading@11
|
52 }
|
yading@11
|
53 }
|
yading@11
|
54 return NULL;
|
yading@11
|
55 }
|
yading@11
|
56
|
yading@11
|
57 void *av_tree_insert(AVTreeNode **tp, void *key,
|
yading@11
|
58 int (*cmp)(void *key, const void *b), AVTreeNode **next)
|
yading@11
|
59 {
|
yading@11
|
60 AVTreeNode *t = *tp;
|
yading@11
|
61 if (t) {
|
yading@11
|
62 unsigned int v = cmp(t->elem, key);
|
yading@11
|
63 void *ret;
|
yading@11
|
64 if (!v) {
|
yading@11
|
65 if (*next)
|
yading@11
|
66 return t->elem;
|
yading@11
|
67 else if (t->child[0] || t->child[1]) {
|
yading@11
|
68 int i = !t->child[0];
|
yading@11
|
69 void *next_elem[2];
|
yading@11
|
70 av_tree_find(t->child[i], key, cmp, next_elem);
|
yading@11
|
71 key = t->elem = next_elem[i];
|
yading@11
|
72 v = -i;
|
yading@11
|
73 } else {
|
yading@11
|
74 *next = t;
|
yading@11
|
75 *tp = NULL;
|
yading@11
|
76 return NULL;
|
yading@11
|
77 }
|
yading@11
|
78 }
|
yading@11
|
79 ret = av_tree_insert(&t->child[v >> 31], key, cmp, next);
|
yading@11
|
80 if (!ret) {
|
yading@11
|
81 int i = (v >> 31) ^ !!*next;
|
yading@11
|
82 AVTreeNode **child = &t->child[i];
|
yading@11
|
83 t->state += 2 * i - 1;
|
yading@11
|
84
|
yading@11
|
85 if (!(t->state & 1)) {
|
yading@11
|
86 if (t->state) {
|
yading@11
|
87 /* The following code is equivalent to
|
yading@11
|
88 if((*child)->state*2 == -t->state)
|
yading@11
|
89 rotate(child, i^1);
|
yading@11
|
90 rotate(tp, i);
|
yading@11
|
91
|
yading@11
|
92 with rotate():
|
yading@11
|
93 static void rotate(AVTreeNode **tp, int i) {
|
yading@11
|
94 AVTreeNode *t= *tp;
|
yading@11
|
95
|
yading@11
|
96 *tp= t->child[i];
|
yading@11
|
97 t->child[i]= t->child[i]->child[i^1];
|
yading@11
|
98 (*tp)->child[i^1]= t;
|
yading@11
|
99 i= 4*t->state + 2*(*tp)->state + 12;
|
yading@11
|
100 t ->state= ((0x614586 >> i) & 3)-1;
|
yading@11
|
101 (*tp)->state= ((*tp)->state>>1) + ((0x400EEA >> i) & 3)-1;
|
yading@11
|
102 }
|
yading@11
|
103 but such a rotate function is both bigger and slower
|
yading@11
|
104 */
|
yading@11
|
105 if (( *child )->state * 2 == -t->state) {
|
yading@11
|
106 *tp = (*child)->child[i ^ 1];
|
yading@11
|
107 (*child)->child[i ^ 1] = (*tp)->child[i];
|
yading@11
|
108 (*tp)->child[i] = *child;
|
yading@11
|
109 *child = ( *tp )->child[i ^ 1];
|
yading@11
|
110 (*tp)->child[i ^ 1] = t;
|
yading@11
|
111
|
yading@11
|
112 (*tp)->child[0]->state = -((*tp)->state > 0);
|
yading@11
|
113 (*tp)->child[1]->state = (*tp)->state < 0;
|
yading@11
|
114 (*tp)->state = 0;
|
yading@11
|
115 } else {
|
yading@11
|
116 *tp = *child;
|
yading@11
|
117 *child = (*child)->child[i ^ 1];
|
yading@11
|
118 (*tp)->child[i ^ 1] = t;
|
yading@11
|
119 if ((*tp)->state) t->state = 0;
|
yading@11
|
120 else t->state >>= 1;
|
yading@11
|
121 (*tp)->state = -t->state;
|
yading@11
|
122 }
|
yading@11
|
123 }
|
yading@11
|
124 }
|
yading@11
|
125 if (!(*tp)->state ^ !!*next)
|
yading@11
|
126 return key;
|
yading@11
|
127 }
|
yading@11
|
128 return ret;
|
yading@11
|
129 } else {
|
yading@11
|
130 *tp = *next;
|
yading@11
|
131 *next = NULL;
|
yading@11
|
132 if (*tp) {
|
yading@11
|
133 (*tp)->elem = key;
|
yading@11
|
134 return NULL;
|
yading@11
|
135 } else
|
yading@11
|
136 return key;
|
yading@11
|
137 }
|
yading@11
|
138 }
|
yading@11
|
139
|
yading@11
|
140 void av_tree_destroy(AVTreeNode *t)
|
yading@11
|
141 {
|
yading@11
|
142 if (t) {
|
yading@11
|
143 av_tree_destroy(t->child[0]);
|
yading@11
|
144 av_tree_destroy(t->child[1]);
|
yading@11
|
145 av_free(t);
|
yading@11
|
146 }
|
yading@11
|
147 }
|
yading@11
|
148
|
yading@11
|
149 void av_tree_enumerate(AVTreeNode *t, void *opaque,
|
yading@11
|
150 int (*cmp)(void *opaque, void *elem),
|
yading@11
|
151 int (*enu)(void *opaque, void *elem))
|
yading@11
|
152 {
|
yading@11
|
153 if (t) {
|
yading@11
|
154 int v = cmp ? cmp(opaque, t->elem) : 0;
|
yading@11
|
155 if (v >= 0)
|
yading@11
|
156 av_tree_enumerate(t->child[0], opaque, cmp, enu);
|
yading@11
|
157 if (v == 0)
|
yading@11
|
158 enu(opaque, t->elem);
|
yading@11
|
159 if (v <= 0)
|
yading@11
|
160 av_tree_enumerate(t->child[1], opaque, cmp, enu);
|
yading@11
|
161 }
|
yading@11
|
162 }
|
yading@11
|
163
|
yading@11
|
164 #ifdef TEST
|
yading@11
|
165
|
yading@11
|
166 #include "common.h"
|
yading@11
|
167 #include "lfg.h"
|
yading@11
|
168
|
yading@11
|
169 static int check(AVTreeNode *t)
|
yading@11
|
170 {
|
yading@11
|
171 if (t) {
|
yading@11
|
172 int left = check(t->child[0]);
|
yading@11
|
173 int right = check(t->child[1]);
|
yading@11
|
174
|
yading@11
|
175 if (left>999 || right>999)
|
yading@11
|
176 return 1000;
|
yading@11
|
177 if (right - left != t->state)
|
yading@11
|
178 return 1000;
|
yading@11
|
179 if (t->state>1 || t->state<-1)
|
yading@11
|
180 return 1000;
|
yading@11
|
181 return FFMAX(left, right) + 1;
|
yading@11
|
182 }
|
yading@11
|
183 return 0;
|
yading@11
|
184 }
|
yading@11
|
185
|
yading@11
|
186 static void print(AVTreeNode *t, int depth)
|
yading@11
|
187 {
|
yading@11
|
188 int i;
|
yading@11
|
189 for (i = 0; i < depth * 4; i++) av_log(NULL, AV_LOG_ERROR, " ");
|
yading@11
|
190 if (t) {
|
yading@11
|
191 av_log(NULL, AV_LOG_ERROR, "Node %p %2d %p\n", t, t->state, t->elem);
|
yading@11
|
192 print(t->child[0], depth + 1);
|
yading@11
|
193 print(t->child[1], depth + 1);
|
yading@11
|
194 } else
|
yading@11
|
195 av_log(NULL, AV_LOG_ERROR, "NULL\n");
|
yading@11
|
196 }
|
yading@11
|
197
|
yading@11
|
198 static int cmp(void *a, const void *b)
|
yading@11
|
199 {
|
yading@11
|
200 return (uint8_t *) a - (const uint8_t *) b;
|
yading@11
|
201 }
|
yading@11
|
202
|
yading@11
|
203 int main (void)
|
yading@11
|
204 {
|
yading@11
|
205 int i;
|
yading@11
|
206 void *k;
|
yading@11
|
207 AVTreeNode *root = NULL, *node = NULL;
|
yading@11
|
208 AVLFG prng;
|
yading@11
|
209
|
yading@11
|
210 av_lfg_init(&prng, 1);
|
yading@11
|
211
|
yading@11
|
212 for (i = 0; i < 10000; i++) {
|
yading@11
|
213 intptr_t j = av_lfg_get(&prng) % 86294;
|
yading@11
|
214 if (check(root) > 999) {
|
yading@11
|
215 av_log(NULL, AV_LOG_ERROR, "FATAL error %d\n", i);
|
yading@11
|
216 print(root, 0);
|
yading@11
|
217 return -1;
|
yading@11
|
218 }
|
yading@11
|
219 av_log(NULL, AV_LOG_ERROR, "inserting %4d\n", (int)j);
|
yading@11
|
220 if (!node)
|
yading@11
|
221 node = av_tree_node_alloc();
|
yading@11
|
222 av_tree_insert(&root, (void *) (j + 1), cmp, &node);
|
yading@11
|
223
|
yading@11
|
224 j = av_lfg_get(&prng) % 86294;
|
yading@11
|
225 {
|
yading@11
|
226 AVTreeNode *node2 = NULL;
|
yading@11
|
227 av_log(NULL, AV_LOG_ERROR, "removing %4d\n", (int)j);
|
yading@11
|
228 av_tree_insert(&root, (void *) (j + 1), cmp, &node2);
|
yading@11
|
229 k = av_tree_find(root, (void *) (j + 1), cmp, NULL);
|
yading@11
|
230 if (k)
|
yading@11
|
231 av_log(NULL, AV_LOG_ERROR, "removal failure %d\n", i);
|
yading@11
|
232 }
|
yading@11
|
233 }
|
yading@11
|
234 return 0;
|
yading@11
|
235 }
|
yading@11
|
236 #endif
|