2 * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
4 * This file is part of FFmpeg.
6 * FFmpeg is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * FFmpeg is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with FFmpeg; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
25 typedef struct AVTreeNode
{
26 struct AVTreeNode
*child
[2];
31 const int av_tree_node_size
= sizeof(AVTreeNode
);
33 void *av_tree_find(const AVTreeNode
*t
, void *key
, int (*cmp
)(void *key
, const void *b
), void *next
[2]){
35 unsigned int v
= cmp(key
, t
->elem
);
37 if(next
) next
[v
>>31]= t
->elem
;
38 return av_tree_find(t
->child
[(v
>>31)^1], key
, cmp
, next
);
41 av_tree_find(t
->child
[0], key
, cmp
, next
);
42 av_tree_find(t
->child
[1], key
, cmp
, next
);
50 void *av_tree_insert(AVTreeNode
**tp
, void *key
, int (*cmp
)(void *key
, const void *b
), AVTreeNode
**next
){
53 unsigned int v
= cmp(t
->elem
, key
);
58 else if(t
->child
[0]||t
->child
[1]){
61 av_tree_find(t
->child
[i
], key
, cmp
, next_elem
);
62 key
= t
->elem
= next_elem
[i
];
70 ret
= av_tree_insert(&t
->child
[v
>>31], key
, cmp
, next
);
72 int i
= (v
>>31) ^ !!*next
;
73 AVTreeNode
**child
= &t
->child
[i
];
78 /* The following code is equivalent to
79 if((*child)->state*2 == -t->state)
84 static void rotate(AVTreeNode **tp, int i){
88 t->child[i]= t->child[i]->child[i^1];
90 i= 4*t->state + 2*(*tp)->state + 12;
91 t ->state= ((0x614586 >> i) & 3)-1;
92 (*tp)->state= ((*tp)->state>>1) + ((0x400EEA >> i) & 3)-1;
94 but such a rotate function is both bigger and slower
96 if((*child
)->state
*2 == -t
->state
){
97 *tp
= (*child
)->child
[i
^1];
98 (*child
)->child
[i
^1]= (*tp
)->child
[i
];
99 (*tp
)->child
[i
]= *child
;
100 *child
= (*tp
)->child
[i
^1];
101 (*tp
)->child
[i
^1]= t
;
103 (*tp
)->child
[0]->state
= -((*tp
)->state
>0);
104 (*tp
)->child
[1]->state
= (*tp
)->state
<0 ;
108 *child
= (*child
)->child
[i
^1];
109 (*tp
)->child
[i
^1]= t
;
110 if((*tp
)->state
) t
->state
= 0;
112 (*tp
)->state
= -t
->state
;
116 if(!(*tp
)->state
^ !!*next
)
121 *tp
= *next
; *next
= NULL
;
130 void av_tree_destroy(AVTreeNode
*t
){
132 av_tree_destroy(t
->child
[0]);
133 av_tree_destroy(t
->child
[1]);
139 void av_tree_enumerate(AVTreeNode
*t
, void *opaque
, int (*f
)(void *opaque
, void *elem
)){
140 int v
= f(opaque
, t
->elem
);
141 if(v
>=0) av_tree_enumerate(t
->child
[0], opaque
, f
);
142 if(v
<=0) av_tree_enumerate(t
->child
[1], opaque
, f
);
148 static int check(AVTreeNode
*t
){
150 int left
= check(t
->child
[0]);
151 int right
= check(t
->child
[1]);
153 if(left
>999 || right
>999)
155 if(right
- left
!= t
->state
)
157 if(t
->state
>1 || t
->state
<-1)
159 return FFMAX(left
, right
)+1;
164 static void print(AVTreeNode
*t
, int depth
){
166 for(i
=0; i
<depth
*4; i
++) av_log(NULL
, AV_LOG_ERROR
, " ");
168 av_log(NULL
, AV_LOG_ERROR
, "Node %p %2d %4d\n", t
, t
->state
, t
->elem
);
169 print(t
->child
[0], depth
+1);
170 print(t
->child
[1], depth
+1);
172 av_log(NULL
, AV_LOG_ERROR
, "NULL\n");
175 int cmp(const void *a
, const void *b
){
181 AVTreeNode
*root
= NULL
, *node
=NULL
;
183 for(i
=0; i
<10000; i
++){
184 int j
= (random()%86294);
185 if(check(root
) > 999){
186 av_log(NULL
, AV_LOG_ERROR
, "FATAL error %d\n", i
);
190 av_log(NULL
, AV_LOG_ERROR
, "inserting %4d\n", j
);
192 node
= av_mallocz(av_tree_node_size
);
193 av_tree_insert(&root
, (void*)(j
+1), cmp
, &node
);
197 AVTreeNode
*node2
=NULL
;
198 av_log(NULL
, AV_LOG_ERROR
, "removing %4d\n", j
);
199 av_tree_insert(&root
, (void*)(j
+1), cmp
, &node2
);
200 k
= av_tree_find(root
, (void*)(j
+1), cmp
, NULL
);
202 av_log(NULL
, AV_LOG_ERROR
, "removal failure %d\n", i
);