xref: /base/startup/init/services/utils/list.c (revision d9f0492f)
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 */
29void 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 */
45void 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 */
63void 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 */
83void 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 */
117ListNode *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 */
152int 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
182static 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 */
202void 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 */
218int 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