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