/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2017 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * Doubly linked list implementation. * * @file list.h * @author Mike Becker * @author Olaf Wintermann */ #ifndef UCX_LIST_H #define UCX_LIST_H #include "ucx.h" #include "allocator.h" #ifdef __cplusplus extern "C" { #endif /** * Loop statement for UCX lists. * * The first argument is the name of the iteration variable. The scope of * this variable is limited to the UCX_FOREACH statement. * * The second argument is a pointer to the list. In most cases this will be the * pointer to the first element of the list, but it may also be an arbitrary * element of the list. The iteration will then start with that element. * * @param list The first element of the list * @param elem The variable name of the element */ #define UCX_FOREACH(elem,list) \ for (UcxList* elem = (UcxList*) list ; elem != NULL ; elem = elem->next) /** * UCX list type. * @see UcxList */ typedef struct UcxList UcxList; /** * UCX list structure. */ struct UcxList { /** * List element payload. */ void *data; /** * Pointer to the next list element or NULL, if this is the * last element. */ UcxList *next; /** * Pointer to the previous list element or NULL, if this is * the first element. */ UcxList *prev; }; /** * Creates an element-wise copy of a list. * * This function clones the specified list by creating new list elements and * copying the data with the specified copy_func(). If no copy_func() is * specified, a shallow copy is created and the new list will reference the * same data as the source list. * * @param list the list to copy * @param cpyfnc a pointer to the function that shall copy an element (may be * NULL) * @param data additional data for the copy_func() * @return a pointer to the copy */ UcxList *ucx_list_clone(const UcxList *list, copy_func cpyfnc, void* data); /** * Creates an element-wise copy of a list using a UcxAllocator. * * See ucx_list_clone() for details. * * You might want to pass the allocator via the data parameter, * to access it within the copy function for making deep copies. * * @param allocator the allocator to use * @param list the list to copy * @param cpyfnc a pointer to the function that shall copy an element (may be * NULL) * @param data additional data for the copy_func() * @return a pointer to the copy * @see ucx_list_clone() */ UcxList *ucx_list_clone_a(UcxAllocator *allocator, const UcxList *list, copy_func cpyfnc, void* data); /** * Compares two UCX lists element-wise by using a compare function. * * Each element of the two specified lists are compared by using the specified * compare function and the additional data. The type and content of this * additional data depends on the cmp_func() used. * * If the list pointers denote elements within a list, the lists are compared * starting with the denoted elements. Thus any previous elements are not taken * into account. This might be useful to check, if certain list tails match * each other. * * @param list1 the first list * @param list2 the second list * @param cmpfnc the compare function * @param data additional data for the compare function * @return 1, if and only if the two lists equal element-wise, 0 otherwise */ int ucx_list_equals(const UcxList *list1, const UcxList *list2, cmp_func cmpfnc, void* data); /** * Destroys the entire list. * * The members of the list are not automatically freed, so ensure they are * otherwise referenced or destroyed by ucx_list_free_contents(). * Otherwise, a memory leak is likely to occur. * * Caution: the argument MUST denote an entire list (i.e. a call * to ucx_list_first() on the argument must return the argument itself) * * @param list the list to free * @see ucx_list_free_contents() */ void ucx_list_free(UcxList *list); /** * Destroys the entire list using a UcxAllocator. * * See ucx_list_free() for details. * * @param allocator the allocator to use * @param list the list to free * @see ucx_list_free() */ void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); /** * Destroys the contents of the specified list by calling the specified * destructor on each of them. * * Note, that the contents are not usable afterwards and the list should be * destroyed with ucx_list_free(). * * If no destructor is specified (NULL), stdlib's free() is used. * * @param list the list for which the contents shall be freed * @param destr optional destructor function * @see ucx_list_free() */ void ucx_list_free_content(UcxList* list, ucx_destructor destr); /** * Inserts an element at the end of the list. * * This is generally an O(n) operation, as the end of the list is retrieved with * ucx_list_last(). * * @param list the list where to append the data, or NULL to * create a new list * @param data the data to insert * @return list, if it is not NULL or a pointer to * the newly created list otherwise */ UcxList *ucx_list_append(UcxList *list, void *data); /** * Inserts an element at the end of the list using a UcxAllocator. * * See ucx_list_append() for details. * * @param allocator the allocator to use * @param list the list where to append the data, or NULL to * create a new list * @param data the data to insert * @return list, if it is not NULL or a pointer to * the newly created list otherwise * @see ucx_list_append() */ UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); /** * Inserts an element at the beginning of the list. * * You should overwrite the old list pointer by calling * mylist = ucx_list_prepend(mylist, mydata);. However, you may * also perform successive calls of ucx_list_prepend() on the same list pointer, * as this function always searchs for the head of the list with * ucx_list_first(). * * @param list the list where to insert the data or NULL to create * a new list * @param data the data to insert * @return a pointer to the new list head */ UcxList *ucx_list_prepend(UcxList *list, void *data); /** * Inserts an element at the beginning of the list using a UcxAllocator. * * See ucx_list_prepend() for details. * * @param allocator the allocator to use * @param list the list where to insert the data or NULL to create * a new list * @param data the data to insert * @return a pointer to the new list head * @see ucx_list_prepend() */ UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); /** * Concatenates two lists. * * Either of the two arguments may be NULL. * * This function modifies the references to the next/previous element of * the last/first element of list1/ * list2. * * @param list1 first list * @param list2 second list * @return if list1 is NULL, list2 is * returned, otherwise list1 is returned */ UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); /** * Returns the first element of a list. * * If the argument is the list pointer, it is directly returned. Otherwise * this function traverses to the first element of the list and returns the * list pointer. * * @param elem one element of the list * @return the first element of the list, the specified element is a member of */ UcxList *ucx_list_first(const UcxList *elem); /** * Returns the last element of a list. * * If the argument has no successor, it is the last element and therefore * directly returned. Otherwise this function traverses to the last element of * the list and returns it. * * @param elem one element of the list * @return the last element of the list, the specified element is a member of */ UcxList *ucx_list_last(const UcxList *elem); /** * Returns the list element at the specified index. * * @param list the list to retrieve the element from * @param index index of the element to return * @return the element at the specified index or NULL, if the * index is greater than the list size */ UcxList *ucx_list_get(const UcxList *list, size_t index); /** * Returns the index of an element. * * @param list the list where to search for the element * @param elem the element to find * @return the index of the element or -1 if the list does not contain the * element */ ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); /** * Returns the element count of the list. * * @param list the list whose elements are counted * @return the element count */ size_t ucx_list_size(const UcxList *list); /** * Returns the index of an element containing the specified data. * * This function uses a cmp_func() to compare the data of each list element * with the specified data. If no cmp_func is provided, the pointers are * compared. * * If the list contains the data more than once, the index of the first * occurrence is returned. * * @param list the list where to search for the data * @param elem the element data * @param cmpfnc the compare function * @param data additional data for the compare function * @return the index of the element containing the specified data or -1 if the * data is not found in this list */ ssize_t ucx_list_find(const UcxList *list, void *elem, cmp_func cmpfnc, void *data); /** * Checks, if a list contains a specific element. * * An element is found, if ucx_list_find() returns a value greater than -1. * * @param list the list where to search for the data * @param elem the element data * @param cmpfnc the compare function * @param data additional data for the compare function * @return 1, if and only if the list contains the specified element data * @see ucx_list_find() */ int ucx_list_contains(const UcxList *list, void *elem, cmp_func cmpfnc, void *data); /** * Sorts a UcxList with natural merge sort. * * This function uses O(n) additional temporary memory for merge operations * that is automatically freed after each merge. * * As the head of the list might change, you MUST call this function * as follows: mylist = ucx_list_sort(mylist, mycmpfnc, mydata);. * * @param list the list to sort * @param cmpfnc the function that shall be used to compare the element data * @param data additional data for the cmp_func() * @return the sorted list */ UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); /** * Removes an element from the list. * * If the first element is removed, the list pointer changes. So it is * highly recommended to always update the pointer by calling * mylist = ucx_list_remove(mylist, myelem);. * * @param list the list from which the element shall be removed * @param element the element to remove * @return returns the updated list pointer or NULL, if the list * is now empty */ UcxList *ucx_list_remove(UcxList *list, UcxList *element); /** * Removes an element from the list using a UcxAllocator. * * See ucx_list_remove() for details. * * @param allocator the allocator to use * @param list the list from which the element shall be removed * @param element the element to remove * @return returns the updated list pointer or NULL, if the list * @see ucx_list_remove() */ UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, UcxList *element); /** * Returns the union of two lists. * * The union is a list of unique elements regarding cmpfnc obtained from * both source lists. * * @param left the left source list * @param right the right source list * @param cmpfnc a function to compare elements * @param cmpdata additional data for the compare function * @param cpfnc a function to copy the elements * @param cpdata additional data for the copy function * @return a new list containing the union */ UcxList* ucx_list_union(const UcxList *left, const UcxList *right, cmp_func cmpfnc, void* cmpdata, copy_func cpfnc, void* cpdata); /** * Returns the union of two lists. * * The union is a list of unique elements regarding cmpfnc obtained from * both source lists. * * @param allocator allocates the new list elements * @param left the left source list * @param right the right source list * @param cmpfnc a function to compare elements * @param cmpdata additional data for the compare function * @param cpfnc a function to copy the elements * @param cpdata additional data for the copy function * @return a new list containing the union */ UcxList* ucx_list_union_a(UcxAllocator *allocator, const UcxList *left, const UcxList *right, cmp_func cmpfnc, void* cmpdata, copy_func cpfnc, void* cpdata); /** * Returns the intersection of two lists. * * The intersection contains all elements of the left list * (including duplicates) that can be found in the right list. * * @param left the left source list * @param right the right source list * @param cmpfnc a function to compare elements * @param cmpdata additional data for the compare function * @param cpfnc a function to copy the elements * @param cpdata additional data for the copy function * @return a new list containing the intersection */ UcxList* ucx_list_intersection(const UcxList *left, const UcxList *right, cmp_func cmpfnc, void* cmpdata, copy_func cpfnc, void* cpdata); /** * Returns the intersection of two lists. * * The intersection contains all elements of the left list * (including duplicates) that can be found in the right list. * * @param allocator allocates the new list elements * @param left the left source list * @param right the right source list * @param cmpfnc a function to compare elements * @param cmpdata additional data for the compare function * @param cpfnc a function to copy the elements * @param cpdata additional data for the copy function * @return a new list containing the intersection */ UcxList* ucx_list_intersection_a(UcxAllocator *allocator, const UcxList *left, const UcxList *right, cmp_func cmpfnc, void* cmpdata, copy_func cpfnc, void* cpdata); /** * Returns the difference of two lists. * * The difference contains all elements of the left list * (including duplicates) that are not equal to any element of the right list. * * @param left the left source list * @param right the right source list * @param cmpfnc a function to compare elements * @param cmpdata additional data for the compare function * @param cpfnc a function to copy the elements * @param cpdata additional data for the copy function * @return a new list containing the difference */ UcxList* ucx_list_difference(const UcxList *left, const UcxList *right, cmp_func cmpfnc, void* cmpdata, copy_func cpfnc, void* cpdata); /** * Returns the difference of two lists. * * The difference contains all elements of the left list * (including duplicates) that are not equal to any element of the right list. * * @param allocator allocates the new list elements * @param left the left source list * @param right the right source list * @param cmpfnc a function to compare elements * @param cmpdata additional data for the compare function * @param cpfnc a function to copy the elements * @param cpdata additional data for the copy function * @return a new list containing the difference */ UcxList* ucx_list_difference_a(UcxAllocator *allocator, const UcxList *left, const UcxList *right, cmp_func cmpfnc, void* cmpdata, copy_func cpfnc, void* cpdata); #ifdef __cplusplus } #endif #endif /* UCX_LIST_H */