]>
git.ipfire.org Git - people/ms/strongswan.git/blob - src/libstrongswan/collections/array.c
2 * Copyright (C) 2013 Martin Willi
3 * Copyright (C) 2013 revosec AG
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 * Data is an allocated block, with potentially unused head and tail:
21 * "esize" each (or sizeof(void*) if esize = 0)
22 * /-\ /-\ /-\ /-\ /-\ /-\
24 * +---------------+-------------------------------+---------------+
25 * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l |
26 * +---------------+-------------------------------+---------------+
28 * \--------------/ \-----------------------------/ \-------------/
30 * "head" "count" "tail"
34 /** number of elements currently in array (not counting head/tail) */
36 /** size of each element, 0 for a pointer based array */
38 /** allocated but unused elements at array front */
40 /** allocated but unused elements at array end */
46 /** maximum number of unused head/tail elements before cleanup */
47 #define ARRAY_MAX_UNUSED 32
50 * Get the actual size of a number of elements
52 static size_t get_size(array_t
*array
, int num
)
56 return array
->esize
* num
;
58 return sizeof(void*) * num
;
62 * Increase allocated but unused tail room to at least "room"
64 static void make_tail_room(array_t
*array
, u_int8_t room
)
66 if (array
->tail
< room
)
68 array
->data
= realloc(array
->data
,
69 get_size(array
, array
->count
+ array
->head
+ room
));
75 * Increase allocated but unused head room to at least "room"
77 static void make_head_room(array_t
*array
, u_int8_t room
)
79 if (array
->head
< room
)
81 u_int8_t increase
= room
- array
->head
;
83 array
->data
= realloc(array
->data
,
84 get_size(array
, array
->count
+ array
->tail
+ room
));
85 memmove(array
->data
+ get_size(array
, increase
), array
->data
,
86 get_size(array
, array
->count
+ array
->tail
+ array
->head
));
92 * Make space for an item at index using tail room
94 static void insert_tail(array_t
*array
, int idx
)
96 make_tail_room(array
, 1);
97 /* move up all elements after idx by one */
98 memmove(array
->data
+ get_size(array
, array
->head
+ idx
+ 1),
99 array
->data
+ get_size(array
, array
->head
+ idx
),
100 get_size(array
, array
->count
- idx
));
107 * Make space for an item at index using head room
109 static void insert_head(array_t
*array
, int idx
)
111 make_head_room(array
, 1);
112 /* move down all elements before idx by one */
113 memmove(array
->data
+ get_size(array
, array
->head
- 1),
114 array
->data
+ get_size(array
, array
->head
),
115 get_size(array
, idx
));
122 * Remove an item, increase tail
124 static void remove_tail(array_t
*array
, int idx
)
126 /* move all items after idx one down */
127 memmove(array
->data
+ get_size(array
, idx
+ array
->head
),
128 array
->data
+ get_size(array
, idx
+ array
->head
+ 1),
129 get_size(array
, array
->count
- idx
));
135 * Remove an item, increase head
137 static void remove_head(array_t
*array
, int idx
)
139 /* move all items before idx one up */
140 memmove(array
->data
+ get_size(array
, array
->head
+ 1),
141 array
->data
+ get_size(array
, array
->head
), get_size(array
, idx
));
146 array_t
*array_create(u_int esize
, u_int8_t reserve
)
156 array
->data
= malloc(array
->tail
* array
->esize
);
161 int array_count(array_t
*array
)
170 void array_compress(array_t
*array
)
179 memmove(array
->data
, array
->data
+ get_size(array
, array
->head
),
180 get_size(array
, array
->count
+ array
->tail
));
186 array
->data
= realloc(array
->data
, get_size(array
, array
->count
));
193 /** public enumerator interface */
195 /** enumerated array */
197 /** current index +1, initialized at 0 */
199 } array_enumerator_t
;
201 METHOD(enumerator_t
, enumerate
, bool,
202 array_enumerator_t
*this, void **out
)
206 if (this->idx
>= this->array
->count
)
211 pos
= this->array
->data
+
212 get_size(this->array
, this->idx
+ this->array
->head
);
213 if (this->array
->esize
)
215 /* for element based arrays we return a pointer to the element */
220 /* for pointer based arrays we return the pointer directly */
227 enumerator_t
* array_create_enumerator(array_t
*array
)
229 array_enumerator_t
*enumerator
;
233 return enumerator_create_empty();
238 .enumerate
= (void*)_enumerate
,
239 .destroy
= (void*)free
,
243 return &enumerator
->public;
246 void array_remove_at(array_t
*array
, enumerator_t
*public)
248 array_enumerator_t
*enumerator
= (array_enumerator_t
*)public;
252 array_remove(array
, --enumerator
->idx
, NULL
);
256 void array_insert_create(array_t
**array
, int idx
, void *ptr
)
260 *array
= array_create(0, 0);
262 array_insert(*array
, idx
, ptr
);
265 void array_insert_enumerator(array_t
*array
, int idx
, enumerator_t
*enumerator
)
269 while (enumerator
->enumerate(enumerator
, &ptr
))
271 array_insert(array
, idx
, ptr
);
273 enumerator
->destroy(enumerator
);
276 void array_insert(array_t
*array
, int idx
, void *data
)
278 if (idx
< 0 || idx
<= array_count(array
))
284 idx
= array_count(array
);
287 if (array
->head
&& !array
->tail
)
289 insert_head(array
, idx
);
291 else if (array
->tail
&& !array
->head
)
293 insert_tail(array
, idx
);
295 else if (idx
> array_count(array
) / 2)
297 insert_tail(array
, idx
);
301 insert_head(array
, idx
);
304 pos
= array
->data
+ get_size(array
, array
->head
+ idx
);
307 memcpy(pos
, data
, get_size(array
, 1));
311 /* pointer based array, copy pointer value */
317 bool array_remove(array_t
*array
, int idx
, void *data
)
323 if (idx
>= 0 && idx
>= array_count(array
))
329 if (array_count(array
) == 0)
333 idx
= array_count(array
) - 1;
337 memcpy(data
, array
->data
+ get_size(array
, array
->head
+ idx
),
340 if (idx
> array_count(array
) / 2)
342 remove_tail(array
, idx
);
346 remove_head(array
, idx
);
348 if (array
->head
+ array
->tail
> ARRAY_MAX_UNUSED
)
350 array_compress(array
);
355 void array_invoke(array_t
*array
, array_callback_t cb
, void *user
)
362 for (i
= array
->head
; i
< array
->count
+ array
->head
; i
++)
364 obj
= array
->data
+ get_size(array
, i
);
367 /* dereference if we store store pointers */
370 cb(obj
, i
- array
->head
, user
);
375 void array_invoke_offset(array_t
*array
, size_t offset
)
379 void (*method
)(void *data
);
383 for (i
= array
->head
; i
< array
->count
+ array
->head
; i
++)
385 obj
= array
->data
+ get_size(array
, i
);
388 /* dereference if we store store pointers */
391 method
= *(void**)(obj
+ offset
);
397 void array_destroy(array_t
*array
)
406 void array_destroy_function(array_t
*array
, array_callback_t cb
, void *user
)
408 array_invoke(array
, cb
, user
);
409 array_destroy(array
);
412 void array_destroy_offset(array_t
*array
, size_t offset
)
414 array_invoke_offset(array
, offset
);
415 array_destroy(array
);