librnr  1.14.5
RoadNarrows Robotics Common Library 1
dlist.h
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////////////
2 /*! \file
3  *
4  * \brief Doubly linked list base implementation.
5  *
6  * The dlists are intended to be embedded within the parent structure of
7  * a specific type. Higher level constructs using the dlist base can build
8  * implementations doubly-linked lists, queues, stacks, circular buffers,
9  * and binary trees with data of any type.
10  *
11  * Some of the internal functions ("_dlist_xxx") are useful when manipulating
12  * whole lists rather than single entries, as sometimes we already know the
13  * next/prev entries and we can generate better code by using them directly
14  * rather than using the generic single-entry routines.
15  *
16  * This file has been modified from the original source (see below).
17  *
18  * \pkgsynopsis
19  * RoadNarrows Robotics Common Library 1
20  *
21  * \pkgcomponent{Library}
22  * librnr
23  *
24  * \pkgfile{rnr/dlist.h}
25  *
26  * \author Robin Knight (robin.knight@roadnarrows.com)
27  *
28  * \pkgcopyright{2005-2018,RoadNarrows LLC.,http://www.roadnarrows.com}
29  *
30  * \license{MIT}
31  *
32  * \EulaBegin
33  * See the README and EULA files for any copyright and licensing information.
34  * \EulaEnd
35  *
36  * <hr>
37  * \par Original Source and Copyright
38  *
39  * \par Original Author
40  * Linux 2.6
41  *
42  * \par Original Source Header
43  * Linux header file <linux/list.h>
44  *
45  * <hr>
46  */
47 ////////////////////////////////////////////////////////////////////////////////
48 
49 #ifndef _RNR_DLIST_H
50 #define _RNR_DLIST_H
51 
53 
54 /*!
55  * \brief The doubly linked node structure
56  */
57 typedef struct dlist_node
58 {
59  struct dlist_node *next; ///< next node in dlist
60  struct dlist_node *prev; ///< previous node in dlist
61 } dnode_t;
62 
63 
64 /*!
65  * \brief Initialize node links (pointer version).
66  * \param pnode pointer to dnode_t
67  */
68 #define DLIST_PNODE_INIT_DATA(pnode) (pnode)->next = (pnode)->prev = pnode
69 
70 /*!
71  * \brief Initialize node links.
72  * \param node dnode_t
73  */
74 #define DLIST_NODE_INIT(node) DLIST_PNODE_INIT_DATA(&(node))
75 
76 /*!
77  * \brief Initialize node links (pointer version).
78  * \param pnode pointer to dnode_t
79  */
80 #define DLIST_PNODE_INIT(pnode) DLIST_PNODE_INIT_DATA(pnode)
81 
82 /*!
83  * \brief insert a new entry between two known consecutive entries
84  *
85  * \param node the new node to be inserted
86  * \param prev previous node to new node
87  * \param next next node to new node
88  *
89  * \note This is only for internal list manipulation where we know the prev/next
90  * entries already!
91  */
92 static inline void _dlist_add(dnode_t *node, dnode_t *prev, dnode_t *next)
93 {
94  next->prev = node;
95  node->next = next;
96  node->prev = prev;
97  prev->next = node;
98 }
99 
100 /*!
101  * \brief prepend new node to head of list
102  *
103  * Insert a new node after the specified head. This is good for implementing
104  * stacks.
105  *
106  * \param node the new node to be inserted at head of the list
107  * \param head list head
108  */
109 static inline void dlist_prepend(dnode_t *node, dnode_t *head)
110 {
111  _dlist_add(node, head, head->next);
112 }
113 
114 /*!
115  * \brief append a new node to the in of the list
116  *
117  * Insert a new node before the specified head. This is useful for implementing
118  * queues.
119  *
120  * \param node the new node to be inserted at end of the list
121  * \param head list head
122  */
123 static inline void dlist_append(dnode_t *node, dnode_t *head)
124 {
125  _dlist_add(node, head->prev, head);
126 }
127 
128 /*!
129  * \brief delete the node(s) between the prev/next nodes.
130  *
131  * \param prev previous node to link to next
132  * \param next next node to link with previous
133  *
134  * \note This is only for internal list manipulation where we know the prev/next
135  * entries already!
136  */
137 static inline void _dlist_del(dnode_t *prev, dnode_t *next)
138 {
139  next->prev = prev;
140  prev->next = next;
141 }
142 
143 /*!
144  * \brief deletes node from list
145  *
146  * \param node the node to delete from the list.
147  *
148  * Note: Deleted node becomes an orphan (i.e. empty) head node.
149  */
150 static inline void dlist_delete(dnode_t *node)
151 {
152  _dlist_del(node->prev, node->next);
153  DLIST_PNODE_INIT(node);
154 }
155 
156 /*!
157  * \brief tests whether a list is empty
158  *
159  * \param head list head
160  *
161  * \return non-zero if empty, 0 otherwise
162  */
163 static inline int dlist_is_empty(dnode_t *head)
164 {
165  return head->next == head;
166 }
167 
168 /*!
169  * \brief prepend new list at head of given list
170  *
171  * \param list the new list to add
172  * \param head list head holding newly spliced lists
173  *
174  * \note The list prev/next pointers are not altered so it is still a valid
175  * list.
176  */
177 static inline void dlist_splice(dnode_t *list, dnode_t *head)
178 {
179  if( !dlist_is_empty(list) )
180  {
181  dnode_t *first = list->next;
182  dnode_t *last = list->prev;
183  dnode_t *at = head->next;
184 
185  first->prev = head;
186  head->next = first;
187 
188  last->next = at;
189  at->prev = last;
190  }
191 }
192 
193 /*!
194  * \brief get the pointer to the embedding struct for ptr
195  *
196  * \param ptr the &dnode_t pointer.
197  * \param type the name of the struct the dnode_t is embedded in.
198  * \param member the name of the member in type that is the dnode_t.
199  *
200  * \return pointer to embedding structure
201  */
202 #define dlist_entry(ptr, type, member) \
203  ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member)))
204 
205 /*!
206  * \brief iterate over a list
207  *
208  * \param pos the dnode_t pointer to use as a loop counter
209  * \param head the head of list to iterate over
210  */
211 #define dlist_for_each(pos, head) \
212  for(pos = (head)->next; pos != (head); pos = pos->next)
213 
214 /*!
215  * \brief safely iterate over a list
216  *
217  * \param pos the dnode_t pointer to be use as a loop counter
218  * \param npos another dnode_t pointer to use as temporary storage
219  * \param head the head of list to iterate over
220  *
221  * \note (Somewhat) safe against removal of list entry. That is, node pos can
222  * be deleted, etc and this interator still works. However, this (or the
223  * above interator) are not thread safe.
224  */
225 #define dlist_for_each_safe(pos, npos, head) \
226  for(pos = (head)->next, npos = pos->next; pos != (head); \
227  pos = npos, npos = pos->next)
228 
230 
231 
232 #endif // _RNR_DLIST_H
static void dlist_prepend(dnode_t *node, dnode_t *head)
prepend new node to head of list
Definition: dlist.h:109
The doubly linked node structure.
Definition: dlist.h:57
static void dlist_delete(dnode_t *node)
deletes node from list
Definition: dlist.h:150
#define DLIST_PNODE_INIT(pnode)
Initialize node links (pointer version).
Definition: dlist.h:80
#define C_DECLS_BEGIN
C declaration block begin in C.
Definition: rnrconfig.h:71
static void dlist_append(dnode_t *node, dnode_t *head)
append a new node to the in of the list
Definition: dlist.h:123
struct dlist_node * next
next node in dlist
Definition: dlist.h:59
static void dlist_splice(dnode_t *list, dnode_t *head)
prepend new list at head of given list
Definition: dlist.h:177
struct dlist_node * prev
previous node in dlist
Definition: dlist.h:60
#define C_DECLS_END
C declaration block end in C.
Definition: rnrconfig.h:72
static void _dlist_add(dnode_t *node, dnode_t *prev, dnode_t *next)
insert a new entry between two known consecutive entries
Definition: dlist.h:92
static int dlist_is_empty(dnode_t *head)
tests whether a list is empty
Definition: dlist.h:163
static void _dlist_del(dnode_t *prev, dnode_t *next)
delete the node(s) between the prev/next nodes.
Definition: dlist.h:137
struct dlist_node dnode_t
The doubly linked node structure.