diff options
Diffstat (limited to 'src/libstrongswan/collections')
-rw-r--r-- | src/libstrongswan/collections/array.c | 416 | ||||
-rw-r--r-- | src/libstrongswan/collections/array.h | 195 | ||||
-rw-r--r-- | src/libstrongswan/collections/enumerator.c | 14 | ||||
-rw-r--r-- | src/libstrongswan/collections/hashtable.c | 36 | ||||
-rw-r--r-- | src/libstrongswan/collections/hashtable.h | 35 | ||||
-rw-r--r-- | src/libstrongswan/collections/linked_list.c | 70 | ||||
-rw-r--r-- | src/libstrongswan/collections/linked_list.h | 49 |
7 files changed, 687 insertions, 128 deletions
diff --git a/src/libstrongswan/collections/array.c b/src/libstrongswan/collections/array.c new file mode 100644 index 000000000..387e2a57d --- /dev/null +++ b/src/libstrongswan/collections/array.c @@ -0,0 +1,416 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +#include "array.h" + +/** + * Data is an allocated block, with potentially unused head and tail: + * + * "esize" each (or sizeof(void*) if esize = 0) + * /-\ /-\ /-\ /-\ /-\ /-\ + * + * +---------------+-------------------------------+---------------+ + * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l | + * +---------------+-------------------------------+---------------+ + * + * \--------------/ \-----------------------------/ \-------------/ + * unused used unused + * "head" "count" "tail" + * + */ +struct array_t { + /** number of elements currently in array (not counting head/tail) */ + u_int32_t count; + /** size of each element, 0 for a pointer based array */ + u_int16_t esize; + /** allocated but unused elements at array front */ + u_int8_t head; + /** allocated but unused elements at array end */ + u_int8_t tail; + /** array elements */ + void *data; +}; + +/** maximum number of unused head/tail elements before cleanup */ +#define ARRAY_MAX_UNUSED 32 + +/** + * Get the actual size of a number of elements + */ +static size_t get_size(array_t *array, u_int32_t num) +{ + if (array->esize) + { + return array->esize * num; + } + return sizeof(void*) * num; +} + +/** + * Increase allocated but unused tail room to at least "room" + */ +static void make_tail_room(array_t *array, u_int8_t room) +{ + if (array->tail < room) + { + array->data = realloc(array->data, + get_size(array, array->count + array->head + room)); + array->tail = room; + } +} + +/** + * Increase allocated but unused head room to at least "room" + */ +static void make_head_room(array_t *array, u_int8_t room) +{ + if (array->head < room) + { + u_int8_t increase = room - array->head; + + array->data = realloc(array->data, + get_size(array, array->count + array->tail + room)); + memmove(array->data + get_size(array, increase), array->data, + get_size(array, array->count + array->tail + array->head)); + array->head = room; + } +} + +/** + * Make space for an item at index using tail room + */ +static void insert_tail(array_t *array, int idx) +{ + make_tail_room(array, 1); + /* move up all elements after idx by one */ + memmove(array->data + get_size(array, array->head + idx + 1), + array->data + get_size(array, array->head + idx), + get_size(array, array->count - idx)); + + array->tail--; + array->count++; +} + +/** + * Make space for an item at index using head room + */ +static void insert_head(array_t *array, int idx) +{ + make_head_room(array, 1); + /* move down all elements before idx by one */ + memmove(array->data + get_size(array, array->head - 1), + array->data + get_size(array, array->head), + get_size(array, idx)); + + array->head--; + array->count++; +} + +/** + * Remove an item, increase tail + */ +static void remove_tail(array_t *array, int idx) +{ + /* move all items after idx one down */ + memmove(array->data + get_size(array, idx + array->head), + array->data + get_size(array, idx + array->head + 1), + get_size(array, array->count - idx)); + array->count--; + array->tail++; +} + +/** + * Remove an item, increase head + */ +static void remove_head(array_t *array, int idx) +{ + /* move all items before idx one up */ + memmove(array->data + get_size(array, array->head + 1), + array->data + get_size(array, array->head), get_size(array, idx)); + array->count--; + array->head++; +} + +array_t *array_create(u_int esize, u_int8_t reserve) +{ + array_t *array; + + INIT(array, + .esize = esize, + .tail = reserve, + ); + if (array->tail) + { + array->data = malloc(array->tail * array->esize); + } + return array; +} + +int array_count(array_t *array) +{ + if (array) + { + return array->count; + } + return 0; +} + +void array_compress(array_t *array) +{ + if (array) + { + u_int32_t tail; + + tail = array->tail; + if (array->head) + { + memmove(array->data, array->data + get_size(array, array->head), + get_size(array, array->count + array->tail)); + tail += array->head; + array->head = 0; + } + if (tail) + { + array->data = realloc(array->data, get_size(array, array->count)); + array->tail = 0; + } + } +} + +typedef struct { + /** public enumerator interface */ + enumerator_t public; + /** enumerated array */ + array_t *array; + /** current index +1, initialized at 0 */ + int idx; +} array_enumerator_t; + +METHOD(enumerator_t, enumerate, bool, + array_enumerator_t *this, void **out) +{ + void *pos; + + if (this->idx >= this->array->count) + { + return FALSE; + } + + pos = this->array->data + + get_size(this->array, this->idx + this->array->head); + if (this->array->esize) + { + /* for element based arrays we return a pointer to the element */ + *out = pos; + } + else + { + /* for pointer based arrays we return the pointer directly */ + *out = *(void**)pos; + } + this->idx++; + return TRUE; +} + +enumerator_t* array_create_enumerator(array_t *array) +{ + array_enumerator_t *enumerator; + + if (!array) + { + return enumerator_create_empty(); + } + + INIT(enumerator, + .public = { + .enumerate = (void*)_enumerate, + .destroy = (void*)free, + }, + .array = array, + ); + return &enumerator->public; +} + +void array_remove_at(array_t *array, enumerator_t *public) +{ + array_enumerator_t *enumerator = (array_enumerator_t*)public; + + if (enumerator->idx) + { + array_remove(array, --enumerator->idx, NULL); + } +} + +void array_insert_create(array_t **array, int idx, void *ptr) +{ + if (*array == NULL) + { + *array = array_create(0, 0); + } + array_insert(*array, idx, ptr); +} + +void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator) +{ + void *ptr; + + while (enumerator->enumerate(enumerator, &ptr)) + { + array_insert(array, idx, ptr); + } + enumerator->destroy(enumerator); +} + +void array_insert(array_t *array, int idx, void *data) +{ + if (idx < 0 || idx <= array_count(array)) + { + void *pos; + + if (idx < 0) + { + idx = array_count(array); + } + + if (array->head && !array->tail) + { + insert_head(array, idx); + } + else if (array->tail && !array->head) + { + insert_tail(array, idx); + } + else if (idx > array_count(array) / 2) + { + insert_tail(array, idx); + } + else + { + insert_head(array, idx); + } + + pos = array->data + get_size(array, array->head + idx); + if (array->esize) + { + memcpy(pos, data, get_size(array, 1)); + } + else + { + /* pointer based array, copy pointer value */ + *(void**)pos = data; + } + } +} + +bool array_remove(array_t *array, int idx, void *data) +{ + if (!array) + { + return FALSE; + } + if (idx >= 0 && idx >= array_count(array)) + { + return FALSE; + } + if (idx < 0) + { + if (array_count(array) == 0) + { + return FALSE; + } + idx = array_count(array) - 1; + } + if (data) + { + memcpy(data, array->data + get_size(array, array->head + idx), + get_size(array, 1)); + } + if (idx > array_count(array) / 2) + { + remove_tail(array, idx); + } + else + { + remove_head(array, idx); + } + if (array->head + array->tail > ARRAY_MAX_UNUSED) + { + array_compress(array); + } + return TRUE; +} + +void array_invoke(array_t *array, array_callback_t cb, void *user) +{ + if (array) + { + void *obj; + int i; + + for (i = array->head; i < array->count + array->head; i++) + { + obj = array->data + get_size(array, i); + if (!array->esize) + { + /* dereference if we store store pointers */ + obj = *(void**)obj; + } + cb(obj, i - array->head, user); + } + } +} + +void array_invoke_offset(array_t *array, size_t offset) +{ + if (array) + { + void (*method)(void *data); + void *obj; + int i; + + for (i = array->head; i < array->count + array->head; i++) + { + obj = array->data + get_size(array, i); + if (!array->esize) + { + /* dereference if we store store pointers */ + obj = *(void**)obj; + } + method = *(void**)(obj + offset); + method(obj); + } + } +} + +void array_destroy(array_t *array) +{ + if (array) + { + free(array->data); + free(array); + } +} + +void array_destroy_function(array_t *array, array_callback_t cb, void *user) +{ + array_invoke(array, cb, user); + array_destroy(array); +} + +void array_destroy_offset(array_t *array, size_t offset) +{ + array_invoke_offset(array, offset); + array_destroy(array); +} diff --git a/src/libstrongswan/collections/array.h b/src/libstrongswan/collections/array.h new file mode 100644 index 000000000..0dc7b2250 --- /dev/null +++ b/src/libstrongswan/collections/array.h @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2013 Martin Willi + * Copyright (C) 2013 revosec AG + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + */ + +/** + * @defgroup array array + * @{ @ingroup collections + */ + +#ifndef ARRAY_H_ +#define ARRAY_H_ + +#include <collections/enumerator.h> + +/** + * Variable sized array with fixed size elements. + * + * An array is a primitive object with associated functions to avoid the + * overhead of an object with methods. It is efficient in memory usage, but + * less efficient than a linked list in manipulating elements. + */ +typedef struct array_t array_t; + +typedef enum array_idx_t array_idx_t; + +/** + * Special array index values for insert/remove. + */ +enum array_idx_t { + ARRAY_HEAD = 0, + ARRAY_TAIL = -1, +}; + +/** + * Callback function invoked for each array element. + * + * Data is a pointer to the array element. If this is a pointer based array, + * (esize is zero), data is the pointer itself. + * + * @param data pointer to array data, or the pointer itself + * @param idx array index + * @param user user data passed with callback + */ +typedef void (*array_callback_t)(void *data, int idx, void *user); + +/** + * Create a array instance. + * + * Elements get tight packed to each other. If any alignment is required, pass + * appropriate padding to each element. The reserved space does not affect + * array_count(), but just preallocates buffer space. + * + * @param esize element size for this array, use 0 for a pointer array + * @param reserve number of items to allocate space for + * @return array instance + */ +array_t *array_create(u_int esize, u_int8_t reserve); + +/** + * Get the number of elements currently in the array. + * + * @return number of elements + */ +int array_count(array_t *array); + +/** + * Compress an array, remove unused head/tail space. + * + * @param array array to compress, or NULL + */ +void array_compress(array_t *array); + +/** + * Create an enumerator over an array. + * + * The enumerater enumerates directly over the array element (pass a pointer to + * element types), unless the array is pointer based. If zero is passed as + * element size during construction, the enumerator enumerates over the + * deferenced pointer values. + * + * @param array array to create enumerator for, or NULL + * @return enumerator, over elements or pointers + */ +enumerator_t* array_create_enumerator(array_t *array); + +/** + * Remove an element at enumerator position. + * + * @param array array to remove element in + * @param enumerator enumerator position, from array_create_enumerator() + */ +void array_remove_at(array_t *array, enumerator_t *enumerator); + +/** + * Insert an element to an array. + * + * If the array is pointer based (esize = 0), the pointer itself is appended. + * Otherwise the element gets copied from the pointer. + * The idx must be either within array_count() or one above to append the item. + * Passing -1 has the same effect as passing array_count(), i.e. appends the + * item. It is always valid to pass idx 0 to prepend the item. + * + * @param array array to append element to + * @param idx index to insert item at + * @param data pointer to array element to copy + */ +void array_insert(array_t *array, int idx, void *data); + +/** + * Create an pointer based array if it does not exist, insert pointer. + * + * This is a convenience function for insert a pointer and implicitly + * create a pointer based array if array is NULL. Array is set the the newly + * created array, if any. + * + * @param array pointer to array reference, potentially NULL + * @param idx index to insert item at + * @param ptr pointer to append + */ +void array_insert_create(array_t **array, int idx, void *ptr); + +/** + * Insert all items from an enumerator to an array. + * + * @param array array to add items to + * @param idx index to insert each item with + * @param enumerator enumerator over void*, gets destroyed + */ +void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator); + +/** + * Remove an element from the array. + * + * If data is given, the element is copied to that position. + * + * @param array array to remove element from, or NULL + * @param idx index of the item to remove + * @param data data to copy element to, or NULL + * @return TRUE if idx existed and item removed + */ +bool array_remove(array_t *array, int idx, void *data); + +/** + * Invoke a callback for all array members. + * + * @param array array to traverse, or NULL + * @param cb callback function to invoke each element with + * @param user user data to pass to callback + */ +void array_invoke(array_t *array, array_callback_t cb, void *user); + +/** + * Invoke a method of each element defined with offset. + * + * @param array array to traverse, or NULL + * @param offset offset of element method, use offsetof() + */ +void array_invoke_offset(array_t *array, size_t offset); + +/** + * Destroy an array. + * + * @param array array to destroy, or NULL + */ +void array_destroy(array_t *array); + +/** + * Destroy an array, call a function to clean up all elements. + * + * @param array array to destroy, or NULL + * @param cb callback function to free element data + * @param user user data to pass to callback + */ +void array_destroy_function(array_t *array, array_callback_t cb, void *user); + +/** + * Destroy an array, call element method defined with offset. + * + * @param array array to destroy, or NULL + * @param offset offset of element method, use offsetof() + */ +void array_destroy_offset(array_t *array, size_t offset); + +#endif /** ARRAY_H_ @}*/ diff --git a/src/libstrongswan/collections/enumerator.c b/src/libstrongswan/collections/enumerator.c index f80cdabd2..8049ac016 100644 --- a/src/libstrongswan/collections/enumerator.c +++ b/src/libstrongswan/collections/enumerator.c @@ -264,7 +264,7 @@ static bool enumerate_token_enum(token_enum_t *this, char **token) } } - /* trim trailing characters/separators */ + /* trim trailing characters */ pos--; while (pos >= *token) { @@ -278,17 +278,7 @@ static bool enumerate_token_enum(token_enum_t *this, char **token) } trim++; } - sep = this->sep; - while (*sep) - { - if (*sep == *pos) - { - *(pos--) = '\0'; - break; - } - sep++; - } - if (!*trim && !*sep) + if (!*trim) { break; } diff --git a/src/libstrongswan/collections/hashtable.c b/src/libstrongswan/collections/hashtable.c index d181d8ec8..1003aa0fa 100644 --- a/src/libstrongswan/collections/hashtable.c +++ b/src/libstrongswan/collections/hashtable.c @@ -16,6 +16,8 @@ #include "hashtable.h" +#include <utils/chunk.h> + /** The maximum capacity of the hash table (MUST be a power of 2) */ #define MAX_CAPACITY (1 << 30) @@ -146,9 +148,40 @@ struct private_enumerator_t { * previous pair (used by remove_at) */ pair_t *prev; - }; +/* + * See header. + */ +u_int hashtable_hash_ptr(void *key) +{ + return chunk_hash(chunk_from_thing(key)); +} + +/* + * See header. + */ +u_int hashtable_hash_str(void *key) +{ + return chunk_hash(chunk_from_str((char*)key)); +} + +/* + * See header. + */ +bool hashtable_equals_ptr(void *key, void *other_key) +{ + return key == other_key; +} + +/* + * See header. + */ +bool hashtable_equals_str(void *key, void *other_key) +{ + return streq(key, other_key); +} + /** * This function returns the next-highest power of two for the given number. * The algorithm works by setting all bits on the right-hand side of the most @@ -441,4 +474,3 @@ hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals, return &this->public; } - diff --git a/src/libstrongswan/collections/hashtable.h b/src/libstrongswan/collections/hashtable.h index e38850ded..520a86c90 100644 --- a/src/libstrongswan/collections/hashtable.h +++ b/src/libstrongswan/collections/hashtable.h @@ -34,6 +34,22 @@ typedef struct hashtable_t hashtable_t; typedef u_int (*hashtable_hash_t)(void *key); /** + * Hashtable hash function calculation the hash solely based on the key pointer. + * + * @param key key to hash + * @return hash of key + */ +u_int hashtable_hash_ptr(void *key); + +/** + * Hashtable hash function calculation the hash for char* keys. + * + * @param key key to hash, a char* + * @return hash of key + */ +u_int hashtable_hash_str(void *key); + +/** * Prototype for a function that compares the two keys for equality. * * @param key first key (the one we are looking for) @@ -43,6 +59,24 @@ typedef u_int (*hashtable_hash_t)(void *key); typedef bool (*hashtable_equals_t)(void *key, void *other_key); /** + * Hashtable equals function comparing pointers. + * + * @param key key to compare + * @param other_key other key to compare + * @return TRUE if key == other_key + */ +bool hashtable_equals_ptr(void *key, void *other_key); + +/** + * Hashtable equals function comparing char* keys. + * + * @param key key to compare + * @param other_key other key to compare + * @return TRUE if streq(key, other_key) + */ +bool hashtable_equals_str(void *key, void *other_key); + +/** * Class implementing a hash table. * * General purpose hash table. This hash table is not synchronized. @@ -121,7 +155,6 @@ struct hashtable_t { * Destroys a hash table object. */ void (*destroy) (hashtable_t *this); - }; /** diff --git a/src/libstrongswan/collections/linked_list.c b/src/libstrongswan/collections/linked_list.c index 1ff80999b..a176e5a54 100644 --- a/src/libstrongswan/collections/linked_list.c +++ b/src/libstrongswan/collections/linked_list.c @@ -138,7 +138,10 @@ METHOD(enumerator_t, enumerate, bool, this->finished = TRUE; return FALSE; } - *item = this->current->value; + if (item) + { + *item = this->current->value; + } return TRUE; } @@ -165,16 +168,6 @@ METHOD(linked_list_t, reset_enumerator, void, enumerator->finished = FALSE; } -METHOD(linked_list_t, has_more, bool, - private_linked_list_t *this, private_enumerator_t *enumerator) -{ - if (enumerator->current) - { - return enumerator->current->next != NULL; - } - return !enumerator->finished && this->first != NULL; -} - METHOD(linked_list_t, get_count, int, private_linked_list_t *this) { @@ -316,20 +309,6 @@ METHOD(linked_list_t, insert_before, void, this->count++; } -METHOD(linked_list_t, replace, void*, - private_linked_list_t *this, private_enumerator_t *enumerator, - void *item) -{ - void *old = NULL; - - if (enumerator->current) - { - old = enumerator->current->value; - enumerator->current->value = item; - } - return old; -} - METHOD(linked_list_t, get_last, status_t, private_linked_list_t *this, void **item) { @@ -409,28 +388,6 @@ METHOD(linked_list_t, find_first, status_t, return NOT_FOUND; } -METHOD(linked_list_t, find_last, status_t, - private_linked_list_t *this, linked_list_match_t match, - void **item, void *d1, void *d2, void *d3, void *d4, void *d5) -{ - element_t *current = this->last; - - while (current) - { - if ((match && match(current->value, d1, d2, d3, d4, d5)) || - (!match && item && current->value == *item)) - { - if (item != NULL) - { - *item = current->value; - } - return SUCCESS; - } - current = current->previous; - } - return NOT_FOUND; -} - METHOD(linked_list_t, invoke_offset, void, private_linked_list_t *this, size_t offset, void *d1, void *d2, void *d3, void *d4, void *d5) @@ -476,21 +433,6 @@ METHOD(linked_list_t, clone_offset, linked_list_t*, return clone; } -METHOD(linked_list_t, clone_function, linked_list_t*, - private_linked_list_t *this, void* (*fn)(void*)) -{ - element_t *current = this->first; - linked_list_t *clone; - - clone = linked_list_create(); - while (current) - { - clone->insert_last(clone, fn(current->value)); - current = current->next; - } - return clone; -} - METHOD(linked_list_t, destroy, void, private_linked_list_t *this) { @@ -548,15 +490,12 @@ linked_list_t *linked_list_create() .get_count = _get_count, .create_enumerator = _create_enumerator, .reset_enumerator = (void*)_reset_enumerator, - .has_more = (void*)_has_more, .get_first = _get_first, .get_last = _get_last, .find_first = (void*)_find_first, - .find_last = (void*)_find_last, .insert_first = _insert_first, .insert_last = _insert_last, .insert_before = (void*)_insert_before, - .replace = (void*)_replace, .remove_first = _remove_first, .remove_last = _remove_last, .remove = _remove_, @@ -564,7 +503,6 @@ linked_list_t *linked_list_create() .invoke_offset = (void*)_invoke_offset, .invoke_function = (void*)_invoke_function, .clone_offset = _clone_offset, - .clone_function = _clone_function, .destroy = _destroy, .destroy_offset = _destroy_offset, .destroy_function = _destroy_function, diff --git a/src/libstrongswan/collections/linked_list.h b/src/libstrongswan/collections/linked_list.h index da539a231..abc33c12a 100644 --- a/src/libstrongswan/collections/linked_list.h +++ b/src/libstrongswan/collections/linked_list.h @@ -78,14 +78,6 @@ struct linked_list_t { void (*reset_enumerator)(linked_list_t *this, enumerator_t *enumerator); /** - * Checks if there are more elements following after the enumerator's - * current position. - * - * @param enumerator enumerator to check - */ - bool (*has_more)(linked_list_t *this, enumerator_t *enumerator); - - /** * Inserts a new item at the beginning of the list. * * @param item item value to insert in list @@ -117,16 +109,6 @@ struct linked_list_t { void *item); /** - * Replaces the item the enumerator currently points to with the given item. - * - * @param enumerator enumerator with position - * @param item item value to replace current item with - * @return current item or NULL if the enumerator is at an - * invalid position - */ - void *(*replace)(linked_list_t *this, enumerator_t *enumerator, void *item); - - /** * Remove an item from the list where the enumerator points to. * * @param enumerator enumerator with position @@ -180,7 +162,8 @@ struct linked_list_t { */ status_t (*get_last) (linked_list_t *this, void **item); - /** Find the first matching element in the list. + /** + * Find the first matching element in the list. * * The first object passed to the match function is the current list item, * followed by the user supplied data. @@ -200,26 +183,6 @@ struct linked_list_t { status_t (*find_first) (linked_list_t *this, linked_list_match_t match, void **item, ...); - /** Find the last matching element in the list. - * - * The first object passed to the match function is the current list item, - * followed by the user supplied data. - * If the supplied function returns TRUE this function returns SUCCESS, and - * the current object is returned in the third parameter, otherwise, - * the next item is checked. - * - * If match is NULL, *item and the current object are compared. - * - * @warning Only use pointers as user supplied data. - * - * @param match comparison function to call on each object, or NULL - * @param item the list item, if found - * @param ... user data to supply to match function (limited to 5 arguments) - * @return SUCCESS if found, NOT_FOUND otherwise - */ - status_t (*find_last) (linked_list_t *this, linked_list_match_t match, - void **item, ...); - /** * Invoke a method on all of the contained objects. * @@ -255,14 +218,6 @@ struct linked_list_t { linked_list_t *(*clone_offset) (linked_list_t *this, size_t offset); /** - * Clones a list and its objects using a given function. - * - * @param function function that clones an object - * @return cloned list - */ - linked_list_t *(*clone_function) (linked_list_t *this, void*(*)(void*)); - - /** * Destroys a linked_list object. */ void (*destroy) (linked_list_t *this); |