blob: 72d7f40abc4e6b4a8b1f750f830a1c97256ac339 [file] [log] [blame]
Michael Niedermayer9eb88fd2006-11-14 01:02:301/*
2 * copyright (c) 2006 Michael Niedermayer <[email protected]>
3 *
Mans Rullgard2912e872011-03-18 17:35:104 * This file is part of Libav.
Michael Niedermayer9eb88fd2006-11-14 01:02:305 *
Mans Rullgard2912e872011-03-18 17:35:106 * Libav is free software; you can redistribute it and/or
Michael Niedermayer9eb88fd2006-11-14 01:02:307 * 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.
10 *
Mans Rullgard2912e872011-03-18 17:35:1011 * Libav is distributed in the hope that it will be useful,
Michael Niedermayer9eb88fd2006-11-14 01:02:3012 * 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.
15 *
16 * You should have received a copy of the GNU Lesser General Public
Mans Rullgard2912e872011-03-18 17:35:1017 * License along with Libav; if not, write to the Free Software
Michael Niedermayer9eb88fd2006-11-14 01:02:3018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
Michael Niedermayer9eb88fd2006-11-14 01:02:3021#include "log.h"
Martin Storsjö1d9c2dc2012-08-06 13:49:3222#include "mem.h"
Michael Niedermayer9eb88fd2006-11-14 01:02:3023#include "tree.h"
24
Yordan Makariev425b45d2011-12-03 18:25:5725typedef struct AVTreeNode {
Michael Niedermayer9eb88fd2006-11-14 01:02:3026 struct AVTreeNode *child[2];
27 void *elem;
28 int state;
Yordan Makariev425b45d2011-12-03 18:25:5729} AVTreeNode;
Michael Niedermayer9eb88fd2006-11-14 01:02:3030
Martin Storsjö9a92aea2012-10-11 12:08:0431#if FF_API_CONTEXT_SIZE
Michael Niedermayer6e8b9822008-01-04 17:52:1632const int av_tree_node_size = sizeof(AVTreeNode);
Martin Storsjö9a92aea2012-10-11 12:08:0433#endif
34
35struct AVTreeNode *av_tree_node_alloc(void)
36{
37 return av_mallocz(sizeof(struct AVTreeNode));
38}
Michael Niedermayer6e8b9822008-01-04 17:52:1639
Yordan Makariev425b45d2011-12-03 18:25:5740void *av_tree_find(const AVTreeNode *t, void *key,
41 int (*cmp)(void *key, const void *b), void *next[2])
42{
43 if (t) {
44 unsigned int v = cmp(key, t->elem);
45 if (v) {
Diego Biurrun10db1a92012-10-16 14:08:0546 if (next)
47 next[v >> 31] = t->elem;
Yordan Makariev425b45d2011-12-03 18:25:5748 return av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next);
49 } else {
50 if (next) {
Michael Niedermayer116d15cc2008-01-04 10:14:2151 av_tree_find(t->child[0], key, cmp, next);
52 av_tree_find(t->child[1], key, cmp, next);
53 }
Michael Niedermayer9eb88fd2006-11-14 01:02:3054 return t->elem;
55 }
56 }
57 return NULL;
58}
59
Yordan Makariev425b45d2011-12-03 18:25:5760void *av_tree_insert(AVTreeNode **tp, void *key,
61 int (*cmp)(void *key, const void *b), AVTreeNode **next)
62{
63 AVTreeNode *t = *tp;
64 if (t) {
65 unsigned int v = cmp(t->elem, key);
Michael Niedermayerf05dda32008-01-04 18:20:0366 void *ret;
Yordan Makariev425b45d2011-12-03 18:25:5767 if (!v) {
68 if (*next)
Michael Niedermayerf05dda32008-01-04 18:20:0369 return t->elem;
Yordan Makariev425b45d2011-12-03 18:25:5770 else if (t->child[0] || t->child[1]) {
71 int i = !t->child[0];
Michael Niedermayerf05dda32008-01-04 18:20:0372 void *next_elem[2];
Michael Niedermayer3f161c72008-01-16 01:54:1873 av_tree_find(t->child[i], key, cmp, next_elem);
Yordan Makariev425b45d2011-12-03 18:25:5774 key = t->elem = next_elem[i];
Diego Biurrun10db1a92012-10-16 14:08:0575 v = -i;
Yordan Makariev425b45d2011-12-03 18:25:5776 } else {
77 *next = t;
Diego Biurrun10db1a92012-10-16 14:08:0578 *tp = NULL;
Michael Niedermayerf05dda32008-01-04 18:20:0379 return NULL;
80 }
81 }
Yordan Makariev425b45d2011-12-03 18:25:5782 ret = av_tree_insert(&t->child[v >> 31], key, cmp, next);
83 if (!ret) {
Diego Biurrun10db1a92012-10-16 14:08:0584 int i = (v >> 31) ^ !!*next;
Yordan Makariev425b45d2011-12-03 18:25:5785 AVTreeNode **child = &t->child[i];
86 t->state += 2 * i - 1;
Michael Niedermayerf05dda32008-01-04 18:20:0387
Yordan Makariev425b45d2011-12-03 18:25:5788 if (!(t->state & 1)) {
89 if (t->state) {
Michael Niedermayer51198a82008-01-23 21:03:2190 /* The following code is equivalent to
Diego Biurrun10db1a92012-10-16 14:08:0591 * if ((*child)->state * 2 == -t->state)
92 * rotate(child, i ^ 1);
93 * rotate(tp, i);
94 *
95 * with rotate():
96 * static void rotate(AVTreeNode **tp, int i)
97 * {
98 * AVTreeNode *t= *tp;
99 *
100 * *tp = t->child[i];
101 * t->child[i] = t->child[i]->child[i ^ 1];
102 * (*tp)->child[i ^ 1] = t;
103 * i = 4 * t->state + 2 * (*tp)->state + 12;
104 * t->state = ((0x614586 >> i) & 3) - 1;
105 * (*tp)->state = ((0x400EEA >> i) & 3) - 1 +
106 * ((*tp)->state >> 1);
107 * }
108 * but such a rotate function is both bigger and slower
109 */
110 if ((*child)->state * 2 == -t->state) {
Yordan Makariev425b45d2011-12-03 18:25:57111 *tp = (*child)->child[i ^ 1];
112 (*child)->child[i ^ 1] = (*tp)->child[i];
113 (*tp)->child[i] = *child;
Diego Biurrun10db1a92012-10-16 14:08:05114 *child = (*tp)->child[i ^ 1];
Yordan Makariev425b45d2011-12-03 18:25:57115 (*tp)->child[i ^ 1] = t;
Michael Niedermayer9eb88fd2006-11-14 01:02:30116
Yordan Makariev425b45d2011-12-03 18:25:57117 (*tp)->child[0]->state = -((*tp)->state > 0);
Diego Biurrun10db1a92012-10-16 14:08:05118 (*tp)->child[1]->state = (*tp)->state < 0;
Yordan Makariev425b45d2011-12-03 18:25:57119 (*tp)->state = 0;
120 } else {
Diego Biurrun10db1a92012-10-16 14:08:05121 *tp = *child;
122 *child = (*child)->child[i ^ 1];
123 (*tp)->child[i ^ 1] = t;
124 if ((*tp)->state)
125 t->state = 0;
126 else
127 t->state >>= 1;
128 (*tp)->state = -t->state;
Michael Niedermayer9eb88fd2006-11-14 01:02:30129 }
Michael Niedermayer9eb88fd2006-11-14 01:02:30130 }
131 }
Yordan Makariev425b45d2011-12-03 18:25:57132 if (!(*tp)->state ^ !!*next)
Michael Niedermayera35bf972008-01-04 19:16:38133 return key;
134 }
135 return ret;
Yordan Makariev425b45d2011-12-03 18:25:57136 } else {
137 *tp = *next;
138 *next = NULL;
139 if (*tp) {
140 (*tp)->elem = key;
Michael Niedermayereed36072008-09-19 12:41:12141 return NULL;
Yordan Makariev425b45d2011-12-03 18:25:57142 } else
Michael Niedermayereed36072008-09-19 12:41:12143 return key;
Michael Niedermayer9eb88fd2006-11-14 01:02:30144 }
145}
146
Yordan Makariev425b45d2011-12-03 18:25:57147void av_tree_destroy(AVTreeNode *t)
148{
149 if (t) {
Aurelien Jacobs045cbba2009-01-04 17:48:54150 av_tree_destroy(t->child[0]);
151 av_tree_destroy(t->child[1]);
152 av_free(t);
Aurelien Jacobsd8bd1132009-01-04 17:48:19153 }
Michael Niedermayer9eb88fd2006-11-14 01:02:30154}
155
Yordan Makariev425b45d2011-12-03 18:25:57156void av_tree_enumerate(AVTreeNode *t, void *opaque,
157 int (*cmp)(void *opaque, void *elem),
158 int (*enu)(void *opaque, void *elem))
159{
160 if (t) {
161 int v = cmp ? cmp(opaque, t->elem) : 0;
162 if (v >= 0)
163 av_tree_enumerate(t->child[0], opaque, cmp, enu);
164 if (v == 0)
165 enu(opaque, t->elem);
166 if (v <= 0)
167 av_tree_enumerate(t->child[1], opaque, cmp, enu);
Michael Niedermayeredabf352009-11-14 19:14:14168 }
Michael Niedermayer9eb88fd2006-11-14 01:02:30169}
Michael Niedermayer9eb88fd2006-11-14 01:02:30170
171#ifdef TEST
Diego Biurrun294eaa22009-03-20 11:48:27172
Martin Storsjö1d9c2dc2012-08-06 13:49:32173#include "common.h"
Diego Biurrun294eaa22009-03-20 11:48:27174#include "lfg.h"
175
Yordan Makariev425b45d2011-12-03 18:25:57176static int check(AVTreeNode *t)
177{
178 if (t) {
179 int left = check(t->child[0]);
180 int right = check(t->child[1]);
Michael Niedermayer9eb88fd2006-11-14 01:02:30181
Diego Biurrun10db1a92012-10-16 14:08:05182 if (left > 999 || right > 999)
Michael Niedermayer9eb88fd2006-11-14 01:02:30183 return 1000;
Yordan Makariev425b45d2011-12-03 18:25:57184 if (right - left != t->state)
Michael Niedermayer9eb88fd2006-11-14 01:02:30185 return 1000;
Diego Biurrun10db1a92012-10-16 14:08:05186 if (t->state > 1 || t->state < -1)
Michael Niedermayer9eb88fd2006-11-14 01:02:30187 return 1000;
Yordan Makariev425b45d2011-12-03 18:25:57188 return FFMAX(left, right) + 1;
Michael Niedermayer9eb88fd2006-11-14 01:02:30189 }
190 return 0;
191}
192
Yordan Makariev425b45d2011-12-03 18:25:57193static void print(AVTreeNode *t, int depth)
194{
Michael Niedermayer9eb88fd2006-11-14 01:02:30195 int i;
Diego Biurrun10db1a92012-10-16 14:08:05196 for (i = 0; i < depth * 4; i++)
197 av_log(NULL, AV_LOG_ERROR, " ");
Yordan Makariev425b45d2011-12-03 18:25:57198 if (t) {
Benoit Fouet168fffd2009-03-31 14:00:46199 av_log(NULL, AV_LOG_ERROR, "Node %p %2d %p\n", t, t->state, t->elem);
Yordan Makariev425b45d2011-12-03 18:25:57200 print(t->child[0], depth + 1);
201 print(t->child[1], depth + 1);
202 } else
Michael Niedermayer9eb88fd2006-11-14 01:02:30203 av_log(NULL, AV_LOG_ERROR, "NULL\n");
204}
205
Yordan Makariev425b45d2011-12-03 18:25:57206static int cmp(void *a, const void *b)
207{
208 return (uint8_t *) a - (const uint8_t *) b;
Michael Niedermayer9eb88fd2006-11-14 01:02:30209}
210
Diego Biurrun10db1a92012-10-16 14:08:05211int main(void)
Yordan Makariev425b45d2011-12-03 18:25:57212{
Benoit Fouet168fffd2009-03-31 14:00:46213 int i;
214 void *k;
Yordan Makariev425b45d2011-12-03 18:25:57215 AVTreeNode *root = NULL, *node = NULL;
Diego Biurrun64bde192009-04-10 17:23:38216 AVLFG prng;
Diego Biurrun294eaa22009-03-20 11:48:27217
Diego Biurrun64bde192009-04-10 17:23:38218 av_lfg_init(&prng, 1);
Michael Niedermayer9eb88fd2006-11-14 01:02:30219
Yordan Makariev425b45d2011-12-03 18:25:57220 for (i = 0; i < 10000; i++) {
Diego Biurrun64bde192009-04-10 17:23:38221 int j = av_lfg_get(&prng) % 86294;
Yordan Makariev425b45d2011-12-03 18:25:57222 if (check(root) > 999) {
Michael Niedermayer9eb88fd2006-11-14 01:02:30223 av_log(NULL, AV_LOG_ERROR, "FATAL error %d\n", i);
Diego Biurrun10db1a92012-10-16 14:08:05224 print(root, 0);
Michael Niedermayer9eb88fd2006-11-14 01:02:30225 return -1;
226 }
227 av_log(NULL, AV_LOG_ERROR, "inserting %4d\n", j);
Yordan Makariev425b45d2011-12-03 18:25:57228 if (!node)
Martin Storsjöe002e322012-10-11 12:10:45229 node = av_tree_node_alloc();
Diego Biurrun10db1a92012-10-16 14:08:05230 av_tree_insert(&root, (void *)(j + 1), cmp, &node);
Michael Niedermayerf05dda32008-01-04 18:20:03231
Diego Biurrun64bde192009-04-10 17:23:38232 j = av_lfg_get(&prng) % 86294;
Michael Niedermayereed36072008-09-19 12:41:12233 {
Yordan Makariev425b45d2011-12-03 18:25:57234 AVTreeNode *node2 = NULL;
Michael Niedermayer5d1e3d22008-01-16 01:54:56235 av_log(NULL, AV_LOG_ERROR, "removing %4d\n", j);
Diego Biurrun10db1a92012-10-16 14:08:05236 av_tree_insert(&root, (void *)(j + 1), cmp, &node2);
237 k = av_tree_find(root, (void *)(j + 1), cmp, NULL);
Yordan Makariev425b45d2011-12-03 18:25:57238 if (k)
Diego Biurrun89c9ff52009-01-28 00:16:05239 av_log(NULL, AV_LOG_ERROR, "removal failure %d\n", i);
Michael Niedermayerf05dda32008-01-04 18:20:03240 }
Michael Niedermayer9eb88fd2006-11-14 01:02:30241 }
242 return 0;
243}
244#endif