1ef270ab1SKenneth D. Merry /*-
2ef270ab1SKenneth D. Merry * Copyright (c) 2017 Broadcom. All rights reserved.
3ef270ab1SKenneth D. Merry * The term "Broadcom" refers to Broadcom Limited and/or its subsidiaries.
4ef270ab1SKenneth D. Merry *
5ef270ab1SKenneth D. Merry * Redistribution and use in source and binary forms, with or without
6ef270ab1SKenneth D. Merry * modification, are permitted provided that the following conditions are met:
7ef270ab1SKenneth D. Merry *
8ef270ab1SKenneth D. Merry * 1. Redistributions of source code must retain the above copyright notice,
9ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer.
10ef270ab1SKenneth D. Merry *
11ef270ab1SKenneth D. Merry * 2. Redistributions in binary form must reproduce the above copyright notice,
12ef270ab1SKenneth D. Merry * this list of conditions and the following disclaimer in the documentation
13ef270ab1SKenneth D. Merry * and/or other materials provided with the distribution.
14ef270ab1SKenneth D. Merry *
15ef270ab1SKenneth D. Merry * 3. Neither the name of the copyright holder nor the names of its contributors
16ef270ab1SKenneth D. Merry * may be used to endorse or promote products derived from this software
17ef270ab1SKenneth D. Merry * without specific prior written permission.
18ef270ab1SKenneth D. Merry *
19ef270ab1SKenneth D. Merry * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20ef270ab1SKenneth D. Merry * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21ef270ab1SKenneth D. Merry * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22ef270ab1SKenneth D. Merry * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23ef270ab1SKenneth D. Merry * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24ef270ab1SKenneth D. Merry * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25ef270ab1SKenneth D. Merry * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26ef270ab1SKenneth D. Merry * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27ef270ab1SKenneth D. Merry * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28ef270ab1SKenneth D. Merry * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29ef270ab1SKenneth D. Merry * POSSIBILITY OF SUCH DAMAGE.
30ef270ab1SKenneth D. Merry */
31ef270ab1SKenneth D. Merry
32ef270ab1SKenneth D. Merry /**
33ef270ab1SKenneth D. Merry * @file
34ef270ab1SKenneth D. Merry *
35ef270ab1SKenneth D. Merry * OCS linked list API
36ef270ab1SKenneth D. Merry *
37ef270ab1SKenneth D. Merry */
38ef270ab1SKenneth D. Merry
39ef270ab1SKenneth D. Merry #if !defined(__OCS_LIST_H__)
40ef270ab1SKenneth D. Merry #define __OCS_LIST_H__
41ef270ab1SKenneth D. Merry
42ef270ab1SKenneth D. Merry #define OCS_LIST_DEBUG
43ef270ab1SKenneth D. Merry
44ef270ab1SKenneth D. Merry #if defined(OCS_LIST_DEBUG)
45ef270ab1SKenneth D. Merry
46ef270ab1SKenneth D. Merry #define ocs_list_magic_decl uint32_t magic;
47ef270ab1SKenneth D. Merry #define OCS_LIST_LIST_MAGIC 0xcafe0000
48ef270ab1SKenneth D. Merry #define OCS_LIST_LINK_MAGIC 0xcafe0001
49ef270ab1SKenneth D. Merry #define ocs_list_set_list_magic list->magic = OCS_LIST_LIST_MAGIC
50ef270ab1SKenneth D. Merry #define ocs_list_set_link_magic list->magic = OCS_LIST_LINK_MAGIC
51ef270ab1SKenneth D. Merry
52ef270ab1SKenneth D. Merry #define ocs_list_assert(cond, ...) \
53ef270ab1SKenneth D. Merry if (!(cond)) { \
54ef270ab1SKenneth D. Merry return __VA_ARGS__; \
55ef270ab1SKenneth D. Merry }
56ef270ab1SKenneth D. Merry #else
57ef270ab1SKenneth D. Merry #define ocs_list_magic_decl
58ef270ab1SKenneth D. Merry #define ocs_list_assert(cond, ...)
59ef270ab1SKenneth D. Merry #define ocs_list_set_list_magic
60ef270ab1SKenneth D. Merry #define ocs_list_set_link_magic
61ef270ab1SKenneth D. Merry #endif
62ef270ab1SKenneth D. Merry
63ef270ab1SKenneth D. Merry /**
64ef270ab1SKenneth D. Merry * @brief list/link structure
65ef270ab1SKenneth D. Merry *
66ef270ab1SKenneth D. Merry * used for both the list object, and the link object(s). offset
67ef270ab1SKenneth D. Merry * is specified when the list is initialized; this implies that a list
68ef270ab1SKenneth D. Merry * will always point to objects of the same type. offset is not used
69ef270ab1SKenneth D. Merry * when ocs_list_t is used as a link (ocs_list_link_t).
70ef270ab1SKenneth D. Merry *
71ef270ab1SKenneth D. Merry */
72ef270ab1SKenneth D. Merry
73ef270ab1SKenneth D. Merry typedef struct ocs_list_s ocs_list_t;
74ef270ab1SKenneth D. Merry struct ocs_list_s {
75ef270ab1SKenneth D. Merry ocs_list_magic_decl /*<< used if debugging is enabled */
76ef270ab1SKenneth D. Merry ocs_list_t *next; /*<< pointer to head of list (or next if link) */
77ef270ab1SKenneth D. Merry ocs_list_t *prev; /*<< pointer to tail of list (or previous if link) */
78ef270ab1SKenneth D. Merry uint32_t offset; /*<< offset in bytes to the link element of the objects in list */
79ef270ab1SKenneth D. Merry };
80ef270ab1SKenneth D. Merry typedef ocs_list_t ocs_list_link_t;
81ef270ab1SKenneth D. Merry
82ef270ab1SKenneth D. Merry /* item2link - return pointer to link given pointer to an item */
83ef270ab1SKenneth D. Merry #define item2link(list, item) ((ocs_list_t*) (((uint8_t*)(item)) + (list)->offset))
84ef270ab1SKenneth D. Merry
85ef270ab1SKenneth D. Merry /* link2item - return pointer to item given pointer to a link */
86ef270ab1SKenneth D. Merry #define link2item(list, link) ((void*) (((uint8_t*)(link)) - (list)->offset))
87ef270ab1SKenneth D. Merry
88ef270ab1SKenneth D. Merry /**
89ef270ab1SKenneth D. Merry * @brief Initialize a list
90ef270ab1SKenneth D. Merry *
91ef270ab1SKenneth D. Merry * A list object is initialized. Helper define is used to call _ocs_list_init() with
92ef270ab1SKenneth D. Merry * offsetof(type, link)
93ef270ab1SKenneth D. Merry *
94ef270ab1SKenneth D. Merry * @param list Pointer to list
95ef270ab1SKenneth D. Merry * @param offset Offset in bytes in item to the link element
96ef270ab1SKenneth D. Merry *
97ef270ab1SKenneth D. Merry * @return none
98ef270ab1SKenneth D. Merry */
99ef270ab1SKenneth D. Merry static inline void
_ocs_list_init(ocs_list_t * list,uint32_t offset)100ef270ab1SKenneth D. Merry _ocs_list_init(ocs_list_t *list, uint32_t offset)
101ef270ab1SKenneth D. Merry {
102ef270ab1SKenneth D. Merry ocs_list_assert(list);
103ef270ab1SKenneth D. Merry ocs_list_set_list_magic;
104ef270ab1SKenneth D. Merry
105ef270ab1SKenneth D. Merry list->next = list;
106ef270ab1SKenneth D. Merry list->prev = list;
107ef270ab1SKenneth D. Merry list->offset = offset;
108ef270ab1SKenneth D. Merry }
109ef270ab1SKenneth D. Merry #define ocs_list_init(head, type, link) _ocs_list_init(head, offsetof(type, link))
110ef270ab1SKenneth D. Merry
111ef270ab1SKenneth D. Merry /**
112ef270ab1SKenneth D. Merry * @ingroup os
113ef270ab1SKenneth D. Merry * @brief Test if a list is empty
114ef270ab1SKenneth D. Merry *
115ef270ab1SKenneth D. Merry * @param list Pointer to list head
116ef270ab1SKenneth D. Merry *
117ef270ab1SKenneth D. Merry * @return 1 if empty, 0 otherwise
118ef270ab1SKenneth D. Merry */
119ef270ab1SKenneth D. Merry static inline int32_t
ocs_list_empty(ocs_list_t * list)120ef270ab1SKenneth D. Merry ocs_list_empty(ocs_list_t *list)
121ef270ab1SKenneth D. Merry {
122ef270ab1SKenneth D. Merry ocs_list_assert(list, 1);
123ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, 1);
124ef270ab1SKenneth D. Merry return list->next == list;
125ef270ab1SKenneth D. Merry }
126ef270ab1SKenneth D. Merry
127ef270ab1SKenneth D. Merry /**
128ef270ab1SKenneth D. Merry * @ingroup os
129ef270ab1SKenneth D. Merry * @brief Test if a list is valid (ready for use)
130ef270ab1SKenneth D. Merry *
131ef270ab1SKenneth D. Merry * @param list Pointer to list head
132ef270ab1SKenneth D. Merry *
133ef270ab1SKenneth D. Merry * @return true if list is usable, false otherwise
134ef270ab1SKenneth D. Merry */
135ef270ab1SKenneth D. Merry static inline int
ocs_list_valid(ocs_list_t * list)136ef270ab1SKenneth D. Merry ocs_list_valid(ocs_list_t *list)
137ef270ab1SKenneth D. Merry {
138ef270ab1SKenneth D. Merry return (list->magic == OCS_LIST_LIST_MAGIC);
139ef270ab1SKenneth D. Merry }
140ef270ab1SKenneth D. Merry
141ef270ab1SKenneth D. Merry /**
142ef270ab1SKenneth D. Merry * @brief Insert link between two other links
143ef270ab1SKenneth D. Merry *
144ef270ab1SKenneth D. Merry * Inserts a link in between two other links
145ef270ab1SKenneth D. Merry *
146ef270ab1SKenneth D. Merry * @param a Pointer to first link
147ef270ab1SKenneth D. Merry * @param b Pointer to next link
148ef270ab1SKenneth D. Merry * @param c Pointer to link to insert between a and b
149ef270ab1SKenneth D. Merry *
150ef270ab1SKenneth D. Merry * @return none
151ef270ab1SKenneth D. Merry */
152ef270ab1SKenneth D. Merry static inline void
_ocs_list_insert_link(ocs_list_t * a,ocs_list_t * b,ocs_list_t * c)153ef270ab1SKenneth D. Merry _ocs_list_insert_link(ocs_list_t *a, ocs_list_t *b, ocs_list_t *c)
154ef270ab1SKenneth D. Merry {
155ef270ab1SKenneth D. Merry ocs_list_assert(a);
156ef270ab1SKenneth D. Merry ocs_list_assert((a->magic == OCS_LIST_LIST_MAGIC) || (a->magic == OCS_LIST_LINK_MAGIC));
157ef270ab1SKenneth D. Merry ocs_list_assert(a->next);
158ef270ab1SKenneth D. Merry ocs_list_assert(a->prev);
159ef270ab1SKenneth D. Merry ocs_list_assert(b);
160ef270ab1SKenneth D. Merry ocs_list_assert((b->magic == OCS_LIST_LIST_MAGIC) || (b->magic == OCS_LIST_LINK_MAGIC));
161ef270ab1SKenneth D. Merry ocs_list_assert(b->next);
162ef270ab1SKenneth D. Merry ocs_list_assert(b->prev);
163ef270ab1SKenneth D. Merry ocs_list_assert(c);
164ef270ab1SKenneth D. Merry ocs_list_assert((c->magic == OCS_LIST_LIST_MAGIC) || (c->magic == OCS_LIST_LINK_MAGIC));
165ef270ab1SKenneth D. Merry ocs_list_assert(!c->next);
166ef270ab1SKenneth D. Merry ocs_list_assert(!c->prev);
167ef270ab1SKenneth D. Merry
168ef270ab1SKenneth D. Merry ocs_list_assert(a->offset == b->offset);
169ef270ab1SKenneth D. Merry ocs_list_assert(b->offset == c->offset);
170ef270ab1SKenneth D. Merry
171ef270ab1SKenneth D. Merry c->next = a->next;
172ef270ab1SKenneth D. Merry c->prev = b->prev;
173ef270ab1SKenneth D. Merry a->next = c;
174ef270ab1SKenneth D. Merry b->prev = c;
175ef270ab1SKenneth D. Merry }
176ef270ab1SKenneth D. Merry
177ef270ab1SKenneth D. Merry #if defined(OCS_LIST_DEBUG)
178ef270ab1SKenneth D. Merry /**
179ef270ab1SKenneth D. Merry * @brief Initialize a list link for debug purposes
180ef270ab1SKenneth D. Merry *
181ef270ab1SKenneth D. Merry * For debugging a linked list link element has a magic number that is initialized,
182*cededdffSGordon Bergling * and the offset value initialized and used for subsequent assertions.
183ef270ab1SKenneth D. Merry *
184ef270ab1SKenneth D. Merry *
185ef270ab1SKenneth D. Merry * @param list Pointer to list head
186ef270ab1SKenneth D. Merry * @param link Pointer to link to be initialized
187ef270ab1SKenneth D. Merry *
188ef270ab1SKenneth D. Merry * @return none
189ef270ab1SKenneth D. Merry */
190ef270ab1SKenneth D. Merry static inline void
ocs_list_init_link(ocs_list_t * list,ocs_list_t * link)191ef270ab1SKenneth D. Merry ocs_list_init_link(ocs_list_t *list, ocs_list_t *link)
192ef270ab1SKenneth D. Merry {
193ef270ab1SKenneth D. Merry ocs_list_assert(list);
194ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
195ef270ab1SKenneth D. Merry ocs_list_assert(link);
196ef270ab1SKenneth D. Merry
197ef270ab1SKenneth D. Merry if (link->magic == 0) {
198ef270ab1SKenneth D. Merry link->magic = OCS_LIST_LINK_MAGIC;
199ef270ab1SKenneth D. Merry link->offset = list->offset;
200ef270ab1SKenneth D. Merry link->next = NULL;
201ef270ab1SKenneth D. Merry link->prev = NULL;
202ef270ab1SKenneth D. Merry }
203ef270ab1SKenneth D. Merry }
204ef270ab1SKenneth D. Merry #else
205ef270ab1SKenneth D. Merry #define ocs_list_init_link(...)
206ef270ab1SKenneth D. Merry #endif
207ef270ab1SKenneth D. Merry
208ef270ab1SKenneth D. Merry /**
209ef270ab1SKenneth D. Merry * @ingroup os
210ef270ab1SKenneth D. Merry * @brief Add an item to the head of the list
211ef270ab1SKenneth D. Merry *
212ef270ab1SKenneth D. Merry * @param list Pointer to list head
213ef270ab1SKenneth D. Merry * @param item Item to add
214ef270ab1SKenneth D. Merry */
215ef270ab1SKenneth D. Merry static inline void
ocs_list_add_head(ocs_list_t * list,void * item)216ef270ab1SKenneth D. Merry ocs_list_add_head(ocs_list_t *list, void *item)
217ef270ab1SKenneth D. Merry {
218ef270ab1SKenneth D. Merry ocs_list_t *link;
219ef270ab1SKenneth D. Merry
220ef270ab1SKenneth D. Merry ocs_list_assert(list);
221ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
222ef270ab1SKenneth D. Merry ocs_list_assert(item);
223ef270ab1SKenneth D. Merry
224ef270ab1SKenneth D. Merry link = item2link(list, item);
225ef270ab1SKenneth D. Merry ocs_list_init_link(list, link);
226ef270ab1SKenneth D. Merry
227ef270ab1SKenneth D. Merry ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
228ef270ab1SKenneth D. Merry ocs_list_assert(link->offset == list->offset);
229ef270ab1SKenneth D. Merry ocs_list_assert(link->next == NULL);
230ef270ab1SKenneth D. Merry ocs_list_assert(link->prev == NULL);
231ef270ab1SKenneth D. Merry
232ef270ab1SKenneth D. Merry _ocs_list_insert_link(list, list->next, item2link(list, item));
233ef270ab1SKenneth D. Merry }
234ef270ab1SKenneth D. Merry
235ef270ab1SKenneth D. Merry /**
236ef270ab1SKenneth D. Merry * @ingroup os
237ef270ab1SKenneth D. Merry * @brief Add an item to the tail of the list
238ef270ab1SKenneth D. Merry *
239ef270ab1SKenneth D. Merry * @param list Head of the list
240ef270ab1SKenneth D. Merry * @param item Item to add
241ef270ab1SKenneth D. Merry */
242ef270ab1SKenneth D. Merry static inline void
ocs_list_add_tail(ocs_list_t * list,void * item)243ef270ab1SKenneth D. Merry ocs_list_add_tail(ocs_list_t *list, void *item)
244ef270ab1SKenneth D. Merry {
245ef270ab1SKenneth D. Merry ocs_list_t *link;
246ef270ab1SKenneth D. Merry
247ef270ab1SKenneth D. Merry ocs_list_assert(list);
248ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC);
249ef270ab1SKenneth D. Merry ocs_list_assert(item);
250ef270ab1SKenneth D. Merry
251ef270ab1SKenneth D. Merry link = item2link(list, item);
252ef270ab1SKenneth D. Merry ocs_list_init_link(list, link);
253ef270ab1SKenneth D. Merry
254ef270ab1SKenneth D. Merry ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC);
255ef270ab1SKenneth D. Merry ocs_list_assert(link->offset == list->offset);
256ef270ab1SKenneth D. Merry ocs_list_assert(link->next == NULL);
257ef270ab1SKenneth D. Merry ocs_list_assert(link->prev == NULL);
258ef270ab1SKenneth D. Merry
259ef270ab1SKenneth D. Merry _ocs_list_insert_link(list->prev, list, link);
260ef270ab1SKenneth D. Merry }
261ef270ab1SKenneth D. Merry
262ef270ab1SKenneth D. Merry /**
263ef270ab1SKenneth D. Merry * @ingroup os
264ef270ab1SKenneth D. Merry * @brief Return the first item in the list
265ef270ab1SKenneth D. Merry *
266ef270ab1SKenneth D. Merry * @param list Head of the list
267ef270ab1SKenneth D. Merry *
268ef270ab1SKenneth D. Merry * @return pointer to the first item, NULL otherwise
269ef270ab1SKenneth D. Merry */
270ef270ab1SKenneth D. Merry static inline void *
ocs_list_get_head(ocs_list_t * list)271ef270ab1SKenneth D. Merry ocs_list_get_head(ocs_list_t *list)
272ef270ab1SKenneth D. Merry {
273ef270ab1SKenneth D. Merry ocs_list_assert(list, NULL);
274ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
275ef270ab1SKenneth D. Merry return ocs_list_empty(list) ? NULL : link2item(list, list->next);
276ef270ab1SKenneth D. Merry }
277ef270ab1SKenneth D. Merry
278ef270ab1SKenneth D. Merry /**
279ef270ab1SKenneth D. Merry * @ingroup os
280ef270ab1SKenneth D. Merry * @brief Return the first item in the list
281ef270ab1SKenneth D. Merry *
282ef270ab1SKenneth D. Merry * @param list head of the list
283ef270ab1SKenneth D. Merry *
284ef270ab1SKenneth D. Merry * @return pointer to the last item, NULL otherwise
285ef270ab1SKenneth D. Merry */
286ef270ab1SKenneth D. Merry static inline void *
ocs_list_get_tail(ocs_list_t * list)287ef270ab1SKenneth D. Merry ocs_list_get_tail(ocs_list_t *list)
288ef270ab1SKenneth D. Merry {
289ef270ab1SKenneth D. Merry ocs_list_assert(list, NULL);
290ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
291ef270ab1SKenneth D. Merry return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
292ef270ab1SKenneth D. Merry }
293ef270ab1SKenneth D. Merry
294ef270ab1SKenneth D. Merry /**
295ef270ab1SKenneth D. Merry * @ingroup os
296ef270ab1SKenneth D. Merry * @brief Return the last item in the list
297ef270ab1SKenneth D. Merry *
298ef270ab1SKenneth D. Merry * @param list Pointer to list head
299ef270ab1SKenneth D. Merry *
300ef270ab1SKenneth D. Merry * @return pointer to the last item, NULL otherwise
301ef270ab1SKenneth D. Merry */
ocs_list_tail(ocs_list_t * list)302ef270ab1SKenneth D. Merry static inline void *ocs_list_tail(ocs_list_t *list)
303ef270ab1SKenneth D. Merry {
304ef270ab1SKenneth D. Merry ocs_list_assert(list, NULL);
305ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
306ef270ab1SKenneth D. Merry return ocs_list_empty(list) ? NULL : link2item(list, list->prev);
307ef270ab1SKenneth D. Merry }
308ef270ab1SKenneth D. Merry
309ef270ab1SKenneth D. Merry /**
310ef270ab1SKenneth D. Merry * @ingroup os
311ef270ab1SKenneth D. Merry * @brief Get the next item on the list
312ef270ab1SKenneth D. Merry *
313ef270ab1SKenneth D. Merry * @param list head of the list
314ef270ab1SKenneth D. Merry * @param item current item
315ef270ab1SKenneth D. Merry *
316ef270ab1SKenneth D. Merry * @return pointer to the next item, NULL otherwise
317ef270ab1SKenneth D. Merry */
ocs_list_next(ocs_list_t * list,void * item)318ef270ab1SKenneth D. Merry static inline void *ocs_list_next(ocs_list_t *list, void *item)
319ef270ab1SKenneth D. Merry {
320ef270ab1SKenneth D. Merry ocs_list_t *link;
321ef270ab1SKenneth D. Merry
322ef270ab1SKenneth D. Merry if (item == NULL) {
323ef270ab1SKenneth D. Merry return NULL;
324ef270ab1SKenneth D. Merry }
325ef270ab1SKenneth D. Merry
326ef270ab1SKenneth D. Merry ocs_list_assert(list, NULL);
327ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
328ef270ab1SKenneth D. Merry ocs_list_assert(item, NULL);
329ef270ab1SKenneth D. Merry
330ef270ab1SKenneth D. Merry link = item2link(list, item);
331ef270ab1SKenneth D. Merry
332ef270ab1SKenneth D. Merry ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
333ef270ab1SKenneth D. Merry ocs_list_assert(link->offset == list->offset, NULL);
334ef270ab1SKenneth D. Merry ocs_list_assert(link->next, NULL);
335ef270ab1SKenneth D. Merry ocs_list_assert(link->prev, NULL);
336ef270ab1SKenneth D. Merry
337ef270ab1SKenneth D. Merry if ((link->next) == list) {
338ef270ab1SKenneth D. Merry return NULL;
339ef270ab1SKenneth D. Merry }
340ef270ab1SKenneth D. Merry
341ef270ab1SKenneth D. Merry return link2item(list, link->next);
342ef270ab1SKenneth D. Merry }
343ef270ab1SKenneth D. Merry
344ef270ab1SKenneth D. Merry /**
345ef270ab1SKenneth D. Merry * @ingroup os
346ef270ab1SKenneth D. Merry * @brief Remove and return an item from the head of the list
347ef270ab1SKenneth D. Merry *
348ef270ab1SKenneth D. Merry * @param list head of the list
349ef270ab1SKenneth D. Merry *
350ef270ab1SKenneth D. Merry * @return pointer to returned item, or NULL if list is empty
351ef270ab1SKenneth D. Merry */
352ef270ab1SKenneth D. Merry #define ocs_list_remove_head(list) ocs_list_remove(list, ocs_list_get_head(list))
353ef270ab1SKenneth D. Merry
354ef270ab1SKenneth D. Merry /**
355ef270ab1SKenneth D. Merry * @ingroup os
356ef270ab1SKenneth D. Merry * @brief Remove an item from the list
357ef270ab1SKenneth D. Merry *
358ef270ab1SKenneth D. Merry * @param list Head of the list
359ef270ab1SKenneth D. Merry * @param item Item to remove
360ef270ab1SKenneth D. Merry *
361ef270ab1SKenneth D. Merry * @return pointer to item, or NULL if item is not found.
362ef270ab1SKenneth D. Merry */
ocs_list_remove(ocs_list_t * list,void * item)363ef270ab1SKenneth D. Merry static inline void *ocs_list_remove(ocs_list_t *list, void *item)
364ef270ab1SKenneth D. Merry {
365ef270ab1SKenneth D. Merry ocs_list_t *link;
366ef270ab1SKenneth D. Merry ocs_list_t *prev;
367ef270ab1SKenneth D. Merry ocs_list_t *next;
368ef270ab1SKenneth D. Merry
369ef270ab1SKenneth D. Merry if (item == NULL) {
370ef270ab1SKenneth D. Merry return NULL;
371ef270ab1SKenneth D. Merry }
372ef270ab1SKenneth D. Merry ocs_list_assert(list, NULL);
373ef270ab1SKenneth D. Merry ocs_list_assert(list->magic == OCS_LIST_LIST_MAGIC, NULL);
374ef270ab1SKenneth D. Merry
375ef270ab1SKenneth D. Merry link = item2link(list, item);
376ef270ab1SKenneth D. Merry
377ef270ab1SKenneth D. Merry ocs_list_assert(link->magic == OCS_LIST_LINK_MAGIC, NULL);
378ef270ab1SKenneth D. Merry ocs_list_assert(link->offset == list->offset, NULL);
379ef270ab1SKenneth D. Merry ocs_list_assert(link->next, NULL);
380ef270ab1SKenneth D. Merry ocs_list_assert(link->prev, NULL);
381ef270ab1SKenneth D. Merry
382ef270ab1SKenneth D. Merry prev = link->prev;
383ef270ab1SKenneth D. Merry next = link->next;
384ef270ab1SKenneth D. Merry
385ef270ab1SKenneth D. Merry prev->next = next;
386ef270ab1SKenneth D. Merry next->prev = prev;
387ef270ab1SKenneth D. Merry
388ef270ab1SKenneth D. Merry link->next = link->prev = NULL;
389ef270ab1SKenneth D. Merry
390ef270ab1SKenneth D. Merry return item;
391ef270ab1SKenneth D. Merry }
392ef270ab1SKenneth D. Merry
393ef270ab1SKenneth D. Merry /**
394ef270ab1SKenneth D. Merry * @brief Iterate a linked list
395ef270ab1SKenneth D. Merry *
396ef270ab1SKenneth D. Merry * Iterate a linked list.
397ef270ab1SKenneth D. Merry *
398ef270ab1SKenneth D. Merry * @param list Pointer to list
399ef270ab1SKenneth D. Merry * @param item Pointer to iterated item
400ef270ab1SKenneth D. Merry *
401ef270ab1SKenneth D. Merry * note, item is NULL after full list is traversed.
402ef270ab1SKenneth D. Merry
403ef270ab1SKenneth D. Merry * @return none
404ef270ab1SKenneth D. Merry */
405ef270ab1SKenneth D. Merry
406ef270ab1SKenneth D. Merry #define ocs_list_foreach(list, item) \
407ef270ab1SKenneth D. Merry for (item = ocs_list_get_head((list)); item; item = ocs_list_next((list), item) )
408ef270ab1SKenneth D. Merry
409ef270ab1SKenneth D. Merry /**
410ef270ab1SKenneth D. Merry * @brief Iterate a linked list safely
411ef270ab1SKenneth D. Merry *
412ef270ab1SKenneth D. Merry * Iterate a linked list safely, meaning that the iterated item
413ef270ab1SKenneth D. Merry * may be safely removed from the list.
414ef270ab1SKenneth D. Merry *
415ef270ab1SKenneth D. Merry * @param list Pointer to list
416ef270ab1SKenneth D. Merry * @param item Pointer to iterated item
417ef270ab1SKenneth D. Merry * @param nxt Pointer to saveed iterated item
418ef270ab1SKenneth D. Merry *
419ef270ab1SKenneth D. Merry * note, item is NULL after full list is traversed.
420ef270ab1SKenneth D. Merry *
421ef270ab1SKenneth D. Merry * @return none
422ef270ab1SKenneth D. Merry */
423ef270ab1SKenneth D. Merry
424ef270ab1SKenneth D. Merry #define ocs_list_foreach_safe(list, item, nxt) \
425ef270ab1SKenneth D. Merry for (item = ocs_list_get_head(list), nxt = item ? ocs_list_next(list, item) : NULL; item; \
426ef270ab1SKenneth D. Merry item = nxt, nxt = ocs_list_next(list, item))
427ef270ab1SKenneth D. Merry
428ef270ab1SKenneth D. Merry /**
429ef270ab1SKenneth D. Merry * @brief Test if object is on a list
430ef270ab1SKenneth D. Merry *
431ef270ab1SKenneth D. Merry * Returns True if object is on a list
432ef270ab1SKenneth D. Merry *
433ef270ab1SKenneth D. Merry * @param link Pointer to list link
434ef270ab1SKenneth D. Merry *
435ef270ab1SKenneth D. Merry * @return returns True if object is on a list
436ef270ab1SKenneth D. Merry */
437ef270ab1SKenneth D. Merry static inline int32_t
ocs_list_on_list(ocs_list_link_t * link)438ef270ab1SKenneth D. Merry ocs_list_on_list(ocs_list_link_t *link)
439ef270ab1SKenneth D. Merry {
440ef270ab1SKenneth D. Merry return (link->next != NULL);
441ef270ab1SKenneth D. Merry }
442ef270ab1SKenneth D. Merry
443ef270ab1SKenneth D. Merry #endif /* __OCS_LIST_H__ */
444