From 684a27c9599feb29d84f931d5c007066126d7fb2 Mon Sep 17 00:00:00 2001 From: Gatsby Van Date: Fri, 19 Jan 2024 17:00:15 +0800 Subject: [PATCH] restore adi list. --- df_datalink/src/include/list.h | 397 +++++++++--- df_datalink/src/util/list.c | 1085 ++++++++++++++++++++++++-------- 2 files changed, 1118 insertions(+), 364 deletions(-) diff --git a/df_datalink/src/include/list.h b/df_datalink/src/include/list.h index 45f2c19..517a51c 100644 --- a/df_datalink/src/include/list.h +++ b/df_datalink/src/include/list.h @@ -1,118 +1,327 @@ +/***************************************************************************//** + * @file list.h + * @brief List library header + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * @copyright + * Copyright 2020(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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. +******************************************************************************** + * + * @section list_details Library description + * This library handles double linked lists and it expose inseart, + * read, get and delete functions. \n + * It also can be accesed using it member functions which wrapp function for + * usual list types.\n + * @subsection example Sample code + * @code{.c} + * // -- Use a generic list + * struct list_desc *list1; + * struct iterator *it; + * uint32_t a; + * // Create list list1 + * list_init(&list1, LIST_DEFAULT, NULL); + * // Add items to the list + * list_add_last(list1, 1); + * list_add_last(list1, 2); + * list_add_last(list1, 3); + * // Here the list will be: 1 -> 2 - > 3 + * + * list_read_last(list1, &a); + * printf("Last: %d\n", a); + * // 3 will be printed + * // Create an iterator on the end of the list + * iterator_init(&it, list1, 0); + * // Move the iterator backword with one position + * iterator_move(it, -1); + * // Read the data at the current position + * iterator_read(it, &a); + * printf("Current: %d\n", a); + * // 2 will be printed + * iterator_remove(it); + * list_remove(list1); + * + * // -- Use a popular list + * struct list_desc *stack; + * // Create a FIFO list + * list_init(&stack, LIST_STACK, NULL); + * // Put elements in the list + * stack->push(stack, 1); + * stack->push(stack, 2); + * stack->push(stack, 3); + * // Read from the stack + * stack->pop(stack, &a); + * printf("Last: %d\n", a); + * // 3 will be printed + * list_remove(stack); + * @endcode +*******************************************************************************/ -// -// list.h -// -// Copyright (c) 2010 TJ Holowaychuk -// +#ifndef _LIST_H_ +#define _LIST_H_ -#ifndef __LIST_H__ -#define __LIST_H__ +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ -#ifdef __cplusplus -extern "C" -{ -#endif - -#include #include +#include - /* - * list_t iterator direction. - */ +/******************************************************************************/ +/*************************** Types Declarations *******************************/ +/******************************************************************************/ - typedef enum - { - LIST_HEAD, - LIST_TAIL - } list_direction_t; +/** + * @struct list_desc + * @brief Structure storing the list and function wrapper for usual list types + * + * With this structure the funtionalities of usual list types + * ( \ref adapter_type ) can be accesed with the functions referenced in this + * structure. + * For example: + * @code{.c} + * my_queue->push(my_queue, my_data); + * @endcode + */ +struct list_desc; - /* - * list_t node struct. - */ +/** + * @struct list_iterator + * @brief Structure used to iterate through the list using Iterator functions. + */ +struct iterator; - typedef struct list_node - { - struct list_node *prev; - struct list_node *next; - void *val; - } list_node_t; +/** + * @brief Prototype of the compare function. + * + * The function used to compare the elements of the liste when doing + * operations on an ordered list. + * @param data1 - First element to be compared + * @param data2 - Second element to be compared + * @return + * - -1 - If data1 < data2 + * - 0 - If data1 == data2 + * - 1 - If data1 > data2 + */ +typedef int32_t (*f_cmp)(void *data1, void *data2); - /* - * list_t struct. - */ +/** + * @name Generic functions + * Each function interacting with the list have one of the following formats.\n + * Aditionaly they may have one more parametere for specific functionalities.\n + * In the Iterator functions, the list reference is replaced by the iterator's + * one. + * @{ + */ - typedef struct - { - list_node_t *head; - list_node_t *tail; - uint32_t len; - void (*free)(void *val); - int8_t (*compare)(void *a, void *b); - } list_t; +/** + * @brief Add an element in the list. + * + * The element of the list is created and the data field is stored in it. + * @param list_desc - Reference to the list. Created by \ref list_init. + * @param data - Data to store in a list element + * @return + * - 0 : On success + * - -1 : Otherwise + */ +typedef int32_t (*f_add)(struct list_desc *list_desc, void *data); - /* - * list_t iterator struct. - */ +/** + * @brief Edit an element in the list. The content is replaced by new_data. + * @param list_desc - Reference to the list. Created by \ref list_init. + * @param new_data - New data to replace the old one + * @return + * - 0 : On success + * - -1 : Otherwise + */ +typedef int32_t (*f_edit)(struct list_desc *list_desc, void *new_data); - typedef struct - { - list_node_t *next; - list_direction_t direction; - } list_iterator_t; +/** + * @brief Read an element from the list. + * @param list_desc - Reference to the list. Created by \ref list_init. + * @param result - If not null, result is filled with: + * @param data - Content of the list element, NULL if some error occur. + * @return \n + * - 0 : On success + * - -1 : Otherwise + * @note If the content of an element can be 0 then the result must be checked + * to see if the functions has succeded + */ +typedef int32_t (*f_read)(struct list_desc *list_desc, void **data); - // Node prototypes. +/** + * @brief Read and remove an element from the list. + * @param list_desc - Reference to the list. Created by \ref list_init. + * @param result - If not null, result is filled with: + * @param data - Content of the list element, NULL if some error occur. + * @return + * - 0 : On success + * - -1 : Otherwise + */ +typedef int32_t (*f_get)(struct list_desc *list_desc, void **data); - list_node_t * - list_node_new(void *val); +/** @} */ - // list_t prototypes. +/** + * @enum adapter_type + * @brief Selects functionalities for functions in \ref list_desc + */ +enum adapter_type { + /** Default type is LIST_STACK */ + LIST_DEFAULT, + /** + * Functions for a FIFO list (First-in first-out). Elements are inserted + * in one end and extracted from the other end. + * - \e Push: Insert element + * - \e Pop: Get next element (Read and remove) + * - \e Top_next: Read next element + * - \e Back: Read first element + * - \e Swap: Edit the content of the next element + */ + LIST_QUEUE, + /** + * Functions for a LIFO list (Last-in first-out). Elements are inserted + * and extracted only from the same end. + * - \e Push: Insert element + * - \e Pop: Get top element (Read and remove) + * - \e Top_next: Read top element + * - \e Back: Read bottom element + * - \e Swap: Edit the content of the top element + */ + LIST_STACK, + /** + * Functions for ordered list. The order of element is determinated + * usinge the \ref f_cmp. + * - \e Push: Insert element + * - \e Pop: Get lowest element (Read and remove) + * - \e Top_next: Read lowest element + * - \e Back: Read the biggest element + * - \e Swap: Edit the lowest element + */ + LIST_PRIORITY_LIST +}; - list_t * - list_new(void); +struct list_desc { + /** Refer to \ref adapter_type */ + f_add push; + /** Refer to \ref adapter_type */ + f_get pop; + /** Refer to \ref adapter_type */ + f_read top_next; + /** Refer to \ref adapter_type */ + f_read back; + /** Refer to \ref adapter_type */ + f_edit swap; + /** Structure storing the list internal parameters */ + void *priv_desc; +}; - list_node_t * - list_rpush(list_t *self, list_node_t *node); +/******************************************************************************/ +/************************ Functions Declarations ******************************/ +/******************************************************************************/ - list_node_t * - list_lpush(list_t *self, list_node_t *node); +int32_t list_init(struct list_desc **list_desc, + enum adapter_type type, + f_cmp comparator); +int32_t list_remove(struct list_desc *list_desc); +int32_t list_get_size(struct list_desc *list_desc, + uint32_t *out_size); - list_node_t * - list_find(list_t *self, void *val); +/** + * @name Iterator functions + * An iterator is used to iterate through the list. For a list, any number of + * iterators can be created. All must be removed before removing a list. + * @{ + */ +int32_t iterator_init(struct iterator **iter, + struct list_desc *list_desc, + bool start); +int32_t iterator_remove(struct iterator *iter); +int32_t iterator_move(struct iterator *iter, int32_t steps); +int32_t iterator_move_to_idx(struct iterator *iter, int32_t idx); +int32_t iterator_find(struct iterator *iter, void *cmp_data); +int32_t iterator_insert(struct iterator *iter, void *data, + bool after); +int32_t iterator_edit(struct iterator *iter, void *new_data); +int32_t iterator_read(struct iterator *iter, void **data); +int32_t iterator_get(struct iterator *iter, void **data); +/** @}*/ - list_node_t * - list_at(list_t *self, int index); +/** + * @name Operations on the ends of the list + * These functions will operate on the first or last element of the list + * @{ + */ +int32_t list_add_first(struct list_desc *list_desc, void *data); +int32_t list_edit_first(struct list_desc *list_desc, + void *new_data); +int32_t list_read_first(struct list_desc *list_desc, void **data); +int32_t list_get_first(struct list_desc *list_desc, void **data); - list_node_t * - list_rpop(list_t *self); +int32_t list_add_last(struct list_desc *list_desc, void *data); +int32_t list_edit_last(struct list_desc *list_desc, void *new_data); +int32_t list_read_last(struct list_desc *list_desc, void **data); +int32_t list_get_last(struct list_desc *list_desc, void **data); +/** @}*/ - list_node_t * - list_lpop(list_t *self); +/** + * @name Operations by index + * These functions use an index to identify the element in the list. + * @{ + */ +int32_t list_add_idx(struct list_desc *list_desc, void *data, + uint32_t idx); +int32_t list_edit_idx(struct list_desc *list_desc, void *new_data, + uint32_t idx); +int32_t list_read_idx(struct list_desc *list_desc, void **data, + uint32_t idx); +int32_t list_get_idx(struct list_desc *list_desc, void **data, + uint32_t idx); +/** @}*/ - void - list_remove(list_t *self, list_node_t *node); +/** + * @name Operations by comparation + * These functions use the specified \ref f_cmp at \ref list_init to identify + * the element this will operate on. + * @{ + */ +int32_t list_add_find(struct list_desc *list_desc, void *data); +int32_t list_edit_find(struct list_desc *list_desc, void *new_data, + void *cmp_data); +int32_t list_read_find(struct list_desc *list_desc, void **data, + void *cmp_data); +int32_t list_get_find(struct list_desc *list_desc, void **data, + void *cmp_data); +/** @}*/ - void - list_clear(list_t *self); - - void - list_destroy(list_t *self); - - // list_t iterator prototypes. - - list_iterator_t * - list_iterator_new(list_t *list, list_direction_t direction); - - list_iterator_t * - list_iterator_new_from_node(list_node_t *node, list_direction_t direction); - - list_node_t * - list_iterator_next(list_iterator_t *self); - - void - list_iterator_destroy(list_iterator_t *self); - -#ifdef __cplusplus -} -#endif - -#endif /* __CLIBS_LIST_H__ */ +#endif // _LIST_H_ diff --git a/df_datalink/src/util/list.c b/df_datalink/src/util/list.c index 119fa89..21ea676 100644 --- a/df_datalink/src/util/list.c +++ b/df_datalink/src/util/list.c @@ -1,342 +1,887 @@ -#ifndef LIST_MALLOC -#define LIST_MALLOC malloc -#endif +/******************************************************************************* +//** + * @file list.c + * @brief List library implementation + * @author Mihail Chindris (mihail.chindris@analog.com) +******************************************************************************** + * Copyright 2020(c) Analog Devices, Inc. + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * - 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. + * - Neither the name of Analog Devices, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * - The use of this software may or may not infringe the patent rights + * of one or more patent holders. This license does not release you + * from the requirement that you obtain separate licenses from these + * patent holders to use this software. + * - Use of the software either in source or binary form, must be run + * on or directly connected to an Analog Devices Inc. component. + * + * THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES "AS IS" AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, NON-INFRINGEMENT, + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ANALOG DEVICES BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, INTELLECTUAL PROPERTY RIGHTS, 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. +*******************************************************************************/ -#ifndef LIST_FREE -#define LIST_FREE free -#endif +/******************************************************************************/ +/***************************** Include Files **********************************/ +/******************************************************************************/ -// -// list.c -// -// Copyright (c) 2010 TJ Holowaychuk -// - -#include #include "list.h" +#include "error.h" +#include -/* - * Allocates a new list_node_t. NULL on failure. +/******************************************************************************/ +/*************************** Types Declarations *******************************/ +/******************************************************************************/ + +/** + * @struct list_elem + * @brief Format of each element of the list */ - -list_node_t * -list_node_new(void *val) +struct list_elem { - list_node_t *self; - if (!(self = LIST_MALLOC(sizeof(list_node_t)))) - return NULL; - self->prev = NULL; - self->next = NULL; - self->val = val; - return self; + /** User data */ + void *data; + /** Reference to previous element */ + struct list_elem *prev; + /** Reference to next element */ + struct list_elem *next; +}; + +/** + * @struct list_iterator + * @brief Structure used to iterate through the list + */ +struct iterator +{ + /** List reference */ + struct _list_desc *list; + /** Current element reference */ + struct list_elem *elem; +}; + +/** + * @struct _list_desc + * @brief List descriptor + */ +struct _list_desc +{ + /** Reference to first element in the list */ + struct list_elem *first; + /** Reference to last element in the list*/ + struct list_elem *last; + /** Number of elements in the list */ + uint32_t nb_elements; + /** Function used to compare elements */ + f_cmp comparator; + /** Number of current active iterators */ + uint32_t nb_iterators; + /** Internal list iterator */ + struct iterator l_it; +}; + +/** @brief Default function used to compare element in the list ( \ref f_cmp) */ +static int32_t default_comparator(void *data1, void *data2) +{ + return (int32_t)((int32_t *)data1 - (int32_t *)data2); } -/* - * Allocate a new list_t. NULL on failure. +/** + * @brief Creates a new list elements an configure its value + * @param data - To set list_elem.data + * @param prev - To set list_elem.prev + * @param next - To set list_elem.next + * @return Address of the new element or NULL if allocation fails. */ - -list_t * -list_new(void) +static inline struct list_elem *create_element(void *data, + struct list_elem *prev, + struct list_elem *next) { - list_t *self; - if (!(self = LIST_MALLOC(sizeof(list_t)))) - return NULL; - self->head = NULL; - self->tail = NULL; - self->free = NULL; - self->compare = NULL; - self->len = 0; - return self; + struct list_elem *elem; + + elem = (struct list_elem *)calloc(1, sizeof(*elem)); + if (!elem) + return NULL; + elem->data = data; + elem->prev = prev; + elem->next = next; + + return (elem); } -/* - * Remove all the node in list. - * @self: Pointer to the list +/** + * @brief Updates the necesary link on the list elements to add or remove one + * @param prev - Low element + * @param elem - Middle element + * @param next - High element */ - -void list_clear(list_t *self) +static inline void update_links(struct list_elem *prev, struct list_elem *elem, + struct list_elem *next) { - uint32_t len = self->len; - list_node_t *next; - list_node_t *curr = self->head; - - while (len) - { - next = curr->next; - if (self->free) - self->free(curr->val); - LIST_FREE(curr); - curr = next; - len--; - } + if (prev) + prev->next = elem ? elem : next; + if (elem) + { + elem->prev = prev; + elem->next = next; + } + if (next) + next->prev = elem ? elem : prev; } -/* - * Free the list. - * @self: Pointer to the list +/** + * @brief Update according to modification the list descriptor + * @param list - List reference + * @param new_first - New first element + * @param new_last - New last element */ - -void list_destroy(list_t *self) +static inline void update_desc(struct _list_desc *list, + struct list_elem *new_first, + struct list_elem *new_last) { - list_clear(self); - LIST_FREE(self); + if (new_first == list->first) + { + list->last = new_last; + if (new_first == NULL || new_last == NULL) + list->first = new_last; + } + else + { /* if (new_last == list->last) */ + list->first = new_first; + if (new_last == NULL || new_first == NULL) + list->last = new_first; + } } -/* - * Append the given node to the list - * and return the node, NULL on failure. - * @self: Pointer to the list for popping node - * @node: the node to push +/** + * @brief Set the adapter functions acording to the adapter type + * @param ad - Reference of the adapter + * @param type - Type of the adapter */ - -list_node_t * -list_rpush(list_t *self, list_node_t *node) +static inline void set_adapter(struct list_desc *ad, enum adapter_type type) { - if (!node) - return NULL; - - if (self->len) - { - node->prev = self->tail; - node->next = NULL; - self->tail->next = node; - self->tail = node; - } - else - { - self->head = self->tail = node; - node->prev = node->next = NULL; - } - - ++self->len; - return node; + switch (type) + { + case LIST_PRIORITY_LIST: + ad->push = list_add_find; + ad->pop = list_get_first; + ad->top_next = list_read_first; + ad->back = list_read_last; + ad->swap = list_edit_first; + break; + case LIST_QUEUE: + ad->push = list_add_last; + ad->pop = list_get_first; + ad->top_next = list_read_first; + ad->back = list_read_last; + ad->swap = list_edit_first; + break; + case LIST_DEFAULT: + case LIST_STACK: + default: + ad->push = list_add_last; + ad->pop = list_get_last; + ad->top_next = list_read_last; + ad->back = list_read_first; + ad->swap = list_edit_last; + break; + } } -/* - * Return / detach the last node in the list, or NULL. - * @self: Pointer to the list for popping node +/** + * @brief Create a new empty list + * @param list_desc - Where to store the reference of the new created list + * @param type - Type of adapter to use. + * @param comparator - Used to compare item when using an ordered list or when + * using the \em find functions. + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise */ - -list_node_t * -list_rpop(list_t *self) +int32_t list_init(struct list_desc **list_desc, enum adapter_type type, + f_cmp comparator) { - if (!self->len) - return NULL; + struct list_desc *l_desc; + struct _list_desc *list; - list_node_t *node = self->tail; + if (!list_desc) + return FAILURE; + l_desc = (struct list_desc *)calloc(1, sizeof(*l_desc)); + if (!l_desc) + return FAILURE; + list = (struct _list_desc *)calloc(1, sizeof(*list)); + if (!list) + { + free(l_desc); + return FAILURE; + } - if (--self->len) - { - (self->tail = node->prev)->next = NULL; - } - else - { - self->tail = self->head = NULL; - } + *list_desc = l_desc; + l_desc->priv_desc = list; + list->comparator = comparator ? comparator : default_comparator; - node->next = node->prev = NULL; - return node; + /* Configure wrapper */ + set_adapter(l_desc, type); + list->l_it.list = list; + + return SUCCESS; } -/* - * Return / detach the first node in the list, or NULL. - * @self: Pointer to the list for popping node +/** + * @brief Remove the created list. + * + * All its elements will be cleared and the data inside each will be lost. If + * not all iterators have been removed, the list will not be removed. + * @param list_desc - Reference to the list + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise */ - -list_node_t * -list_lpop(list_t *self) +int32_t list_remove(struct list_desc *list_desc) { - if (!self->len) - return NULL; + void *data; + struct _list_desc *list; - list_node_t *node = self->head; + if (!list_desc) + return FAILURE; - if (--self->len) - { - (self->head = node->next)->prev = NULL; - } - else - { - self->head = self->tail = NULL; - } + list = list_desc->priv_desc; + if (list->nb_iterators != 0) + return FAILURE; - node->next = node->prev = NULL; - return node; + /* Remove all the elements */ + while (SUCCESS == list_get_first(list_desc, &data)) + ; + free(list_desc->priv_desc); + free(list_desc); + + return SUCCESS; } -/* - * Prepend the given node to the list - * and return the node, NULL on failure. - * @self: Pointer to the list for pushing node - * @node: the node to push +/** + * @brief Get the number of elements inside the list + * @param list_desc - List reference + * @param out_size - Where to store the number of elements + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise */ - -list_node_t * -list_lpush(list_t *self, list_node_t *node) +int32_t list_get_size(struct list_desc *list_desc, uint32_t *out_size) { - if (!node) - return NULL; + struct _list_desc *list; - if (self->len) - { - node->next = self->head; - node->prev = NULL; - self->head->prev = node; - self->head = node; - } - else - { - self->head = self->tail = node; - node->prev = node->next = NULL; - } + if (!list_desc || !out_size) + return FAILURE; - ++self->len; - return node; + list = list_desc->priv_desc; + *out_size = list->nb_elements; + + return SUCCESS; } -/* - * Return the node associated to val or NULL. - * @self: Pointer to the list for finding given value - * @val: Value to find - */ - -list_node_t * -list_find(list_t *self, void *val) +/** @brief Add element at the begining of the list. Refer to \ref f_add */ +int32_t list_add_first(struct list_desc *list_desc, void *data) { - list_iterator_t *it = list_iterator_new(self, LIST_HEAD); - list_node_t *node; + struct list_elem *prev; + struct list_elem *next; + struct list_elem *elem; + struct _list_desc *list; - while ((node = list_iterator_next(it))) - { - if (self->compare) - { - if (self->compare(val, node->val) == 0) - { - list_iterator_destroy(it); - return node; - } - } - else - { - if (val == node->val) - { - list_iterator_destroy(it); - return node; - } - } - } + if (!list_desc) + return FAILURE; - list_iterator_destroy(it); - return NULL; + list = list_desc->priv_desc; + + prev = NULL; + next = list->first; + elem = create_element(data, prev, next); + if (!elem) + return FAILURE; + + update_links(prev, elem, next); + + update_desc(list, elem, list->last); + + list->nb_elements++; + + return SUCCESS; } -/* - * Return the node at the given index or NULL. - * @self: Pointer to the list for finding given index - * @index: the index of node in the list - */ - -list_node_t * -list_at(list_t *self, int index) +/** @brief Add element at the end of the list. Refer to \ref f_add */ +int32_t list_add_last(struct list_desc *list_desc, void *data) { - list_direction_t direction = LIST_HEAD; + struct list_elem *prev; + struct list_elem *next; + struct list_elem *elem; + struct _list_desc *list; - if (index < 0) - { - direction = LIST_TAIL; - index = ~index; - } + if (!list_desc) + return FAILURE; + list = list_desc->priv_desc; - if ((unsigned)index < self->len) - { - list_iterator_t *it = list_iterator_new(self, direction); - list_node_t *node = list_iterator_next(it); - while (index--) - node = list_iterator_next(it); - list_iterator_destroy(it); - return node; - } + prev = list->last; + next = NULL; + elem = create_element(data, prev, next); + if (!elem) + return FAILURE; - return NULL; + update_links(prev, elem, next); + + update_desc(list, list->first, elem); + + list->nb_elements++; + + return SUCCESS; } -/* - * Remove the given node from the list, freeing it and it's value. - * @self: Pointer to the list to delete a node - * @node: Pointer the node to be deleted - */ - -void list_remove(list_t *self, list_node_t *node) +/** @brief Add element at the specified idx. Refer to \ref f_add */ +int32_t list_add_idx(struct list_desc *list_desc, void *data, uint32_t idx) { - node->prev - ? (node->prev->next = node->next) - : (self->head = node->next); + struct _list_desc *list; - node->next - ? (node->next->prev = node->prev) - : (self->tail = node->prev); + if (!list_desc) + return FAILURE; + list = list_desc->priv_desc; - if (self->free) - self->free(node->val); + /* If there are no elements the creation of an iterator will fail */ + if (list->nb_elements == 0 || idx == 0) + return list_add_first(list_desc, data); + if (list->nb_elements == idx) + return list_add_last(list_desc, data); - LIST_FREE(node); - --self->len; + list->l_it.elem = list->first; + if (SUCCESS != iterator_move(&(list->l_it), idx)) + return FAILURE; + + return iterator_insert(&(list->l_it), data, 0); } -/* - * Allocate a new list_iterator_t. NULL on failure. - * Accepts a direction, which may be LIST_HEAD or LIST_TAIL. - */ - -list_iterator_t * -list_iterator_new(list_t *list, list_direction_t direction) +/** @brief Add element in ascending order. Refer to \ref f_add */ +int32_t list_add_find(struct list_desc *list_desc, void *data) { - list_node_t *node = direction == LIST_HEAD - ? list->head - : list->tail; - return list_iterator_new_from_node(node, direction); + struct list_elem *elem; + struct _list_desc *list; + + if (!list_desc) + return FAILURE; + list = list_desc->priv_desc; + + /* Based on place iterator */ + elem = list->first; + while (elem) + { + if (0 < list->comparator(elem->data, data)) + break; + elem = elem->next; + } + if (elem == NULL) + { + list->l_it.elem = list->last; + return iterator_insert(&(list->l_it), data, 1); + } + else + { + list->l_it.elem = elem; + return iterator_insert(&(list->l_it), data, 0); + } } -/* - * Allocate a new list_iterator_t with the given start - * node. NULL on failure. - */ - -list_iterator_t * -list_iterator_new_from_node(list_node_t *node, list_direction_t direction) +/** @brief Edit the first element of the list. Refer to \ref f_edit */ +int32_t list_edit_first(struct list_desc *list_desc, void *new_data) { - list_iterator_t *self; - if (!(self = LIST_MALLOC(sizeof(list_iterator_t)))) - return NULL; - self->next = node; - self->direction = direction; - return self; + struct _list_desc *list; + + if (!list_desc) + return FAILURE; + + list = list_desc->priv_desc; + list->first->data = new_data; + + return SUCCESS; } -/* - * Return the next list_node_t or NULL when no more - * nodes remain in the list. - */ - -list_node_t * -list_iterator_next(list_iterator_t *self) +/** @brief Edit the last element of the list. Refer to \ref f_edit */ +int32_t list_edit_last(struct list_desc *list_desc, void *new_data) { - list_node_t *curr = self->next; - if (curr) - { - self->next = self->direction == LIST_HEAD - ? curr->next - : curr->prev; - } - return curr; + struct _list_desc *list; + + if (!list_desc) + return FAILURE; + + list = list_desc->priv_desc; + list->last->data = new_data; + + return SUCCESS; } -/* - * Free the list iterator. - */ - -void list_iterator_destroy(list_iterator_t *self) +/** @brief Edit the element at the specified idx. Refer to \ref f_edit */ +int32_t list_edit_idx(struct list_desc *list_desc, void *new_data, uint32_t idx) { - LIST_FREE(self); - self = NULL; + struct _list_desc *list; + + if (!list_desc) + return FAILURE; + list = list_desc->priv_desc; + + list->l_it.elem = list->first; + if (SUCCESS != iterator_move(&(list->l_it), idx)) + return FAILURE; + + return iterator_edit(&(list->l_it), new_data); +} + +/** @brief Edit the element which match with cmp_data. Refer to \ref f_edit */ +int32_t list_edit_find(struct list_desc *list_desc, void *new_data, + void *cmp_data) +{ + struct _list_desc *list; + + if (!list_desc) + return FAILURE; + list = list_desc->priv_desc; + + list->l_it.elem = list->first; + if (SUCCESS != iterator_find(&(list->l_it), cmp_data)) + return FAILURE; + + return iterator_edit(&(list->l_it), new_data); +} + +/** @brief Read the first element of the list. Refer to \ref f_read */ +int32_t list_read_first(struct list_desc *list_desc, void **data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->first) + return FAILURE; + + *data = list->first->data; + + return SUCCESS; +} + +/** @brief Read the last element of the list. Refer to \ref f_read */ +int32_t list_read_last(struct list_desc *list_desc, void **data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->last) + return FAILURE; + + *data = list->last->data; + + return SUCCESS; +} + +/** @brief Read the element at the specified idx. Refer to \ref f_read */ +int32_t list_read_idx(struct list_desc *list_desc, void **data, uint32_t idx) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + if (!list) + return FAILURE; + + if (idx >= list->nb_elements) + return FAILURE; + + list->l_it.elem = list->first; + if (SUCCESS != iterator_move(&(list->l_it), idx)) + return FAILURE; + + return iterator_read(&(list->l_it), data); +} + +/** @brief Read the element which match with cmp_data. Refer to \ref f_read */ +int32_t list_read_find(struct list_desc *list_desc, void **data, + void *cmp_data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + if (!list) + return FAILURE; + + list = list_desc->priv_desc; + list->l_it.elem = list->first; + if (SUCCESS != iterator_find(&(list->l_it), cmp_data)) + return FAILURE; + + return iterator_read(&(list->l_it), data); +} + +/** @brief Read and delete the first element of the list. Refer to \ref f_get */ +int32_t list_get_first(struct list_desc *list_desc, void **data) +{ + struct list_elem *prev; + struct list_elem *next; + struct list_elem *elem; + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->nb_elements) + return FAILURE; + + elem = list->first; + prev = elem->prev; + next = elem->next; + + update_links(prev, NULL, next); + update_desc(list, next, list->last); + list->nb_elements--; + + *data = elem->data; + free(elem); + + return SUCCESS; +} + +/** @brief Read and delete the last element of the list. Refer to \ref f_get */ +int32_t list_get_last(struct list_desc *list_desc, void **data) +{ + struct list_elem *prev; + struct list_elem *next; + struct list_elem *elem; + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + if (!list->nb_elements) + return FAILURE; + + elem = list->last; + prev = elem->prev; + next = elem->next; + + update_links(prev, NULL, next); + update_desc(list, list->first, prev); + list->nb_elements--; + + *data = elem->data; + free(elem); + + return SUCCESS; +} + +/** @brief Read and delete the element at idx. Refer to \ref f_get */ +int32_t list_get_idx(struct list_desc *list_desc, void **data, uint32_t idx) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + list->l_it.elem = list->first; + if (SUCCESS != iterator_move(&(list->l_it), idx)) + return FAILURE; + + return iterator_get(&(list->l_it), data); +} + +/** + * @brief Read and delete the element which match with cmp_data. + * Refer to \ref f_get + */ +int32_t list_get_find(struct list_desc *list_desc, void **data, void *cmp_data) +{ + struct _list_desc *list; + + if (!list_desc || !data) + return FAILURE; + + *data = NULL; + list = list_desc->priv_desc; + list->l_it.elem = list->first; + if (SUCCESS != iterator_find(&(list->l_it), cmp_data)) + return FAILURE; + + return iterator_get(&(list->l_it), data); +} + +/** + * @brief Create a new iterator + * @param iter - Where to store the reference for the new iterator + * @param list_desc - Reference of the list the iterator will be used for + * @param start - If it is true the iterator will be positioned at the first + * element of the list, else it will be positioned at the last. + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise + */ +int32_t iterator_init(struct iterator **iter, struct list_desc *list_desc, + bool start) +{ + struct iterator *it; + + if (!list_desc) + return FAILURE; + + it = (struct iterator *)calloc(1, sizeof(*it)); + if (!it) + return FAILURE; + it->list = list_desc->priv_desc; + it->list->nb_iterators++; + it->elem = start ? it->list->first : it->list->last; + *iter = it; + + return SUCCESS; +} + +/** + * @brief Remove the created iterator + * @param iter - Reference of the iterator + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise + */ +int32_t iterator_remove(struct iterator *iter) +{ + struct iterator *it = iter; + + if (!it) + return FAILURE; + + it->list->nb_iterators--; + free(it); + + return SUCCESS; +} + +/** + * @brief Move the position of the iteration through the list. + * + * If the required position is outside the list, the call will fail and the + * iterator will keep its position. + * @param iter - Reference of the iterator + * @param steps - Number of positions to be move. If positive, it will be moved + * forward, otherwise backwords. + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise + */ +int32_t iterator_move(struct iterator *iter, int32_t steps) +{ + struct iterator *it = iter; + struct list_elem *elem; + int32_t dir = (steps < 0) ? -1 : 1; + + if (!it) + return FAILURE; + + steps = abs(steps); + elem = it->elem; + while (steps > 0 && elem) + { + elem = dir > 0 ? elem->next : elem->prev; + steps--; + } + if (!elem) + return FAILURE; + + it->elem = elem; + + return SUCCESS; +} + +/** + * @brief Move the position of the iterator at the specified index of the list. + * + * @param iter - Reference of the iterator + * @param idx - Position in the list. If negative start counting backwords + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise + */ +int32_t iterator_move_to_idx(struct iterator *iter, int32_t idx) +{ + struct list_elem *elem; + int32_t dir = (idx < 0) ? -1 : 1; + + if (!iter) + return FAILURE; + + idx = abs(idx); + elem = dir > 0 ? iter->list->first : iter->list->last; + while (idx > 0 && elem) + { + elem = dir > 0 ? elem->next : elem->prev; + idx--; + } + if (!elem) + return FAILURE; + + iter->elem = elem; + + return SUCCESS; +} + +/** + * @brief Place the iterator where cmp_data if found. + * @param iter - Reference to the iterator + * @param cmp_data - Data to be found + * @return + * - \ref SUCCESS : On success + * - \ref FAILURE : Otherwise + */ +int32_t iterator_find(struct iterator *iter, void *cmp_data) +{ + struct iterator *it = iter; + struct list_elem *elem; + + if (!it) + return FAILURE; + + elem = it->list->first; + while (elem) + { + if (0 == it->list->comparator(elem->data, cmp_data)) + { + it->elem = elem; + return SUCCESS; + } + elem = elem->next; + } + + return FAILURE; +} + +/** + * @brief Replace the data at the current position. Refer to \ref f_edit + */ +int32_t iterator_edit(struct iterator *iter, void *new_data) +{ + struct iterator *it = iter; + + if (!it) + return FAILURE; + + it->elem->data = new_data; + + return SUCCESS; +} + +/** + * @brief Read and remove the data at the current position. Refer to \ref f_get. + * + * If the current item is the last one, the iterator will be moved to the + * previous one. + */ +int32_t iterator_get(struct iterator *iter, void **data) +{ + struct iterator *it = iter; + struct list_elem *next; + + if (!it || !it->elem || !data) + return FAILURE; + + update_links(it->elem->prev, NULL, it->elem->next); + if (it->elem == it->list->first) + update_desc(it->list, it->elem->next, it->list->last); + else if (it->elem == it->list->last) + update_desc(it->list, it->list->first, it->elem->prev); + it->list->nb_elements--; + + *data = it->elem->data; + if (it->elem == it->list->last) + next = it->elem->prev; + else + next = it->elem->next; + free(it->elem); + it->elem = next; + + return SUCCESS; +} + +/** + * @brief Read the data at the current position. Refer to \ref f_read + */ +int32_t iterator_read(struct iterator *iter, void **data) +{ + struct iterator *it = iter; + + if (!it || !it->elem || !data) + return FAILURE; + + *data = it->elem->data; + + return SUCCESS; +} + +/** + * @brief Insert an item in the list. Refer to \ref f_add + * @param iter + * @param data + * @param after - If true, the item will be inserted after the current position. + * Otherwise it will be inserted before. + */ +int32_t iterator_insert(struct iterator *iter, void *data, bool after) +{ + struct iterator *it = iter; + struct list_elem *elem; + struct list_desc list_desc; + + if (!it) + return FAILURE; + + list_desc.priv_desc = iter->list; + if (after && it->elem == it->list->last) + return list_add_last(&list_desc, data); + if (!after && it->elem == it->list->first) + return list_add_first(&list_desc, data); + + if (after) + elem = create_element(data, it->elem, it->elem->next); + else + elem = create_element(data, it->elem->prev, it->elem); + if (!elem) + return FAILURE; + + update_links(elem->prev, elem, elem->next); + + it->list->nb_elements++; + + return SUCCESS; }