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