From ca51a72133ed8b8ecfbfc69730752bab4e572829 Mon Sep 17 00:00:00 2001 From: Benjamin Walsh Date: Sun, 14 Jun 2015 12:15:05 -0400 Subject: [PATCH] dlist: enhance library and make all functions inline The old doubly-linked list implementation had only support for very basic operations, i.e. add at head and remove. The new implementation is highly enhanced, allowing these operations: - initialize list - check if a node is the list's head - check if a node is the list's tail - check if the list is empty - get a reference to the head item in the list - get a reference to the next item in the list - add node to tail of list - add node to head of list - insert node after a node - insert node before a node - insert node at position based on condition - remove a specific node from a list - get the first node in a list The implementation is completely inline, since the operations are rather simple and do not warrant a function call. Change-Id: Id85c04e67f6a88b005390172f1276daa12bcf8ce Signed-off-by: Benjamin Walsh --- include/misc/dlist.h | 273 ++++++++++++++++++++++++++++++++++++++++--- misc/Makefile | 2 +- misc/dlist.c | 109 ----------------- 3 files changed, 257 insertions(+), 127 deletions(-) delete mode 100644 misc/dlist.c diff --git a/include/misc/dlist.h b/include/misc/dlist.h index ecd2ff05843..cb04f04b9e4 100644 --- a/include/misc/dlist.h +++ b/include/misc/dlist.h @@ -1,7 +1,7 @@ -/* dlist.h - doubly linked list header file */ +/* dlist.h - doubly-linked list inline implementation */ /* - * Copyright (c) 2013-2014 Wind River Systems, Inc. + * Copyright (c) 2013-2015 Wind River Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -32,28 +32,267 @@ /* DESCRIPTION -This header file implements the necessary structure definitions for a doubly -linked list. +Doubly-linked list implementation. + +The lists are expected to be initialized such that both the head and tail +pointers point to the list itself. Initializing the lists in such a fashion +simplifies the adding and removing of nodes to/from the list. */ -#ifndef _DLIST_H -#define _DLIST_H +#ifndef _misc_dlist__h_ +#define _misc_dlist__h_ -typedef struct dnode_s { +#include + +struct _dnode { union { - struct dnode_s *head; /* ptr to head of list (dlist_t) */ - struct dnode_s *next; /* ptr to next node (dnode_t) */ + struct _dnode *head; /* ptr to head of list (sys_dlist_t) */ + struct _dnode *next; /* ptr to next node (sys_dnode_t) */ }; union { - struct dnode_s *tail; /* ptr to tail of list (dlist_t) */ - struct dnode_s *prev; /* ptr to previous node (dnode_t) */ + struct _dnode *tail; /* ptr to tail of list (sys_dlist_t) */ + struct _dnode *prev; /* ptr to previous node (sys_dnode_t) */ }; -} dlist_t, dnode_t; +}; -/* externs */ +typedef struct _dnode sys_dlist_t; +typedef struct _dnode sys_dnode_t; -extern void dlistAdd(dlist_t *pList, dnode_t *pNode); -extern void dlistRemove(dnode_t *pNode); -extern dnode_t *dlistGet(dlist_t *pList); +/*! + * @brief initialize list + * + * @param list the doubly-linked list + * + * @return None + */ -#endif /* _DLIST_H */ +static inline void sys_dlist_init(sys_dlist_t *list) +{ + list->head = (sys_dnode_t *)list; + list->tail = (sys_dnode_t *)list; +} + +/*! + * @brief check if a node is the list's head + * + * @param list the doubly-linked list to operate on + * @param node the node to check + * + * @return 1 if node is the head, 0 otherwise + */ + +static inline int sys_dlist_is_head(sys_dlist_t *list, sys_dnode_t *node) +{ + return list->head == node; +} + +/*! + * @brief check if a node is the list's tail + * + * @param list the doubly-linked list to operate on + * @param node the node to check + * + * @return 1 if node is the tail, 0 otherwise + */ + +static inline int sys_dlist_is_tail(sys_dlist_t *list, sys_dnode_t *node) +{ + return list->tail == node; +} + +/*! + * @brief check if the list is empty + * + * @param list the doubly-linked list to operate on + * + * @return 1 if empty, 0 otherwise + */ + +static inline int sys_dlist_is_empty(sys_dlist_t *list) +{ + return list->head == list; +} + +/*! + * @brief get a reference to the head item in the list + * + * @param list the doubly-linked list to operate on + * + * @return a pointer to the head element from a node, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_peek_head(sys_dlist_t *list) +{ + return sys_dlist_is_empty(list) ? NULL : list->head; +} + +/*! + * @brief get a reference to the next item in the list + * + * @param list the doubly-linked list to operate on + * @param node the node from which to get the next element in the list + * + * @return a pointer to the next element from a node, NULL if node is the tail + */ + +static inline sys_dnode_t *sys_dlist_peek_next(sys_dlist_t *list, + sys_dnode_t *node) +{ + return node == list->tail ? NULL : node->next; +} + +/*! + * @brief add node to tail of list + * + * @param list the doubly-linked list to operate on + * @param node the element to append + * + * @return None + */ + +static inline void sys_dlist_append(sys_dlist_t *list, sys_dnode_t *node) +{ + node->next = list; + node->prev = list->tail; + + list->tail->next = node; + list->tail = node; +} + +/*! + * @brief add node to head of list + * + * @param list the doubly-linked list to operate on + * @param node the element to append + * + * @return None + */ + +static inline void sys_dlist_prepend(sys_dlist_t *list, sys_dnode_t *node) +{ + node->next = list->head; + node->prev = list; + + list->head->prev = node; + list->head = node; +} + +/*! + * @brief insert node after a node + * + * Insert a node after a specified node in a list. + * + * @param list the doubly-linked list to operate on + * @param insert_point the insert point in the list: if NULL, insert at head + * @param node the element to append + * + * @return None + */ + +static inline void sys_dlist_insert_after(sys_dlist_t *list, + sys_dnode_t *insert_point, sys_dnode_t *node) +{ + if (!insert_point) { + sys_dlist_prepend(list, node); + } else { + node->next = insert_point->next; + node->prev = insert_point; + insert_point->next->prev = node; + insert_point->next = node; + } +} + +/*! + * @brief insert node before a node + * + * Insert a node before a specified node in a list. + * + * @param list the doubly-linked list to operate on + * @param insert_point the insert point in the list: if NULL, insert at tail + * @param node the element to insert + * + * @return None + */ + +static inline void sys_dlist_insert_before(sys_dlist_t *list, + sys_dnode_t *insert_point, sys_dnode_t *node) +{ + if (!insert_point) { + sys_dlist_append(list, node); + } else { + node->prev = insert_point->prev; + node->next = insert_point; + insert_point->prev->next = node; + insert_point->prev = node; + } +} + +/*! + * @brief insert node at position + * + * Insert a node in a location depending on a external condition. The cond() + * function checks if the node is to be inserted _before_ the current node + * against which it is checked. + * + * @param list the doubly-linked list to operate on + * @param node the element to insert + * @param cond a function that determines if the current node is the correct + * insert point + * @param data parameter to cond() + * + * @return None + */ + +static inline void sys_dlist_insert_at(sys_dlist_t *list, sys_dnode_t *node, + int (*cond)(sys_dnode_t *, void *), void *data) +{ + if (sys_dlist_is_empty(list)) { + sys_dlist_append(list, node); + } else { + sys_dnode_t *pos = sys_dlist_peek_head(list); + + while (pos && !cond(pos, data)) { + pos = sys_dlist_peek_next(list, pos); + } + sys_dlist_insert_before(list, pos, node); + } +} + +/*! + * @brief remove a specific node from a list + * + * The list is implicit from the node. The node must be part of a list. + * + * @param node the node to remove + * + * @return None + */ + +static inline void sys_dlist_remove(sys_dnode_t *node) +{ + node->prev->next = node->next; + node->next->prev = node->prev; +} + +/*! + * @brief get the first node in a list + * + * @param list the doubly-linked list to operate on + * + * @return the first node in the list, NULL if list is empty + */ + +static inline sys_dnode_t *sys_dlist_get(sys_dlist_t *list) +{ + sys_dnode_t *node; + + if (sys_dlist_is_empty(list)) { + return NULL; + } + + node = list->head; + sys_dlist_remove(node); + return node; +} + +#endif /* _misc_dlist__h_ */ diff --git a/misc/Makefile b/misc/Makefile index 20940330c4b..dc6d1ebd900 100644 --- a/misc/Makefile +++ b/misc/Makefile @@ -1,3 +1,3 @@ -obj-y = dlist.o +obj-y = obj-$(CONFIG_PRINTK) += printk.o obj-y += generated/ diff --git a/misc/dlist.c b/misc/dlist.c deleted file mode 100644 index 650f977d9f8..00000000000 --- a/misc/dlist.c +++ /dev/null @@ -1,109 +0,0 @@ -/* dlist.c - doubly linked list routines */ - -/* - * Copyright (c) 2013-2014 Wind River Systems, Inc. - * - * 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. - * - * 3) Neither the name of Wind River Systems nor the names of its contributors - * may be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * 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. - */ - -/* -DESCRIPTION -This module implements various routines for manipulating linked lists. -The lists are expected to be initialized such that both the head and tail -pointers point to the list itself. Initializing the lists in such a fashion -simplifies the adding and removing of nodes to/from the list. - -\NOMANUAL -*/ - -#include -#include - -/******************************************************************************* -* -* dlistAdd - add node to tail of list -* -* This routine adds a node to the tail of the specified list. It is assumed -* that the node is not part of any linked list before this routine is called. -* -* RETURNS: N/A -*/ - -void dlistAdd( - dlist_t *pList, /* pointer to list to which to append node */ - dnode_t *pNode /* pointer to node to append */ - ) -{ - pNode->next = pList; - pNode->prev = pList->tail; - - pList->tail->next = pNode; - pList->tail = pNode; -} - -/******************************************************************************* -* -* dlistRemove - remove a node from the list -* -* This routine removes a node from the list on which it resides. An explicit -* pointer to the list is not required due to the way the node and list are -* structured and initialized. -* -* RETURNS: N/A -*/ - -void dlistRemove(dnode_t *pNode /* pointer to node to remove */ - ) -{ - pNode->prev->next = pNode->next; - pNode->next->prev = pNode->prev; -} - -/******************************************************************************* -* -* dlistGet - get the node from the head of the list -* -* This routine removes the node from the head of the list and then returns -* a pointer to it. -* -* RETURNS: pointer to node -*/ - -dnode_t *dlistGet( - dlist_t *pList /* pointer to list from which to get the item */ - ) -{ - dnode_t *pNode = pList->head; - - if (pNode == pList) { - return NULL; - } - - dlistRemove(pNode); /* remove from */ - - return pNode; -}