]>
git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/collections/array.c
2 * Copyright (C) 2014 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * Copyright (C) 2013 Martin Willi
6 * Copyright (C) 2013 revosec AG
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2 of the License, or (at your
11 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #define _GNU_SOURCE /* for qsort_r() */
25 #include <threading/thread_value.h>
29 * Data is an allocated block, with potentially unused head and tail:
31 * "esize" each (or sizeof(void*) if esize = 0)
32 * /-\ /-\ /-\ /-\ /-\ /-\
34 * +---------------+-------------------------------+---------------+
35 * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l |
36 * +---------------+-------------------------------+---------------+
38 * \--------------/ \-----------------------------/ \-------------/
40 * "head" "count" "tail"
44 /** number of elements currently in array (not counting head/tail) */
46 /** size of each element, 0 for a pointer based array */
48 /** allocated but unused elements at array front */
50 /** allocated but unused elements at array end */
57 /* store data to replicate qsort_r in thread local storage */
58 static thread_value_t
*sort_data
;
61 /** maximum number of unused head/tail elements before cleanup */
62 #define ARRAY_MAX_UNUSED 32
65 * Get the actual size of a number of elements
67 static size_t get_size(array_t
*array
, u_int32_t num
)
71 return array
->esize
* num
;
73 return sizeof(void*) * num
;
77 * Increase allocated but unused tail room to at least "room"
79 static void make_tail_room(array_t
*array
, u_int8_t room
)
81 if (array
->tail
< room
)
83 array
->data
= realloc(array
->data
,
84 get_size(array
, array
->count
+ array
->head
+ room
));
90 * Increase allocated but unused head room to at least "room"
92 static void make_head_room(array_t
*array
, u_int8_t room
)
94 if (array
->head
< room
)
96 u_int8_t increase
= room
- array
->head
;
98 array
->data
= realloc(array
->data
,
99 get_size(array
, array
->count
+ array
->tail
+ room
));
100 memmove(array
->data
+ get_size(array
, increase
), array
->data
,
101 get_size(array
, array
->count
+ array
->tail
+ array
->head
));
107 * Make space for an item at index using tail room
109 static void insert_tail(array_t
*array
, int idx
)
111 make_tail_room(array
, 1);
112 /* move up all elements after idx by one */
113 memmove(array
->data
+ get_size(array
, array
->head
+ idx
+ 1),
114 array
->data
+ get_size(array
, array
->head
+ idx
),
115 get_size(array
, array
->count
- idx
));
122 * Make space for an item at index using head room
124 static void insert_head(array_t
*array
, int idx
)
126 make_head_room(array
, 1);
127 /* move down all elements before idx by one */
128 memmove(array
->data
+ get_size(array
, array
->head
- 1),
129 array
->data
+ get_size(array
, array
->head
),
130 get_size(array
, idx
));
137 * Remove an item, increase tail
139 static void remove_tail(array_t
*array
, int idx
)
141 /* move all items after idx one down */
142 memmove(array
->data
+ get_size(array
, idx
+ array
->head
),
143 array
->data
+ get_size(array
, idx
+ array
->head
+ 1),
144 get_size(array
, array
->count
- idx
));
150 * Remove an item, increase head
152 static void remove_head(array_t
*array
, int idx
)
154 /* move all items before idx one up */
155 memmove(array
->data
+ get_size(array
, array
->head
+ 1),
156 array
->data
+ get_size(array
, array
->head
), get_size(array
, idx
));
161 array_t
*array_create(u_int esize
, u_int8_t reserve
)
171 array
->data
= malloc(array
->tail
* array
->esize
);
176 int array_count(array_t
*array
)
185 void array_compress(array_t
*array
)
194 memmove(array
->data
, array
->data
+ get_size(array
, array
->head
),
195 get_size(array
, array
->count
+ array
->tail
));
201 array
->data
= realloc(array
->data
, get_size(array
, array
->count
));
208 /** public enumerator interface */
210 /** enumerated array */
212 /** current index +1, initialized at 0 */
214 } array_enumerator_t
;
216 METHOD(enumerator_t
, enumerate
, bool,
217 array_enumerator_t
*this, void **out
)
221 if (this->idx
>= this->array
->count
)
226 pos
= this->array
->data
+
227 get_size(this->array
, this->idx
+ this->array
->head
);
228 if (this->array
->esize
)
230 /* for element based arrays we return a pointer to the element */
235 /* for pointer based arrays we return the pointer directly */
242 enumerator_t
* array_create_enumerator(array_t
*array
)
244 array_enumerator_t
*enumerator
;
248 return enumerator_create_empty();
253 .enumerate
= (void*)_enumerate
,
254 .destroy
= (void*)free
,
258 return &enumerator
->public;
261 void array_remove_at(array_t
*array
, enumerator_t
*public)
263 array_enumerator_t
*enumerator
= (array_enumerator_t
*)public;
267 array_remove(array
, --enumerator
->idx
, NULL
);
271 void array_insert_create(array_t
**array
, int idx
, void *ptr
)
275 *array
= array_create(0, 0);
277 array_insert(*array
, idx
, ptr
);
280 void array_insert_enumerator(array_t
*array
, int idx
, enumerator_t
*enumerator
)
284 while (enumerator
->enumerate(enumerator
, &ptr
))
286 array_insert(array
, idx
, ptr
);
288 enumerator
->destroy(enumerator
);
291 void array_insert(array_t
*array
, int idx
, void *data
)
293 if (idx
< 0 || idx
<= array_count(array
))
299 idx
= array_count(array
);
302 if (array
->head
&& !array
->tail
)
304 insert_head(array
, idx
);
306 else if (array
->tail
&& !array
->head
)
308 insert_tail(array
, idx
);
310 else if (idx
> array_count(array
) / 2)
312 insert_tail(array
, idx
);
316 insert_head(array
, idx
);
319 pos
= array
->data
+ get_size(array
, array
->head
+ idx
);
322 memcpy(pos
, data
, get_size(array
, 1));
326 /* pointer based array, copy pointer value */
332 bool array_get(array_t
*array
, int idx
, void *data
)
338 if (idx
>= 0 && idx
>= array_count(array
))
344 if (array_count(array
) == 0)
348 idx
= array_count(array
) - 1;
352 memcpy(data
, array
->data
+ get_size(array
, array
->head
+ idx
),
358 bool array_remove(array_t
*array
, int idx
, void *data
)
360 if (!array_get(array
, idx
, data
))
364 if (idx
> array_count(array
) / 2)
366 remove_tail(array
, idx
);
372 idx
= array_count(array
) - 1;
374 remove_head(array
, idx
);
376 if (array
->head
+ array
->tail
> ARRAY_MAX_UNUSED
)
378 array_compress(array
);
386 /** comparison function */
387 int (*cmp
)(const void*,const void*,void*);
388 /** optional user arg */
392 #ifdef HAVE_QSORT_R_GNU
393 static int compare_elements(const void *a
, const void *b
, void *arg
)
394 #elif HAVE_QSORT_R_BSD
395 static int compare_elements(void *arg
, const void *a
, const void *b
)
396 #else /* !HAVE_QSORT_R */
397 static int compare_elements(const void *a
, const void *b
)
401 sort_data_t
*data
= (sort_data_t
*)arg
;
403 sort_data_t
*data
= sort_data
->get(sort_data
);
406 if (data
->array
->esize
)
408 return data
->cmp(a
, b
, data
->arg
);
410 return data
->cmp(*(void**)a
, *(void**)b
, data
->arg
);
413 void array_sort(array_t
*array
, int (*cmp
)(const void*,const void*,void*),
425 start
= array
->data
+ get_size(array
, array
->head
);
427 #ifdef HAVE_QSORT_R_GNU
428 qsort_r(start
, array
->count
, get_size(array
, 1), compare_elements
,
430 #elif HAVE_QSORT_R_BSD
431 qsort_r(start
, array
->count
, get_size(array
, 1), &data
,
433 #else /* !HAVE_QSORT_R */
434 sort_data
->set(sort_data
, &data
);
435 qsort(start
, array
->count
, get_size(array
, 1), compare_elements
);
445 /** comparison function */
446 int (*cmp
)(const void*,const void*);
449 static int search_elements(const void *a
, const void *b
)
451 bsearch_data_t
*data
= (bsearch_data_t
*)a
;
453 if (data
->array
->esize
)
455 return data
->cmp(data
->key
, b
);
457 return data
->cmp(data
->key
, *(void**)b
);
460 int array_bsearch(array_t
*array
, const void *key
,
461 int (*cmp
)(const void*,const void*), void *out
)
467 bsearch_data_t data
= {
474 start
= array
->data
+ get_size(array
, array
->head
);
476 item
= bsearch(&data
, start
, array
->count
, get_size(array
, 1),
482 memcpy(out
, item
, get_size(array
, 1));
484 idx
= (item
- start
) / get_size(array
, 1);
490 void array_invoke(array_t
*array
, array_callback_t cb
, void *user
)
497 for (i
= array
->head
; i
< array
->count
+ array
->head
; i
++)
499 obj
= array
->data
+ get_size(array
, i
);
502 /* dereference if we store store pointers */
505 cb(obj
, i
- array
->head
, user
);
510 void array_invoke_offset(array_t
*array
, size_t offset
)
514 void (*method
)(void *data
);
518 for (i
= array
->head
; i
< array
->count
+ array
->head
; i
++)
520 obj
= array
->data
+ get_size(array
, i
);
523 /* dereference if we store store pointers */
526 method
= *(void**)(obj
+ offset
);
532 void array_destroy(array_t
*array
)
541 void array_destroy_function(array_t
*array
, array_callback_t cb
, void *user
)
543 array_invoke(array
, cb
, user
);
544 array_destroy(array
);
547 void array_destroy_offset(array_t
*array
, size_t offset
)
549 array_invoke_offset(array
, offset
);
550 array_destroy(array
);
556 sort_data
= thread_value_create(NULL
);
563 sort_data
->destroy(sort_data
);