1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "list.h"
17
18 #include <stddef.h>
19 #include <stdlib.h>
20
21 /**
22 * @brief Initialize a double-linked list head
23 *
24 * All other list API should be initialized by this function.\n
25 *
26 * @param head list head, make sure head is valid pointer
27 * @return None
28 */
OH_ListInit(struct ListNode * node)29 void OH_ListInit(struct ListNode *node)
30 {
31 if (node == NULL) {
32 return;
33 }
34 node->next = node;
35 node->prev = node;
36 }
37
38 /**
39 * @brief Add a node to the end of the list
40 *
41 * @param head list head, make sure head is valid pointer
42 * @param item new node to be added
43 * @return None
44 */
OH_ListAddTail(struct ListNode * head,struct ListNode * item)45 void OH_ListAddTail(struct ListNode *head, struct ListNode *item)
46 {
47 if (head == NULL || item == NULL) {
48 return;
49 }
50 item->next = head;
51 item->prev = head->prev;
52 head->prev->next = item;
53 head->prev = item;
54 }
55
56 /**
57 * @brief Remove a node from the list
58 *
59 * @param item the node to be removed from the list.
60 * This function does not free any memory within item.
61 * @return None
62 */
OH_ListRemove(struct ListNode * item)63 void OH_ListRemove(struct ListNode *item)
64 {
65 if (item == NULL) {
66 return;
67 }
68 item->next->prev = item->prev;
69 item->prev->next = item->next;
70 }
71
72 /**
73 * @brief Add a node to the list with order
74 *
75 * @param head list head, make sure head is valid pointer
76 * @param item new node to be added
77 * @param compareProc comparison function for adding node
78 * if it is ascending order, this function should return an integer less than,
79 * equal to, or greater than zero if the first argument is considered to be
80 * respectively less than, equal to, or greater than the second.
81 * @return None
82 */
OH_ListAddWithOrder(struct ListNode * head,struct ListNode * item,ListCompareProc compareProc)83 void OH_ListAddWithOrder(struct ListNode *head, struct ListNode *item, ListCompareProc compareProc)
84 {
85 ListNode *match;
86
87 if (head == NULL || item == NULL || compareProc == NULL) {
88 return;
89 }
90
91 match = head->next;
92 while ((match != NULL) && (match != head)) {
93 if (compareProc(match, item) > 0) {
94 break;
95 }
96 match = match->next;
97 }
98 if (match == NULL) {
99 return;
100 }
101
102 // Insert
103 item->next = match;
104 item->prev = match->prev;
105 match->prev->next = item;
106 match->prev = item;
107 }
108
109 /**
110 * @brief Find a node by traversing the list
111 *
112 * @param head list head, make sure head is valid pointer.
113 * @param data comparing data.
114 * @param compareProc comparing function, return 0 if matched.
115 * @return the found node; return NULL if none is found.
116 */
OH_ListFind(const ListNode * head,void * data,ListTraversalProc compareProc)117 ListNode *OH_ListFind(const ListNode *head, void *data, ListTraversalProc compareProc)
118 {
119 ListNode *match;
120 if ((head == NULL) || (compareProc == NULL)) {
121 return NULL;
122 }
123
124 match = head->next;
125 while ((match != NULL) && (match != head)) {
126 if (compareProc(match, data) == 0) {
127 return match;
128 }
129 match = match->next;
130 }
131
132 return NULL;
133 }
134
135 #define IS_REVERSE_ORDER(flags) (((flags) & TRAVERSE_REVERSE_ORDER) != 0)
136 #define IS_STOP_WHEN_ERROR(flags) (((flags) & TRAVERSE_STOP_WHEN_ERROR) != 0)
137
138 /**
139 * @brief Traversal the list with specified function
140 *
141 * @param head list head, make sure head is valid pointer.
142 * @param cookie optional traversing data.
143 * @param traversalProc comparing function, return 0 if matched.
144 * @param flags optional traversing flags:
145 * TRAVERSE_REVERSE_ORDER: traversing from last node to first node;
146 * default behaviour is from first node to last node
147 * TRAVERSE_STOP_WHEN_ERROR: stop traversing if traversalProc return non-zero
148 * default behaviour will ignore traversalProc return values
149 * @return return -1 for invalid input arguments.
150 * when TRAVERSE_STOP_WHEN_ERROR is specified, it will return errors from traversalProc
151 */
OH_ListTraversal(ListNode * head,void * data,ListTraversalProc traversalProc,unsigned int flags)152 int OH_ListTraversal(ListNode *head, void *data, ListTraversalProc traversalProc, unsigned int flags)
153 {
154 ListNode *match;
155 ListNode *next;
156
157 if ((head == NULL) || (traversalProc == NULL)) {
158 return -1;
159 }
160
161 if (IS_REVERSE_ORDER(flags)) {
162 match = head->prev;
163 } else {
164 match = head->next;
165 }
166 while ((match != NULL) && (match != head)) {
167 if (IS_REVERSE_ORDER(flags)) {
168 next = match->prev;
169 } else {
170 next = match->next;
171 }
172 int ret = traversalProc(match, data);
173 if ((ret != 0) && IS_STOP_WHEN_ERROR(flags)) {
174 return ret;
175 }
176 match = next;
177 }
178
179 return 0;
180 }
181
listDestroyTraversal(ListNode * node,void * data)182 static int listDestroyTraversal(ListNode *node, void *data)
183 {
184 ListDestroyProc destroyProc = (ListDestroyProc)data;
185
186 if (destroyProc == NULL) {
187 free((void *)node);
188 } else {
189 destroyProc(node);
190 }
191
192 return 0;
193 }
194
195 /**
196 * @brief Find a node by traversing the list
197 *
198 * @param head list head, make sure head is valid pointer.
199 * @param destroyProc destroy function; if NULL, it will free each node by default.
200 * @return None
201 */
OH_ListRemoveAll(ListNode * head,ListDestroyProc destroyProc)202 void OH_ListRemoveAll(ListNode *head, ListDestroyProc destroyProc)
203 {
204 if (head == NULL) {
205 return;
206 }
207
208 OH_ListTraversal(head, (void *)destroyProc, listDestroyTraversal, 0);
209 OH_ListInit(head);
210 }
211
212 /**
213 * @brief Get list count
214 *
215 * @param head list head, make sure head is valid pointer.
216 * @return the count of nodes in the list; return 0 if error
217 */
OH_ListGetCnt(const ListNode * head)218 int OH_ListGetCnt(const ListNode *head)
219 {
220 int cnt;
221 ListNode *node;
222
223 if (head == NULL) {
224 return 0;
225 }
226
227 cnt = 0;
228 ForEachListEntry(head, node) {
229 cnt++;
230 }
231 return cnt;
232 }
233