1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	list.h
9  * @brief	List primitives for libmetal.
10  */
11 
12 #ifndef __METAL_LIST__H__
13 #define __METAL_LIST__H__
14 
15 #include <stdbool.h>
16 #include <stdlib.h>
17 
18 #ifdef __cplusplus
19 extern "C" {
20 #endif
21 
22 /** \defgroup list List Primitives
23  *  @{
24  */
25 
26 struct metal_list {
27 	struct metal_list *next, *prev;
28 };
29 
30 /*
31  * METAL_INIT_LIST - used for initializing an list element in a static struct
32  * or global
33  */
34 #define METAL_INIT_LIST(name) { .next = &name, .prev = &name }
35 /*
36  * METAL_DECLARE_LIST - used for defining and initializing a global or
37  * static singleton list
38  */
39 #define METAL_DECLARE_LIST(name)			\
40 	struct metal_list name = METAL_INIT_LIST(name)
41 
metal_list_init(struct metal_list * list)42 static inline void metal_list_init(struct metal_list *list)
43 {
44 	list->prev = list;
45 	list->next = list;
46 }
47 
metal_list_add_before(struct metal_list * node,struct metal_list * new_node)48 static inline void metal_list_add_before(struct metal_list *node,
49 					 struct metal_list *new_node)
50 {
51 	new_node->prev = node->prev;
52 	new_node->next = node;
53 	new_node->next->prev = new_node;
54 	new_node->prev->next = new_node;
55 }
56 
metal_list_add_after(struct metal_list * node,struct metal_list * new_node)57 static inline void metal_list_add_after(struct metal_list *node,
58 					struct metal_list *new_node)
59 {
60 	new_node->prev = node;
61 	new_node->next = node->next;
62 	new_node->next->prev = new_node;
63 	new_node->prev->next = new_node;
64 }
65 
metal_list_add_head(struct metal_list * list,struct metal_list * node)66 static inline void metal_list_add_head(struct metal_list *list,
67 				       struct metal_list *node)
68 {
69 	metal_list_add_after(list, node);
70 }
71 
metal_list_add_tail(struct metal_list * list,struct metal_list * node)72 static inline void metal_list_add_tail(struct metal_list *list,
73 				       struct metal_list *node)
74 {
75 	metal_list_add_before(list, node);
76 }
77 
metal_list_is_empty(struct metal_list * list)78 static inline int metal_list_is_empty(struct metal_list *list)
79 {
80 	return list->next == list;
81 }
82 
metal_list_del(struct metal_list * node)83 static inline void metal_list_del(struct metal_list *node)
84 {
85 	node->next->prev = node->prev;
86 	node->prev->next = node->next;
87 	node->prev = node;
88 	node->next = node;
89 }
90 
metal_list_first(struct metal_list * list)91 static inline struct metal_list *metal_list_first(struct metal_list *list)
92 {
93 	return metal_list_is_empty(list) ? NULL : list->next;
94 }
95 
96 /**
97  * @brief	Used for iterating over a list
98  *
99  * @param	list	Pointer to the head node of the list
100  * @param	node	Pointer to each node in the list during iteration
101  */
102 #define metal_list_for_each(list, node)		\
103 	for ((node) = (list)->next;		\
104 	     (node) != (list);			\
105 	     (node) = (node)->next)
106 
107 /**
108  * @brief	Used for iterating over a list safely
109  *
110  * @param	list	Pointer to the head node of the list
111  * @param	temp	Pointer to the next node's address during iteration
112  * @param	node	Pointer to each node in the list during iteration
113  */
114 #define metal_list_for_each_safe(list, temp, node)		\
115 	for ((node) = (list)->next, (temp) = (node)->next;	\
116 	     (node) != (list);					\
117 	     (node) = (temp), (temp) = (node)->next)
118 
metal_list_find_node(struct metal_list * list,struct metal_list * node)119 static inline bool metal_list_find_node(struct metal_list *list,
120 					struct metal_list *node)
121 {
122 	struct metal_list *n;
123 
124 	metal_list_for_each(list, n) {
125 		if (n == node)
126 			return true;
127 	}
128 	return false;
129 }
130 /** @} */
131 
132 #ifdef __cplusplus
133 }
134 #endif
135 
136 #endif /* __METAL_LIST__H__ */
137