ChibiOS  21.6.0
chlists.h
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006,2007,2008,2009,2010,2011,2012,2013,2014,
3  2015,2016,2017,2018,2019,2020,2021 Giovanni Di Sirio.
4 
5  This file is part of ChibiOS.
6 
7  ChibiOS is free software; you can redistribute it and/or modify
8  it under the terms of the GNU General Public License as published by
9  the Free Software Foundation version 3 of the License.
10 
11  ChibiOS is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19 
20 /**
21  * @file chlists.h
22  * @brief Lists and Queues header.
23  *
24  * @addtogroup os_lists
25  * @{
26  */
27 
28 #ifndef CHLISTS_H
29 #define CHLISTS_H
30 
31 /*===========================================================================*/
32 /* Module constants. */
33 /*===========================================================================*/
34 
35 /*===========================================================================*/
36 /* Module pre-compile time settings. */
37 /*===========================================================================*/
38 
39 /*===========================================================================*/
40 /* Derived constants and error checks. */
41 /*===========================================================================*/
42 
43 /*===========================================================================*/
44 /* Module data structures and types. */
45 /*===========================================================================*/
46 
47 /**
48  * @brief Type of a generic single link list header and element.
49  */
50 typedef struct ch_list ch_list_t;
51 
52 /**
53  * @brief Structure representing a generic single link list header
54  * and element.
55  */
56 struct ch_list {
57  ch_list_t *next; /**< @brief Next in the list/queue. */
58 };
59 
60 /**
61  * @brief Type of a generic bidirectional linked list header and element.
62  */
63 typedef struct ch_queue ch_queue_t;
64 
65 /**
66  * @brief Structure representing a generic bidirectional linked list header
67  * and element.
68  */
69 struct ch_queue {
70  ch_queue_t *next; /**< @brief Next in the list/queue. */
71  ch_queue_t *prev; /**< @brief Previous in the queue. */
72 };
73 
74 /**
75  * @brief Type of a generic priority-ordered bidirectional linked list
76  * header and element.
77  */
79 
80 /**
81  * @brief Structure representing a generic priority-ordered bidirectional
82  * linked list header and element.
83  * @note Link fields are void pointers in order to avoid aliasing issues.
84  */
86  ch_priority_queue_t *next; /**< @brief Next in the queue. */
87  ch_priority_queue_t *prev; /**< @brief Previous in the queue. */
88  tprio_t prio; /**< @brief Priority of this element. */
89 };
90 
91 /**
92  * @brief Type of a generic bidirectional linked delta list
93  * header and element.
94  */
96 
97 /**
98  * @brief Delta list element and header structure.
99  */
101  ch_delta_list_t *next; /**< @brief Next in the delta list. */
102  ch_delta_list_t *prev; /**< @brief Previous in the delta list. */
103  sysinterval_t delta; /**< @brief Time interval from previous.*/
104 };
105 
106 /*===========================================================================*/
107 /* Module macros. */
108 /*===========================================================================*/
109 
110 /**
111  * @brief Data part of a static queue object initializer.
112  * @details This macro should be used when statically initializing a
113  * queue that is part of a bigger structure.
114  *
115  * @param[in] name the name of the queue variable
116  */
117 #define __CH_QUEUE_DATA(name) {(ch_queue_t *)&name, (ch_queue_t *)&name}
118 
119 /**
120  * @brief Static queue object initializer.
121  * @details Statically initialized queues require no explicit
122  * initialization using @p queue_init().
123  *
124  * @param[in] name the name of the queue variable
125  */
126 #define CH_QUEUE_DECL(name) \
127  ch_queue_t name = __CH_QUEUE_DATA(name)
128 
129 /*===========================================================================*/
130 /* External declarations. */
131 /*===========================================================================*/
132 
133 /* Early function prototypes required by the following headers.*/
134 #ifdef __cplusplus
135 extern "C" {
136 #endif
137 
138 #ifdef __cplusplus
139 }
140 #endif
141 
142 /*===========================================================================*/
143 /* Module inline functions. */
144 /*===========================================================================*/
145 
146 /**
147  * @brief List initialization.
148  *
149  * @param[out] lp pointer to the list header
150  *
151  * @notapi
152  */
153 static inline void ch_list_init(ch_list_t *lp) {
154 
155  lp->next = lp;
156 }
157 
158 /**
159  * @brief Evaluates to @p true if the specified list is empty.
160  *
161  * @param[in] lp pointer to the list header
162  * @return The status of the list.
163  *
164  * @notapi
165  */
166 static inline bool ch_list_isempty(ch_list_t *lp) {
167 
168  return (bool)(lp->next == lp);
169 }
170 
171 /**
172  * @brief Evaluates to @p true if the specified list is not empty.
173  *
174  * @param[in] lp pointer to the list header
175  * @return The status of the list.
176  *
177  * @notapi
178  */
179 static inline bool ch_list_notempty(ch_list_t *lp) {
180 
181  return (bool)(lp->next != lp);
182 }
183 
184 /**
185  * @brief Pushes an element on top of a stack list.
186  *
187  * @param[in] lp the pointer to the list header
188  * @param[in] p the pointer to the element to be inserted in the list
189  *
190  * @notapi
191  */
192 static inline void ch_list_link(ch_list_t *lp, ch_list_t *p) {
193 
194  p->next = lp->next;
195  lp->next = p;
196 }
197 
198 /**
199  * @brief Pops an element from the top of a stack list and returns it.
200  * @pre The list must be non-empty before calling this function.
201  *
202  * @param[in] lp the pointer to the list header
203  * @return The removed element pointer.
204  *
205  * @notapi
206  */
207 static inline ch_list_t *ch_list_unlink(ch_list_t *lp) {
208 
209  ch_list_t *p = lp->next;
210  lp->next = p->next;
211 
212  return p;
213 }
214 
215 /**
216  * @brief Queue initialization.
217  *
218  * @param[out] qp pointer to the queue header
219  *
220  * @notapi
221  */
222 static inline void ch_queue_init(ch_queue_t *qp) {
223 
224  qp->next = qp;
225  qp->prev = qp;
226 }
227 
228 /**
229  * @brief Evaluates to @p true if the specified queue is empty.
230  *
231  * @param[in] qp pointer to the queue header
232  * @return The status of the queue.
233  *
234  * @notapi
235  */
236 static inline bool ch_queue_isempty(const ch_queue_t *qp) {
237 
238  return (bool)(qp->next == qp);
239 }
240 
241 /**
242  * @brief Evaluates to @p true if the specified queue is not empty.
243  *
244  * @param[in] qp pointer to the queue header
245  * @return The status of the queue.
246  *
247  * @notapi
248  */
249 static inline bool ch_queue_notempty(const ch_queue_t *qp) {
250 
251  return (bool)(qp->next != qp);
252 }
253 
254 /**
255  * @brief Inserts an element into a queue.
256  *
257  * @param[in] qp the pointer to the queue header
258  * @param[in] p the pointer to the element to be inserted in the queue
259  *
260  * @notapi
261  */
262 static inline void ch_queue_insert(ch_queue_t *qp, ch_queue_t *p) {
263 
264  p->next = qp;
265  p->prev = qp->prev;
266  p->prev->next = p;
267  qp->prev = p;
268 }
269 
270 /**
271  * @brief Removes the first-out element from a queue and returns it.
272  * @note If the queue is priority ordered then this function returns the
273  * element with the highest priority.
274  *
275  * @param[in] qp the pointer to the queue list header
276  * @return The removed element pointer.
277  *
278  * @notapi
279  */
281  ch_queue_t *p = qp->next;
282 
283  qp->next = p->next;
284  qp->next->prev = qp;
285 
286  return p;
287 }
288 
289 /**
290  * @brief Removes the last-out element from a queue and returns it.
291  * @note If the queue is priority ordered then this function returns the
292  * element with the lowest priority.
293  *
294  * @param[in] qp the pointer to the queue list header
295  * @return The removed element pointer.
296  *
297  * @notapi
298  */
300  ch_queue_t *p = qp->prev;
301 
302  qp->prev = p->prev;
303  qp->prev->next = qp;
304 
305  return p;
306 }
307 
308 /**
309  * @brief Removes an element from a queue and returns it.
310  * @details The element is removed from the queue regardless of its relative
311  * position and regardless the used insertion method.
312  *
313  * @param[in] p the pointer to the element to be removed from the queue
314  * @return The removed element pointer.
315  *
316  * @notapi
317  */
319 
320  p->prev->next = p->next;
321  p->next->prev = p->prev;
322 
323  return p;
324 }
325 
326 /**
327  * @brief Priority queue initialization.
328  * @note The queue header priority is initialized to zero, all other
329  * elements in the queue are assumed to have priority greater
330  * than zero.
331  *
332  * @param[out] pqp pointer to the priority queue header
333  *
334  * @notapi
335  */
336 static inline void ch_pqueue_init(ch_priority_queue_t *pqp) {
337 
338  pqp->next = pqp;
339  pqp->prev = pqp;
340  pqp->prio = (tprio_t)0;
341 }
342 
343 /**
344  * @brief Removes the highest priority element from a priority queue and
345  * returns it.
346  *
347  * @param[in] pqp the pointer to the priority queue list header
348  * @return The removed element pointer.
349  *
350  * @notapi
351  */
353  ch_priority_queue_t *p = pqp->next;
354 
355  pqp->next = p->next;
356  pqp->next->prev = pqp;
357 
358  return p;
359 }
360 
361 /**
362  * @brief Inserts an element in the priority queue placing it behind
363  * its peers.
364  * @details The element is positioned behind all elements with higher or
365  * equal priority.
366  *
367  * @param[in] pqp the pointer to the priority queue list header
368  * @param[in] p the pointer to the element to be inserted in the queue
369  * @return The inserted element pointer.
370  *
371  * @notapi
372  */
374  ch_priority_queue_t *p) {
375 
376  /* Scanning priority queue, the list is assumed to be mostly empty.*/
377  do {
378  pqp = pqp->next;
379  } while (unlikely(pqp->prio >= p->prio));
380 
381  /* Insertion on prev.*/
382  p->next = pqp;
383  p->prev = pqp->prev;
384  p->prev->next = p;
385  pqp->prev = p;
386 
387  return p;
388 }
389 
390 /**
391  * @brief Inserts an element in the priority queue placing it ahead of
392  * its peers.
393  * @details The element is positioned ahead of all elements with higher or
394  * equal priority.
395  *
396  * @param[in] pqp the pointer to the priority queue list header
397  * @param[in] p the pointer to the element to be inserted in the queue
398  * @return The inserted element pointer.
399  *
400  * @notapi
401  */
403  ch_priority_queue_t *p) {
404 
405  /* Scanning priority queue, the list is assumed to be mostly empty.*/
406  do {
407  pqp = pqp->next;
408  } while (unlikely(pqp->prio > p->prio));
409 
410  /* Insertion on prev.*/
411  p->next = pqp;
412  p->prev = pqp->prev;
413  p->prev->next = p;
414  pqp->prev = p;
415 
416  return p;
417 }
418 
419 /**
420  * @brief Delta list initialization.
421  *
422  * @param[out] dlhp pointer to the delta list header
423  *
424  * @notapi
425  */
426 static inline void ch_dlist_init(ch_delta_list_t *dlhp) {
427 
428  dlhp->next = dlhp;
429  dlhp->prev = dlhp;
430  dlhp->delta = (sysinterval_t)-1;
431 }
432 
433 /**
434  * @brief Evaluates to @p true if the specified delta list is empty.
435  *
436  * @param[in] dlhp pointer to the delta list header
437  * @return The status of the delta list.
438  *
439  * @notapi
440  */
441 static inline bool ch_dlist_isempty(ch_delta_list_t *dlhp) {
442 
443  return (bool)(dlhp == dlhp->next);
444 }
445 
446 /**
447  * @brief Evaluates to @p true if the specified queue is not empty.
448  *
449  * @param[in] dlhp pointer to the delta list header
450  * @return The status of the delta list.
451  *
452  * @notapi
453  */
454 static inline bool ch_dlist_notempty(ch_delta_list_t *dlhp) {
455 
456  return (bool)(dlhp != dlhp->next);
457 }
458 
459 /**
460  * @brief Last element in the delta list check.
461  *
462  * @param[in] dlhp pointer to the delta list header
463  * @param[in] dlp pointer to the delta list element
464  *
465  * @notapi
466  */
467 static inline bool ch_dlist_islast(ch_delta_list_t *dlhp,
468  ch_delta_list_t *dlp) {
469 
470  return (bool)(dlp->next == dlhp);
471 }
472 
473 /**
474  * @brief Fist element in the delta list check.
475  *
476  * @param[in] dlhp pointer to the delta list header
477  * @param[in] dlp pointer to the delta list element
478  *
479  * @notapi
480  */
481 static inline bool ch_dlist_isfirst(ch_delta_list_t *dlhp,
482  ch_delta_list_t *dlp) {
483 
484  return (bool)(dlhp->next == dlp);
485 }
486 
487 /**
488  * @brief Inserts an element after another header element.
489  *
490  * @param[in] dlhp pointer to the delta list header element
491  * @param[in] dlp element to be inserted after the header element
492  * @param[in] delta delta of the element to be inserted
493  *
494  * @notapi
495  */
496 static inline void ch_dlist_insert_after(ch_delta_list_t *dlhp,
497  ch_delta_list_t *dlp,
498  sysinterval_t delta) {
499 
500  dlp->delta = delta;
501  dlp->prev = dlhp;
502  dlp->next = dlp->prev->next;
503  dlp->next->prev = dlp;
504  dlhp->next = dlp;
505 }
506 
507 /**
508  * @brief Inserts an element before another header element.
509  *
510  * @param[in] dlhp pointer to the delta list header element
511  * @param[in] dlp element to be inserted before the header element
512  * @param[in] delta delta of the element to be inserted
513  *
514  * @notapi
515  */
516 static inline void ch_dlist_insert_before(ch_delta_list_t *dlhp,
517  ch_delta_list_t *dlp,
518  sysinterval_t delta) {
519 
520  dlp->delta = delta;
521  dlp->next = dlhp;
522  dlp->prev = dlp->next->prev;
523  dlp->prev->next = dlp;
524  dlhp->prev = dlp;
525 }
526 
527 /**
528  * @brief Inserts an element in a delta list.
529  *
530  * @param[in] dlhp pointer to the delta list header element
531  * @param[in] dlep element to be inserted before the header element
532  * @param[in] delta delta of the element to be inserted
533  *
534  * @notapi
535  */
536 static inline void ch_dlist_insert(ch_delta_list_t *dlhp,
537  ch_delta_list_t *dlep,
538  sysinterval_t delta) {
539  ch_delta_list_t *dlp;
540 
541  /* The delta list is scanned in order to find the correct position for
542  this element. */
543  dlp = dlhp->next;
544  while (likely(dlp->delta < delta)) {
545  /* Debug assert if the element is already in the list.*/
546  chDbgAssert(dlp != dlep, "element already in list");
547 
548  delta -= dlp->delta;
549  dlp = dlp->next;
550  }
551 
552  /* The timer is inserted in the delta list.*/
553  ch_dlist_insert_before(dlp, dlep, delta);
554 
555  /* Adjusting delta for the following element.*/
556  dlp->delta -= delta;
557 
558  /* Special case when the inserted element is in last position in the list,
559  the value in the header must be restored, just doing it is faster than
560  checking then doing.*/
561  dlhp->delta = (sysinterval_t)-1;
562 }
563 
564 /**
565  * @brief Dequeues an element from the delta list.
566  *
567  * @param[in] dlhp pointer to the delta list header
568  *
569  * @notapi
570  */
572  ch_delta_list_t *dlp = dlhp->next;
573 
574  dlhp->next = dlp->next;
575  dlhp->next->prev = dlhp;
576 
577  return dlp;
578 }
579 
580 /**
581  * @brief Dequeues an element from the delta list.
582  *
583  * @param[in] dlp pointer to the delta list element
584  *
585  * @notapi
586  */
588 
589  dlp->prev->next = dlp->next;
590  dlp->next->prev = dlp->prev;
591 
592  return dlp;
593 }
594 
595 #endif /* CHLISTS_H */
596 
597 /** @} */
tprio_t
uint32_t tprio_t
Definition: chearly.h:87
ch_queue::next
ch_queue_t * next
Next in the list/queue.
Definition: chlists.h:70
chDbgAssert
#define chDbgAssert(c, r)
Condition assertion.
Definition: chdebug.h:144
ch_list::next
ch_list_t * next
Next in the list/queue.
Definition: chlists.h:57
ch_dlist_islast
static bool ch_dlist_islast(ch_delta_list_t *dlhp, ch_delta_list_t *dlp)
Last element in the delta list check.
Definition: chlists.h:467
ch_queue_insert
static void ch_queue_insert(ch_queue_t *qp, ch_queue_t *p)
Inserts an element into a queue.
Definition: chlists.h:262
ch_queue_notempty
static bool ch_queue_notempty(const ch_queue_t *qp)
Evaluates to true if the specified queue is not empty.
Definition: chlists.h:249
ch_queue_isempty
static bool ch_queue_isempty(const ch_queue_t *qp)
Evaluates to true if the specified queue is empty.
Definition: chlists.h:236
ch_list_unlink
static ch_list_t * ch_list_unlink(ch_list_t *lp)
Pops an element from the top of a stack list and returns it.
Definition: chlists.h:207
ch_dlist_isempty
static bool ch_dlist_isempty(ch_delta_list_t *dlhp)
Evaluates to true if the specified delta list is empty.
Definition: chlists.h:441
ch_dlist_insert_before
static void ch_dlist_insert_before(ch_delta_list_t *dlhp, ch_delta_list_t *dlp, sysinterval_t delta)
Inserts an element before another header element.
Definition: chlists.h:516
ch_dlist_dequeue
static ch_delta_list_t * ch_dlist_dequeue(ch_delta_list_t *dlp)
Dequeues an element from the delta list.
Definition: chlists.h:587
ch_dlist_insert_after
static void ch_dlist_insert_after(ch_delta_list_t *dlhp, ch_delta_list_t *dlp, sysinterval_t delta)
Inserts an element after another header element.
Definition: chlists.h:496
likely
#define likely(x)
Marks a boolean expression as likely true.
Definition: chearly.h:178
ch_list_notempty
static bool ch_list_notempty(ch_list_t *lp)
Evaluates to true if the specified list is not empty.
Definition: chlists.h:179
ch_pqueue_insert_ahead
static ch_priority_queue_t * ch_pqueue_insert_ahead(ch_priority_queue_t *pqp, ch_priority_queue_t *p)
Inserts an element in the priority queue placing it ahead of its peers.
Definition: chlists.h:402
ch_delta_list::delta
sysinterval_t delta
Time interval from previous.
Definition: chlists.h:103
ch_queue_fifo_remove
static ch_queue_t * ch_queue_fifo_remove(ch_queue_t *qp)
Removes the first-out element from a queue and returns it.
Definition: chlists.h:280
ch_delta_list::next
ch_delta_list_t * next
Next in the delta list.
Definition: chlists.h:101
ch_pqueue_remove_highest
static ch_priority_queue_t * ch_pqueue_remove_highest(ch_priority_queue_t *pqp)
Removes the highest priority element from a priority queue and returns it.
Definition: chlists.h:352
ch_pqueue_insert_behind
static ch_priority_queue_t * ch_pqueue_insert_behind(ch_priority_queue_t *pqp, ch_priority_queue_t *p)
Inserts an element in the priority queue placing it behind its peers.
Definition: chlists.h:373
ch_queue
Structure representing a generic bidirectional linked list header and element.
Definition: chlists.h:69
ch_dlist_isfirst
static bool ch_dlist_isfirst(ch_delta_list_t *dlhp, ch_delta_list_t *dlp)
Fist element in the delta list check.
Definition: chlists.h:481
ch_queue_init
static void ch_queue_init(ch_queue_t *qp)
Queue initialization.
Definition: chlists.h:222
ch_queue_lifo_remove
static ch_queue_t * ch_queue_lifo_remove(ch_queue_t *qp)
Removes the last-out element from a queue and returns it.
Definition: chlists.h:299
ch_list_isempty
static bool ch_list_isempty(ch_list_t *lp)
Evaluates to true if the specified list is empty.
Definition: chlists.h:166
ch_dlist_notempty
static bool ch_dlist_notempty(ch_delta_list_t *dlhp)
Evaluates to true if the specified queue is not empty.
Definition: chlists.h:454
sysinterval_t
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
ch_pqueue_init
static void ch_pqueue_init(ch_priority_queue_t *pqp)
Priority queue initialization.
Definition: chlists.h:336
ch_priority_queue::next
ch_priority_queue_t * next
Next in the queue.
Definition: chlists.h:86
ch_list_link
static void ch_list_link(ch_list_t *lp, ch_list_t *p)
Pushes an element on top of a stack list.
Definition: chlists.h:192
ch_queue::prev
ch_queue_t * prev
Previous in the queue.
Definition: chlists.h:71
unlikely
#define unlikely(x)
Marks a boolean expression as likely false.
Definition: chearly.h:191
ch_delta_list::prev
ch_delta_list_t * prev
Previous in the delta list.
Definition: chlists.h:102
ch_priority_queue::prev
ch_priority_queue_t * prev
Previous in the queue.
Definition: chlists.h:87
ch_dlist_insert
static void ch_dlist_insert(ch_delta_list_t *dlhp, ch_delta_list_t *dlep, sysinterval_t delta)
Inserts an element in a delta list.
Definition: chlists.h:536
ch_queue_dequeue
static ch_queue_t * ch_queue_dequeue(ch_queue_t *p)
Removes an element from a queue and returns it.
Definition: chlists.h:318
ch_priority_queue::prio
tprio_t prio
Priority of this element.
Definition: chlists.h:88
ch_dlist_remove_first
static ch_delta_list_t * ch_dlist_remove_first(ch_delta_list_t *dlhp)
Dequeues an element from the delta list.
Definition: chlists.h:571
ch_list
Structure representing a generic single link list header and element.
Definition: chlists.h:56
ch_priority_queue
Structure representing a generic priority-ordered bidirectional linked list header and element.
Definition: chlists.h:85
ch_delta_list
Delta list element and header structure.
Definition: chlists.h:100
ch_dlist_init
static void ch_dlist_init(ch_delta_list_t *dlhp)
Delta list initialization.
Definition: chlists.h:426
ch_list_init
static void ch_list_init(ch_list_t *lp)
List initialization.
Definition: chlists.h:153