Libav
tree.c
Go to the documentation of this file.
1 /*
2  * copyright (c) 2006 Michael Niedermayer <michaelni@gmx.at>
3  *
4  * This file is part of Libav.
5  *
6  * Libav 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.
10  *
11  * Libav 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.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with Libav; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 #include "error.h"
22 #include "mem.h"
23 #include "tree.h"
24 
25 typedef struct AVTreeNode {
26  struct AVTreeNode *child[2];
27  void *elem;
28  int state;
29 } AVTreeNode;
30 
32 {
33  return av_mallocz(sizeof(struct AVTreeNode));
34 }
35 
36 void *av_tree_find(const AVTreeNode *t, void *key,
37  int (*cmp)(void *key, const void *b), void *next[2])
38 {
39  if (t) {
40  unsigned int v = cmp(key, t->elem);
41  if (v) {
42  if (next)
43  next[v >> 31] = t->elem;
44  return av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next);
45  } else {
46  if (next) {
47  av_tree_find(t->child[0], key, cmp, next);
48  av_tree_find(t->child[1], key, cmp, next);
49  }
50  return t->elem;
51  }
52  }
53  return NULL;
54 }
55 
56 void *av_tree_insert(AVTreeNode **tp, void *key,
57  int (*cmp)(void *key, const void *b), AVTreeNode **next)
58 {
59  AVTreeNode *t = *tp;
60  if (t) {
61  unsigned int v = cmp(t->elem, key);
62  void *ret;
63  if (!v) {
64  if (*next)
65  return t->elem;
66  else if (t->child[0] || t->child[1]) {
67  int i = !t->child[0];
68  void *next_elem[2];
69  av_tree_find(t->child[i], key, cmp, next_elem);
70  key = t->elem = next_elem[i];
71  v = -i;
72  } else {
73  *next = t;
74  *tp = NULL;
75  return NULL;
76  }
77  }
78  ret = av_tree_insert(&t->child[v >> 31], key, cmp, next);
79  if (!ret) {
80  int i = (v >> 31) ^ !!*next;
81  AVTreeNode **child = &t->child[i];
82  t->state += 2 * i - 1;
83 
84  if (!(t->state & 1)) {
85  if (t->state) {
86  /* The following code is equivalent to
87  * if ((*child)->state * 2 == -t->state)
88  * rotate(child, i ^ 1);
89  * rotate(tp, i);
90  *
91  * with rotate():
92  * static void rotate(AVTreeNode **tp, int i)
93  * {
94  * AVTreeNode *t= *tp;
95  *
96  * *tp = t->child[i];
97  * t->child[i] = t->child[i]->child[i ^ 1];
98  * (*tp)->child[i ^ 1] = t;
99  * i = 4 * t->state + 2 * (*tp)->state + 12;
100  * t->state = ((0x614586 >> i) & 3) - 1;
101  * (*tp)->state = ((0x400EEA >> i) & 3) - 1 +
102  * ((*tp)->state >> 1);
103  * }
104  * but such a rotate function is both bigger and slower
105  */
106  if ((*child)->state * 2 == -t->state) {
107  *tp = (*child)->child[i ^ 1];
108  (*child)->child[i ^ 1] = (*tp)->child[i];
109  (*tp)->child[i] = *child;
110  *child = (*tp)->child[i ^ 1];
111  (*tp)->child[i ^ 1] = t;
112 
113  (*tp)->child[0]->state = -((*tp)->state > 0);
114  (*tp)->child[1]->state = (*tp)->state < 0;
115  (*tp)->state = 0;
116  } else {
117  *tp = *child;
118  *child = (*child)->child[i ^ 1];
119  (*tp)->child[i ^ 1] = t;
120  if ((*tp)->state)
121  t->state = 0;
122  else
123  t->state >>= 1;
124  (*tp)->state = -t->state;
125  }
126  }
127  }
128  if (!(*tp)->state ^ !!*next)
129  return key;
130  }
131  return ret;
132  } else {
133  *tp = *next;
134  *next = NULL;
135  if (*tp) {
136  (*tp)->elem = key;
137  return NULL;
138  } else
139  return key;
140  }
141 }
142 
144 {
145  if (t) {
146  av_tree_destroy(t->child[0]);
147  av_tree_destroy(t->child[1]);
148  av_free(t);
149  }
150 }
151 
152 void av_tree_enumerate(AVTreeNode *t, void *opaque,
153  int (*cmp)(void *opaque, void *elem),
154  int (*enu)(void *opaque, void *elem))
155 {
156  if (t) {
157  int v = cmp ? cmp(opaque, t->elem) : 0;
158  if (v >= 0)
159  av_tree_enumerate(t->child[0], opaque, cmp, enu);
160  if (v == 0)
161  enu(opaque, t->elem);
162  if (v <= 0)
163  av_tree_enumerate(t->child[1], opaque, cmp, enu);
164  }
165 }
memory handling functions
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:31
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(void *key, const void *b), void *next[2])
Definition: tree.c:36
A tree container.
#define b
Definition: input.c:52
static int cmp(void *a, const void *b)
Definition: tree.c:57
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:143
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
Definition: tree.c:56
void av_free(void *ptr)
Free a memory block which has been allocated with av_malloc(z)() or av_realloc(). ...
Definition: mem.c:190
error code definitions
struct AVTreeNode * child[2]
Definition: tree.c:26
int state
Definition: tree.c:28
NULL
Definition: eval.c:55
void av_tree_enumerate(AVTreeNode *t, void *opaque, int(*cmp)(void *opaque, void *elem), int(*enu)(void *opaque, void *elem))
Apply enu(opaque, &elem) to all the elements in the tree in a given range.
Definition: tree.c:152
void * av_mallocz(size_t size)
Allocate a block of size bytes with alignment suitable for all memory accesses (including vectors if ...
Definition: mem.c:211
void * elem
Definition: tree.c:27