diff options
author | Yves-Alexis Perez <corsac@debian.org> | 2014-03-11 20:48:48 +0100 |
---|---|---|
committer | Yves-Alexis Perez <corsac@debian.org> | 2014-03-11 20:48:48 +0100 |
commit | b96bc2fcc06cc6c1762dc193a5117ebcb956e220 (patch) | |
tree | 4915ecb47936524433c6578526cc5d25a0d2913c /src/libstrongswan/collections/array.c | |
parent | 4a7efb286aaf809849d56841b59c2d733e8dff49 (diff) | |
parent | 15fb7904f4431a6e7c305fd08732458f7f885e7e (diff) | |
download | vyos-strongswan-b96bc2fcc06cc6c1762dc193a5117ebcb956e220.tar.gz vyos-strongswan-b96bc2fcc06cc6c1762dc193a5117ebcb956e220.zip |
Merge tag 'upstream/5.1.2'
Upstream version 5.1.2
Diffstat (limited to 'src/libstrongswan/collections/array.c')
-rw-r--r-- | src/libstrongswan/collections/array.c | 151 |
1 files changed, 150 insertions, 1 deletions
diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c index 387e2a57d..314e8e916 100644 --- a/src/libstrongswan/collections/array.c +++ b/src/libstrongswan/collections/array.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2014 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2013 Martin Willi * Copyright (C) 2013 revosec AG * @@ -13,8 +16,15 @@ * for more details. */ +#define _GNU_SOURCE /* for qsort_r() */ +#include <stdlib.h> + #include "array.h" +#ifndef HAVE_QSORT_R +#include <threading/thread_value.h> +#endif + /** * Data is an allocated block, with potentially unused head and tail: * @@ -43,6 +53,11 @@ struct array_t { void *data; }; +#ifndef HAVE_QSORT_R + /* store data to replicate qsort_r in thread local storage */ + static thread_value_t *sort_data; +#endif + /** maximum number of unused head/tail elements before cleanup */ #define ARRAY_MAX_UNUSED 32 @@ -314,7 +329,7 @@ void array_insert(array_t *array, int idx, void *data) } } -bool array_remove(array_t *array, int idx, void *data) +bool array_get(array_t *array, int idx, void *data) { if (!array) { @@ -337,12 +352,25 @@ bool array_remove(array_t *array, int idx, void *data) memcpy(data, array->data + get_size(array, array->head + idx), get_size(array, 1)); } + return TRUE; +} + +bool array_remove(array_t *array, int idx, void *data) +{ + if (!array_get(array, idx, data)) + { + return FALSE; + } if (idx > array_count(array) / 2) { remove_tail(array, idx); } else { + if (idx < 0) + { + idx = array_count(array) - 1; + } remove_head(array, idx); } if (array->head + array->tail > ARRAY_MAX_UNUSED) @@ -352,6 +380,113 @@ bool array_remove(array_t *array, int idx, void *data) return TRUE; } +typedef struct { + /** the array */ + array_t *array; + /** comparison function */ + int (*cmp)(const void*,const void*,void*); + /** optional user arg */ + void *arg; +} sort_data_t; + +#ifdef HAVE_QSORT_R_GNU +static int compare_elements(const void *a, const void *b, void *arg) +#elif defined(HAVE_QSORT_R_BSD) +static int compare_elements(void *arg, const void *a, const void *b) +#else /* !HAVE_QSORT_R */ +static int compare_elements(const void *a, const void *b) +#endif +{ +#ifdef HAVE_QSORT_R + sort_data_t *data = (sort_data_t*)arg; +#else + sort_data_t *data = sort_data->get(sort_data); +#endif + + if (data->array->esize) + { + return data->cmp(a, b, data->arg); + } + return data->cmp(*(void**)a, *(void**)b, data->arg); +} + +void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*), + void *user) +{ + if (array) + { + sort_data_t data = { + .array = array, + .cmp = cmp, + .arg = user, + }; + void *start; + + start = array->data + get_size(array, array->head); + +#ifdef HAVE_QSORT_R_GNU + qsort_r(start, array->count, get_size(array, 1), compare_elements, + &data); +#elif defined(HAVE_QSORT_R_BSD) + qsort_r(start, array->count, get_size(array, 1), &data, + compare_elements); +#else /* !HAVE_QSORT_R */ + sort_data->set(sort_data, &data); + qsort(start, array->count, get_size(array, 1), compare_elements); +#endif + } +} + +typedef struct { + /** the array */ + array_t *array; + /** the key */ + const void *key; + /** comparison function */ + int (*cmp)(const void*,const void*); +} bsearch_data_t; + +static int search_elements(const void *a, const void *b) +{ + bsearch_data_t *data = (bsearch_data_t*)a; + + if (data->array->esize) + { + return data->cmp(data->key, b); + } + return data->cmp(data->key, *(void**)b); +} + +int array_bsearch(array_t *array, const void *key, + int (*cmp)(const void*,const void*), void *out) +{ + int idx = -1; + + if (array) + { + bsearch_data_t data = { + .array = array, + .key = key, + .cmp = cmp, + }; + void *start, *item; + + start = array->data + get_size(array, array->head); + + item = bsearch(&data, start, array->count, get_size(array, 1), + search_elements); + if (item) + { + if (out) + { + memcpy(out, item, get_size(array, 1)); + } + idx = (item - start) / get_size(array, 1); + } + } + return idx; +} + void array_invoke(array_t *array, array_callback_t cb, void *user) { if (array) @@ -414,3 +549,17 @@ void array_destroy_offset(array_t *array, size_t offset) array_invoke_offset(array, offset); array_destroy(array); } + +void arrays_init() +{ +#ifndef HAVE_QSORT_R + sort_data = thread_value_create(NULL); +#endif +} + +void arrays_deinit() +{ +#ifndef HAVE_QSORT_R + sort_data->destroy(sort_data); +#endif +} |