FFmpeg
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 FFmpeg.
5  *
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.
10  *
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.
15  *
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
19  */
20 
21 #include "error.h"
22 #include "log.h"
23 #include "mem.h"
24 #include "tree.h"
25 
26 typedef struct AVTreeNode {
27  struct AVTreeNode *child[2];
28  void *elem;
29  int state;
30 } AVTreeNode;
31 
32 const int av_tree_node_size = sizeof(AVTreeNode);
33 
35 {
36  return av_mallocz(sizeof(struct AVTreeNode));
37 }
38 
39 void *av_tree_find(const AVTreeNode *t, void *key,
40  int (*cmp)(const void *key, const void *b), void *next[2])
41 {
42  if (t) {
43  unsigned int v = cmp(key, t->elem);
44  if (v) {
45  if (next)
46  next[v >> 31] = t->elem;
47  return av_tree_find(t->child[(v >> 31) ^ 1], key, cmp, next);
48  } else {
49  if (next) {
50  av_tree_find(t->child[0], key, cmp, next);
51  av_tree_find(t->child[1], key, cmp, next);
52  }
53  return t->elem;
54  }
55  }
56  return NULL;
57 }
58 
59 void *av_tree_insert(AVTreeNode **tp, void *key,
60  int (*cmp)(const void *key, const void *b), AVTreeNode **next)
61 {
62  AVTreeNode *t = *tp;
63  if (t) {
64  unsigned int v = cmp(t->elem, key);
65  void *ret;
66  if (!v) {
67  if (*next)
68  return t->elem;
69  else if (t->child[0] || t->child[1]) {
70  int i = !t->child[0];
71  void *next_elem[2];
72  av_tree_find(t->child[i], key, cmp, next_elem);
73  key = t->elem = next_elem[i];
74  v = -i;
75  } else {
76  *next = t;
77  *tp = NULL;
78  return NULL;
79  }
80  }
81  ret = av_tree_insert(&t->child[v >> 31], key, cmp, next);
82  if (!ret) {
83  int i = (v >> 31) ^ !!*next;
84  AVTreeNode **child = &t->child[i];
85  t->state += 2 * i - 1;
86 
87  if (!(t->state & 1)) {
88  if (t->state) {
89  /* The following code is equivalent to
90  * if ((*child)->state * 2 == -t->state)
91  * rotate(child, i ^ 1);
92  * rotate(tp, i);
93  *
94  * with rotate():
95  * static void rotate(AVTreeNode **tp, int i)
96  * {
97  * AVTreeNode *t= *tp;
98  *
99  * *tp = t->child[i];
100  * t->child[i] = t->child[i]->child[i ^ 1];
101  * (*tp)->child[i ^ 1] = t;
102  * i = 4 * t->state + 2 * (*tp)->state + 12;
103  * t->state = ((0x614586 >> i) & 3) - 1;
104  * (*tp)->state = ((0x400EEA >> i) & 3) - 1 +
105  * ((*tp)->state >> 1);
106  * }
107  * but such a rotate function is both bigger and slower
108  */
109  if ((*child)->state * 2 == -t->state) {
110  *tp = (*child)->child[i ^ 1];
111  (*child)->child[i ^ 1] = (*tp)->child[i];
112  (*tp)->child[i] = *child;
113  *child = (*tp)->child[i ^ 1];
114  (*tp)->child[i ^ 1] = t;
115 
116  (*tp)->child[0]->state = -((*tp)->state > 0);
117  (*tp)->child[1]->state = (*tp)->state < 0;
118  (*tp)->state = 0;
119  } else {
120  *tp = *child;
121  *child = (*child)->child[i ^ 1];
122  (*tp)->child[i ^ 1] = t;
123  if ((*tp)->state)
124  t->state = 0;
125  else
126  t->state >>= 1;
127  (*tp)->state = -t->state;
128  }
129  }
130  }
131  if (!(*tp)->state ^ !!*next)
132  return key;
133  }
134  return ret;
135  } else {
136  *tp = *next;
137  *next = NULL;
138  if (*tp) {
139  (*tp)->elem = key;
140  return NULL;
141  } else
142  return key;
143  }
144 }
145 
147 {
148  if (t) {
149  av_tree_destroy(t->child[0]);
150  av_tree_destroy(t->child[1]);
151  av_free(t);
152  }
153 }
154 
155 void av_tree_enumerate(AVTreeNode *t, void *opaque,
156  int (*cmp)(void *opaque, void *elem),
157  int (*enu)(void *opaque, void *elem))
158 {
159  if (t) {
160  int v = cmp ? cmp(opaque, t->elem) : 0;
161  if (v >= 0)
162  av_tree_enumerate(t->child[0], opaque, cmp, enu);
163  if (v == 0)
164  enu(opaque, t->elem);
165  if (v <= 0)
166  av_tree_enumerate(t->child[1], opaque, cmp, enu);
167  }
168 }
av_tree_insert
void * av_tree_insert(AVTreeNode **tp, void *key, int(*cmp)(const void *key, const void *b), AVTreeNode **next)
Insert or remove an element.
Definition: tree.c:59
AVTreeNode::elem
void * elem
Definition: tree.c:28
b
#define b
Definition: input.c:41
av_tree_node_alloc
struct AVTreeNode * av_tree_node_alloc(void)
Allocate an AVTreeNode.
Definition: tree.c:34
av_tree_enumerate
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:155
av_tree_node_size
const int av_tree_node_size
Definition: tree.c:32
AVTreeNode::child
struct AVTreeNode * child[2]
Definition: tree.c:27
AVTreeNode::state
int state
Definition: tree.c:29
key
const char * key
Definition: hwcontext_opencl.c:168
NULL
#define NULL
Definition: coverity.c:32
AVTreeNode
Definition: tree.c:26
av_tree_destroy
void av_tree_destroy(AVTreeNode *t)
Definition: tree.c:146
error.h
tree.h
cmp
static int cmp(const void *a, const void *b)
Definition: tree.c:57
i
int i
Definition: input.c:407
log.h
av_mallocz
void * av_mallocz(size_t size)
Allocate a memory block with alignment suitable for all memory accesses (including vectors if availab...
Definition: mem.c:237
ret
ret
Definition: filter_design.txt:187
av_tree_find
void * av_tree_find(const AVTreeNode *t, void *key, int(*cmp)(const void *key, const void *b), void *next[2])
Definition: tree.c:39
mem.h
av_free
#define av_free(p)
Definition: tableprint_vlc.h:34