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