annotate ffmpeg/libavutil/tree.c @ 13:844d341cf643 tip

Back up before ISMIR
author Yading Song <yading.song@eecs.qmul.ac.uk>
date Thu, 31 Oct 2013 13:17:06 +0000
parents f445c3017523
children
rev   line source
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