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