Now inbound_cap_ls() can enable extensions when a bouncer uses a namespace for the...
[rofl0r-ixchat.git] / src / common / tree.c
blob0a459779809726cdda2011b0bf09087dc781baed
1 /*
2 This is used for quick userlist insertion and lookup. It's not really
3 a tree, but it could be :)
4 */
6 #include <stdio.h>
7 #include <string.h>
8 #include <stdlib.h>
10 #include "tree.h"
12 #define ARRAY_GROW 32
14 struct _tree
16 int elements;
17 int array_size;
18 void **array;
19 tree_cmp_func *cmp;
20 void *data;
23 tree *
24 tree_new (tree_cmp_func *cmp, void *data)
26 tree *t = calloc (1, sizeof (tree));
27 t->cmp = cmp;
28 t->data = data;
29 return t;
32 void
33 tree_destroy (tree *t)
35 if (t)
37 if (t->array)
38 free (t->array);
39 free (t);
43 static int
44 tree_find_insertion_pos (tree *t, void *key, int *done)
46 int c, u, l, idx;
48 if (t->elements < 1)
50 *done = 1;
51 t->array[0] = key;
52 t->elements++;
53 return 0;
56 if (t->elements < 2)
58 *done = 1;
59 c = t->cmp (key, t->array[0], t->data);
60 if (c == 0)
61 return -1;
62 t->elements++;
63 if (c > 0)
65 t->array[1] = key;
66 return 1;
68 t->array[1] = t->array[0];
69 t->array[0] = key;
70 return 0;
73 *done = 0;
75 c = t->cmp (key, t->array[0], t->data);
76 if (c < 0)
77 return 0; /* prepend */
79 c = t->cmp (key, t->array[t->elements - 1], t->data);
80 if (c > 0)
81 return t->elements; /* append */
83 l = 0;
84 u = t->elements - 1;
85 while (1)
87 idx = (l + u) / 2;
88 c = t->cmp (key, t->array[idx], t->data);
90 if (0 > c)
91 u = idx;
92 else if (0 < c && 0 > t->cmp (key, t->array[idx+1], t->data))
93 return idx + 1;
94 else if (c == 0)
95 return -1;
96 else
97 l = idx + 1;
101 static void
102 tree_insert_at_pos (tree *t, void *key, int pos)
104 int post_bytes;
106 /* append is easy */
107 if (pos != t->elements)
109 post_bytes = (t->elements - pos) * sizeof (void *);
110 memmove (&t->array[pos + 1], &t->array[pos], post_bytes);
113 t->array[pos] = key;
114 t->elements++;
117 static void *
118 mybsearch (const void *key, void **array, size_t nmemb,
119 int (*compar) (const void *, const void *, void *data), void *data, int *pos)
121 int l, u, idx;
122 int comparison;
124 l = 0;
125 u = nmemb;
126 while (l < u)
128 idx = (l + u) / 2;
129 comparison = (*compar) (key, array[idx], data);
130 if (comparison < 0)
131 u = idx;
132 else if (comparison > 0)
133 l = idx + 1;
134 else
136 *pos = idx;
137 return array[idx];
141 return NULL;
144 void *
145 tree_find (tree *t, void *key, tree_cmp_func *cmp, void *data, int *pos)
147 if (!t || !t->array)
148 return NULL;
150 return mybsearch (key, &t->array[0], t->elements, cmp, data, pos);
153 void
154 tree_remove_at_pos (tree *t, int pos)
156 int post_bytes;
158 t->elements--;
159 if (pos != t->elements)
161 post_bytes = (t->elements - pos) * sizeof (void *);
162 memmove (&t->array[pos], &t->array[pos + 1], post_bytes);
167 tree_remove (tree *t, void *key, int *pos)
169 void *data;
171 data = tree_find (t, key, t->cmp, t->data, pos);
172 if (!data)
173 return 0;
175 tree_remove_at_pos (t, *pos);
176 return 1;
179 void
180 tree_foreach (tree *t, tree_traverse_func *func, void *data)
182 int j;
184 if (!t || !t->array)
185 return;
187 for (j = 0; j < t->elements; j++)
189 if (!func (t->array[j], data))
190 break;
194 static void
195 tree_grow (tree *t)
197 if (t->array_size < t->elements + 1)
199 int new_size = t->array_size + ARRAY_GROW;
201 t->array = realloc (t->array, sizeof (void *) * new_size);
202 t->array_size = new_size;
208 tree_insert (tree *t, void *key)
210 int pos, done;
212 if (!t)
213 return -1;
215 tree_grow (t);
216 pos = tree_find_insertion_pos (t, key, &done);
217 if (!done && pos != -1)
218 tree_insert_at_pos (t, key, pos);
220 return pos;
223 void
224 tree_append (tree *t, void *key)
226 tree_grow (t);
227 tree_insert_at_pos (t, key, t->elements);
230 int tree_size (tree *t)
232 return t->elements;