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 <benjamin.walsh@windriver.com>
This commit is contained in:
Benjamin Walsh 2015-06-14 12:15:05 -04:00 committed by Anas Nashif
commit ca51a72133
3 changed files with 257 additions and 127 deletions

View file

@ -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 <stddef.h>
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_ */

View file

@ -1,3 +1,3 @@
obj-y = dlist.o
obj-y =
obj-$(CONFIG_PRINTK) += printk.o
obj-y += generated/

View file

@ -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 <stddef.h>
#include <misc/dlist.h>
/*******************************************************************************
*
* 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 <pList> */
return pNode;
}