1 /* SPDX-License-Identifier: BSD-3-Clause
2  *
3  * Copyright(c) 2016 Intel Corporation. All rights reserved.
4  *
5  * Author: Liam Girdwood <liam.r.girdwood@linux.intel.com>
6  *         Keyon Jie <yang.jie@linux.intel.com>
7  */
8 
9 #ifndef __SOF_LIST_H__
10 #define __SOF_LIST_H__
11 
12 /* Really simple list manipulation */
13 
14 struct list_item;
15 
16 struct list_item {
17 	struct list_item *next;
18 	struct list_item *prev;
19 };
20 
21 /* a static list head initialiser */
22 #define LIST_INIT(head) {&head, &head}
23 
24 /* initialise list before any use - list will point to itself */
list_init(struct list_item * list)25 static inline void list_init(struct list_item *list)
26 {
27 	list->next = list;
28 	list->prev = list;
29 }
30 
31 /* add new item to the start or head of the list */
list_item_prepend(struct list_item * item,struct list_item * list)32 static inline void list_item_prepend(struct list_item *item,
33 	struct list_item *list)
34 {
35 	struct list_item *next = list->next;
36 
37 	next->prev = item;
38 	item->next = next;
39 	item->prev = list;
40 	list->next = item;
41 }
42 
43 /* add new item to the end or tail of the list */
list_item_append(struct list_item * item,struct list_item * list)44 static inline void list_item_append(struct list_item *item,
45 	struct list_item *list)
46 {
47 	struct list_item *tail = list->prev;
48 
49 	tail->next = item;
50 	item->next = list;
51 	item->prev = tail;
52 	list->prev = item;
53 }
54 
55 /* delete item from the list leaves deleted list item
56  *in undefined state list_is_empty will return true
57  */
list_item_del(struct list_item * item)58 static inline void list_item_del(struct list_item *item)
59 {
60 	item->next->prev = item->prev;
61 	item->prev->next = item->next;
62 	list_init(item);
63 }
64 
65 /* is list item the last item in list ? */
list_item_is_last(struct list_item * item,struct list_item * list)66 static inline int list_item_is_last(struct list_item *item,
67 				struct list_item *list)
68 {
69 	return item->next == list;
70 }
71 
72 /* is list empty ? */
73 #define list_is_empty(item) \
74 	((item)->next == item)
75 
76 #define __list_object(item, type, offset) \
77 	((type *)((char *)(item) - (offset)))
78 
79 /* get the container object of the list item */
80 #define list_item(item, type, member) \
81 	__list_object(item, type, offsetof(type, member))
82 
83 /* get the container object of the first item in the list */
84 #define list_first_item(list, type, member) \
85 	__list_object((list)->next, type, offsetof(type, member))
86 
87 /* get the next container object in the list */
88 #define list_next_item(object, member) \
89 	list_item((object)->member.next, typeof(*(object)), member)
90 
91 /* list iterator */
92 #define list_for_item(item, list) \
93 	for (item = (list)->next; item != (list); item = item->next)
94 
95 /* list iterator */
96 #define list_for_item_prev(item, list) \
97 	for (item = (list)->prev; item != (list); item = item->prev)
98 
99 /* list iterator - safe to delete items */
100 #define list_for_item_safe(item, tmp, list) \
101 	for (item = (list)->next, tmp = item->next;\
102 		item != (list); \
103 		item = tmp, tmp = item->next)
104 
105 /**
106  * Re-links the list when head address changed (list moved).
107  * @param new_list New address of the head.
108  * @param old_list Old address of the head.
109  */
list_relink(struct list_item * new_list,struct list_item * old_list)110 static inline void list_relink(struct list_item *new_list,
111 			       struct list_item *old_list)
112 {
113 	struct list_item *li;
114 
115 	if (new_list->next == old_list) {
116 		list_init(new_list);
117 	} else {
118 		list_for_item(li, new_list)
119 			if (li->next == old_list)
120 				li->next = new_list; /* for stops here */
121 		list_for_item_prev(li, new_list)
122 			if (li->prev == old_list)
123 				li->prev = new_list; /* for stops here */
124 	}
125 }
126 
127 #endif /* __SOF_LIST_H__ */
128