root/liboggz/trunk/src/liboggz/oggz_vector.c

Revision 3525, 9.6 kB (checked in by conrad, 8 months ago)

fix random CRLF line endings

Line 
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 *
76 oggz_vector_new (void)
77 {
78   OggzVector * vector;
79
80   vector = oggz_malloc (sizeof (OggzVector));
81
82   vector->max_elements = 0;
83   vector->nr_elements = 0;
84   vector->data = NULL;
85   vector->compare = NULL;
86   vector->compare_user_data = NULL;
87
88   return vector;
89 }
90
91 static void
92 oggz_vector_clear (OggzVector * vector)
93 {
94   if (vector->data)
95   {
96     oggz_free (vector->data);
97     vector->data = NULL;
98   }
99
100   vector->nr_elements = 0;
101   vector->max_elements = 0;
102 }
103
104 void
105 oggz_vector_delete (OggzVector * vector)
106 {
107   oggz_vector_clear (vector);
108   oggz_free (vector);
109 }
110
111 int
112 oggz_vector_size (OggzVector * vector)
113 {
114   if (vector == NULL) return 0;
115
116   return vector->nr_elements;
117 }
118
119 void *
120 oggz_vector_nth_p (OggzVector * vector, int n)
121 {
122   if (vector == NULL) return NULL;
123
124   if (n >= vector->nr_elements) return NULL;
125
126   return vector->data[n].p;
127 }
128
129 long
130 oggz_vector_nth_l (OggzVector * vector, int n)
131 {
132   if (vector == NULL) return -1L;
133
134   if (n >= vector->nr_elements) return -1L;
135
136   return vector->data[n].l;
137 }
138
139 void *
140 oggz_vector_find_p (OggzVector * vector, const void * data)
141 {
142   void * d;
143   int i;
144
145   if (vector->compare == NULL) return NULL;
146
147   for (i = 0; i < vector->nr_elements; i++) {
148     d = vector->data[i].p;
149     if (vector->compare (d, data, vector->compare_user_data))
150       return d;
151   }
152
153   return NULL;
154 }
155
156 int
157 oggz_vector_find_index_p (OggzVector * vector, const void * data)
158 {
159   void * d;
160   int i;
161
162   if (vector->compare == NULL) return -1;
163
164   for (i = 0; i < vector->nr_elements; i++) {
165     d = vector->data[i].p;
166     if (vector->compare (d, data, vector->compare_user_data))
167       return i;
168   }
169
170   return -1;
171 }
172
173 void *
174 oggz_vector_find_with (OggzVector * vector, OggzFindFunc func, long serialno)
175 {
176   void * d;
177   int i;
178
179   for (i = 0; i < vector->nr_elements; i++) {
180     d = vector->data[i].p;
181     if (func (d, serialno))
182       return d;
183   }
184
185   return NULL;
186 }
187
188 int
189 oggz_vector_foreach (OggzVector * vector, OggzFunc func)
190 {
191   int i;
192
193   for (i = 0; i < vector->nr_elements; i++) {
194     func (vector->data[i].p);
195   }
196
197   return 0;
198 }
199
200 int
201 oggz_vector_foreach1 (OggzVector * vector, OggzFunc1 func, void *arg)
202 {
203   int i;
204
205   for (i = 0; i < vector->nr_elements; i++) {
206     func (vector->data[i].p, arg);
207   }
208
209   return 0;
210 }
211
212 static void
213 _array_swap (oggz_data_t v[], int i, int j)
214 {
215   void * t;
216
217   t = v[i].p;
218   v[i].p = v[j].p;
219   v[j].p = t;
220 }
221
222 /**
223  * Helper function for oggz_vector_insert (). Sorts the vector by
224  * insertion sort, assuming the tail element has just been added and the
225  * rest of the vector is sorted.
226  * \param vector An OggzVector
227  * \pre The vector has just had a new element added to its tail
228  * \pre All elements other than the tail element are already sorted.
229  */
230 static void
231 oggz_vector_tail_insertion_sort (OggzVector * vector)
232 {
233   int i;
234
235   if (vector->compare == NULL) return;
236
237   for (i = vector->nr_elements-1; i > 0; i--) {
238     if (vector->compare (vector->data[i-1].p, vector->data[i].p,
239                          vector->compare_user_data) > 0) {
240       _array_swap (vector->data, i, i-1);
241     } else {
242       break;
243     }
244   }
245
246   return;
247 }
248
249 static OggzVector *
250 oggz_vector_grow (OggzVector * vector)
251 {
252   void * new_elements;
253   int new_max_elements;
254
255   vector->nr_elements++;
256
257   if (vector->nr_elements > vector->max_elements) {
258     if (vector->max_elements == 0) {
259       new_max_elements = 1;
260     } else {
261       new_max_elements = vector->max_elements * 2;
262     }
263
264     new_elements =
265       oggz_realloc (vector->data, (size_t)new_max_elements * sizeof (oggz_data_t));
266
267     if (new_elements == NULL) {
268       vector->nr_elements--;
269       vector->data = NULL;
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 *
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
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
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
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 *
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       {
364         vector->data = NULL;
365         return NULL;
366       }
367
368       vector->max_elements = new_max_elements;
369       vector->data = new_elements;
370     }
371   }
372
373   return vector;
374 }
375
376 OggzVector *
377 oggz_vector_remove_p (OggzVector * vector, void * data)
378 {
379   int i;
380
381   for (i = 0; i < vector->nr_elements; i++) {
382     if (vector->data[i].p == data) {
383       return oggz_vector_remove_nth (vector, i);
384     }
385   }
386
387   return vector;
388 }
389
390 OggzVector *
391 oggz_vector_remove_l (OggzVector * vector, long ldata)
392 {
393   int i;
394
395   for (i = 0; i < vector->nr_elements; i++) {
396     if (vector->data[i].l == ldata) {
397       return oggz_vector_remove_nth (vector, i);
398     }
399   }
400
401   return vector;
402 }
403
404 void *
405 oggz_vector_pop (OggzVector * vector)
406 {
407   void * data;
408 #if 0
409   void * new_elements;
410   int new_max_elements;
411 #endif
412
413   if (!vector || vector->data == NULL) return NULL;
414
415   data = vector->data[0].p;
416
417 #if 0
418   vector->nr_elements--;
419
420   if (vector->nr_elements == 0) {
421     oggz_vector_clear (vector);
422   } else {
423 #if 0
424     memmove (vector->data, &vector->data[1],
425              vector->nr_elements * sizeof (void *));
426 #else
427     {
428       int i;
429       for (i = 0; i < vector->nr_elements; i++) {
430         vector->data[i].p = vector->data[i+1].p;
431       }
432     }
433 #endif
434     if (vector->nr_elements < vector->max_elements/2) {
435       new_max_elements = vector->max_elements/2;
436
437       new_elements =
438         oggz_realloc (vector->data,
439         (size_t)new_max_elements * sizeof (oggz_data_t));
440
441       if (new_elements != NULL) {
442         vector->max_elements = new_max_elements;
443         vector->data = new_elements;
444       }
445     }
446
447   }
448 #else
449
450   oggz_vector_remove_nth (vector, 0);
451
452 #endif
453
454   return data;
455
456 }
Note: See TracBrowser for help on using the browser.