1 /*
2 Copyright (C) 2003 Commonwealth Scientific and Industrial Research
3 Organisation (CSIRO) Australia
4
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
7 are met:
8
9 - Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11
12 - Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in the
14 documentation and/or other materials provided with the distribution.
15
16 - Neither the name of CSIRO Australia nor the names of its
17 contributors may be used to endorse or promote products derived from
18 this software without specific prior written permission.
19
20 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
23 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE ORGANISATION OR
24 CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #include "config.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38
39 #include "oggz_macros.h"
40
41 typedef int (*OggzFunc) (void * data);
42 typedef int (*OggzFunc1) (void * data, void * arg);
43 typedef int (*OggzFindFunc) (void * data, long serialno);
44 typedef int (*OggzCmpFunc) (const void * a, const void * b, void * user_data);
45
46 typedef struct _OggzVector OggzVector;
47
48 typedef union {
49 void * p;
50 long l;
51 } oggz_data_t;
52
53 struct _OggzVector {
54 int max_elements;
55 int nr_elements;
56 oggz_data_t * data;
57 OggzCmpFunc compare;
58 void * compare_user_data;
59 };
60
61 /*
62 * A vector of void * or long; iff it's a vector of void * objects, it
63 * can be optionally sorted. (The sorting is used to implement the
64 * packet queue; the vector of longs is used to implement OggzTable)
65 *
66 * if you set a comparison function (oggz_vector_set_cmp()), the vector
67 * will be sorted and new elements will be inserted in sorted order.
68 *
69 * if you don't set a comparison function, new elements will be appended
70 * at the tail
71 *
72 * to unset the comparison function, call oggz_vector_set_cmp (NULL,NULL)
73 */
74
75 OggzVector *
oggz_vector_new(void)76 oggz_vector_new (void)
77 {
78 OggzVector * vector;
79
80 vector = oggz_malloc (sizeof (OggzVector));
81 if (vector == NULL) return NULL;
82
83 vector->max_elements = 0;
84 vector->nr_elements = 0;
85 vector->data = NULL;
86 vector->compare = NULL;
87 vector->compare_user_data = NULL;
88
89 return vector;
90 }
91
92 static void
oggz_vector_clear(OggzVector * vector)93 oggz_vector_clear (OggzVector * vector)
94 {
95 if (vector->data)
96 {
97 oggz_free (vector->data);
98 vector->data = NULL;
99 }
100
101 vector->nr_elements = 0;
102 vector->max_elements = 0;
103 }
104
105 void
oggz_vector_delete(OggzVector * vector)106 oggz_vector_delete (OggzVector * vector)
107 {
108 oggz_vector_clear (vector);
109 oggz_free (vector);
110 }
111
112 int
oggz_vector_size(OggzVector * vector)113 oggz_vector_size (OggzVector * vector)
114 {
115 if (vector == NULL) return 0;
116
117 return vector->nr_elements;
118 }
119
120 void *
oggz_vector_nth_p(OggzVector * vector,int n)121 oggz_vector_nth_p (OggzVector * vector, int n)
122 {
123 if (vector == NULL) return NULL;
124
125 if (n >= vector->nr_elements) return NULL;
126
127 return vector->data[n].p;
128 }
129
130 long
oggz_vector_nth_l(OggzVector * vector,int n)131 oggz_vector_nth_l (OggzVector * vector, int n)
132 {
133 if (vector == NULL) return -1L;
134
135 if (n >= vector->nr_elements) return -1L;
136
137 return vector->data[n].l;
138 }
139
140 void *
oggz_vector_find_p(OggzVector * vector,const void * data)141 oggz_vector_find_p (OggzVector * vector, const void * data)
142 {
143 void * d;
144 int i;
145
146 if (vector->compare == NULL) return NULL;
147
148 for (i = 0; i < vector->nr_elements; i++) {
149 d = vector->data[i].p;
150 if (vector->compare (d, data, vector->compare_user_data))
151 return d;
152 }
153
154 return NULL;
155 }
156
157 int
oggz_vector_find_index_p(OggzVector * vector,const void * data)158 oggz_vector_find_index_p (OggzVector * vector, const void * data)
159 {
160 void * d;
161 int i;
162
163 if (vector->compare == NULL) return -1;
164
165 for (i = 0; i < vector->nr_elements; i++) {
166 d = vector->data[i].p;
167 if (vector->compare (d, data, vector->compare_user_data))
168 return i;
169 }
170
171 return -1;
172 }
173
174 void *
oggz_vector_find_with(OggzVector * vector,OggzFindFunc func,long serialno)175 oggz_vector_find_with (OggzVector * vector, OggzFindFunc func, long serialno)
176 {
177 void * d;
178 int i;
179
180 for (i = 0; i < vector->nr_elements; i++) {
181 d = vector->data[i].p;
182 if (func (d, serialno))
183 return d;
184 }
185
186 return NULL;
187 }
188
189 int
oggz_vector_foreach(OggzVector * vector,OggzFunc func)190 oggz_vector_foreach (OggzVector * vector, OggzFunc func)
191 {
192 int i;
193
194 for (i = 0; i < vector->nr_elements; i++) {
195 func (vector->data[i].p);
196 }
197
198 return 0;
199 }
200
201 int
oggz_vector_foreach1(OggzVector * vector,OggzFunc1 func,void * arg)202 oggz_vector_foreach1 (OggzVector * vector, OggzFunc1 func, void *arg)
203 {
204 int i;
205
206 for (i = 0; i < vector->nr_elements; i++) {
207 func (vector->data[i].p, arg);
208 }
209
210 return 0;
211 }
212
213 static void
_array_swap(oggz_data_t v[],int i,int j)214 _array_swap (oggz_data_t v[], int i, int j)
215 {
216 void * t;
217
218 t = v[i].p;
219 v[i].p = v[j].p;
220 v[j].p = t;
221 }
222
223 /**
224 * Helper function for oggz_vector_insert (). Sorts the vector by
225 * insertion sort, assuming the tail element has just been added and the
226 * rest of the vector is sorted.
227 * \param vector An OggzVector
228 * \pre The vector has just had a new element added to its tail
229 * \pre All elements other than the tail element are already sorted.
230 */
231 static void
oggz_vector_tail_insertion_sort(OggzVector * vector)232 oggz_vector_tail_insertion_sort (OggzVector * vector)
233 {
234 int i;
235
236 if (vector->compare == NULL) return;
237
238 for (i = vector->nr_elements-1; i > 0; i--) {
239 if (vector->compare (vector->data[i-1].p, vector->data[i].p,
240 vector->compare_user_data) > 0) {
241 _array_swap (vector->data, i, i-1);
242 } else {
243 break;
244 }
245 }
246
247 return;
248 }
249
250 static OggzVector *
oggz_vector_grow(OggzVector * vector)251 oggz_vector_grow (OggzVector * vector)
252 {
253 void * new_elements;
254 int new_max_elements;
255
256 vector->nr_elements++;
257
258 if (vector->nr_elements > vector->max_elements) {
259 if (vector->max_elements == 0) {
260 new_max_elements = 1;
261 } else {
262 new_max_elements = vector->max_elements * 2;
263 }
264
265 new_elements =
266 oggz_realloc (vector->data, (size_t)new_max_elements * sizeof (oggz_data_t));
267
268 if (new_elements == NULL) {
269 vector->nr_elements--;
270 return NULL;
271 }
272
273 vector->max_elements = new_max_elements;
274 vector->data = new_elements;
275 }
276
277 return vector;
278 }
279
280 void *
oggz_vector_insert_p(OggzVector * vector,void * data)281 oggz_vector_insert_p (OggzVector * vector, void * data)
282 {
283 if (oggz_vector_grow (vector) == NULL)
284 return NULL;
285
286 vector->data[vector->nr_elements-1].p = data;
287
288 oggz_vector_tail_insertion_sort (vector);
289
290 return data;
291
292 }
293
294 long
oggz_vector_insert_l(OggzVector * vector,long ldata)295 oggz_vector_insert_l (OggzVector * vector, long ldata)
296 {
297 if (oggz_vector_grow (vector) == NULL)
298 return -1;
299
300 vector->data[vector->nr_elements-1].l = ldata;
301
302 return ldata;
303 }
304
305 static void
oggz_vector_qsort(OggzVector * vector,int left,int right)306 oggz_vector_qsort (OggzVector * vector, int left, int right)
307 {
308 int i, last;
309 oggz_data_t * v = vector->data;
310
311 if (left >= right) return;
312
313 _array_swap (v, left, (left + right)/2);
314 last = left;
315 for (i = left+1; i <= right; i++) {
316 if (vector->compare (v[i].p, v[left].p, vector->compare_user_data) < 0)
317 _array_swap (v, ++last, i);
318 }
319 _array_swap (v, left, last);
320 oggz_vector_qsort (vector, left, last-1);
321 oggz_vector_qsort (vector, last+1, right);
322 }
323
324 int
oggz_vector_set_cmp(OggzVector * vector,OggzCmpFunc compare,void * user_data)325 oggz_vector_set_cmp (OggzVector * vector, OggzCmpFunc compare,
326 void * user_data)
327 {
328 vector->compare = compare;
329 vector->compare_user_data = user_data;
330
331 if (compare) {
332 oggz_vector_qsort (vector, 0, vector->nr_elements-1);
333 }
334
335 return 0;
336 }
337
338
339 static void *
oggz_vector_remove_nth(OggzVector * vector,int n)340 oggz_vector_remove_nth (OggzVector * vector, int n)
341 {
342 int i;
343 oggz_data_t * new_elements;
344 int new_max_elements;
345
346 vector->nr_elements--;
347
348 if (vector->nr_elements == 0) {
349 oggz_vector_clear (vector);
350 } else {
351 for (i = n; i < vector->nr_elements; i++) {
352 vector->data[i] = vector->data[i+1];
353 }
354
355 if (vector->nr_elements < vector->max_elements/2) {
356 new_max_elements = vector->max_elements/2;
357
358 new_elements =
359 oggz_realloc (vector->data,
360 (size_t)new_max_elements * sizeof (oggz_data_t));
361
362 if (new_elements == NULL) {
363 vector->data = NULL;
364 return NULL;
365 }
366
367 vector->max_elements = new_max_elements;
368 vector->data = new_elements;
369 }
370 }
371
372 return vector;
373 }
374
375 OggzVector *
oggz_vector_remove_p(OggzVector * vector,void * data)376 oggz_vector_remove_p (OggzVector * vector, void * data)
377 {
378 int i;
379
380 for (i = 0; i < vector->nr_elements; i++) {
381 if (vector->data[i].p == data) {
382 return oggz_vector_remove_nth (vector, i);
383 }
384 }
385
386 return vector;
387 }
388
389 OggzVector *
oggz_vector_remove_l(OggzVector * vector,long ldata)390 oggz_vector_remove_l (OggzVector * vector, long ldata)
391 {
392 int i;
393
394 for (i = 0; i < vector->nr_elements; i++) {
395 if (vector->data[i].l == ldata) {
396 return oggz_vector_remove_nth (vector, i);
397 }
398 }
399
400 return vector;
401 }
402
403 void *
oggz_vector_pop(OggzVector * vector)404 oggz_vector_pop (OggzVector * vector)
405 {
406 void * data;
407
408 if (vector == NULL || vector->data == NULL) return NULL;
409
410 data = vector->data[0].p;
411
412 oggz_vector_remove_nth (vector, 0);
413
414 return data;
415
416 }
417