/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "list.h" #include #include #include /** * @brief Initialize a double-linked list head * * All other list API should be initialized by this function.\n * * @param head list head, make sure head is valid pointer * @return None */ void OH_ListInit(struct ListNode *node) { if (node == NULL) { return; } node->next = node; node->prev = node; } /** * @brief Add a node to the end of the list * * @param head list head, make sure head is valid pointer * @param item new node to be added * @return None */ void OH_ListAddTail(struct ListNode *head, struct ListNode *item) { if (head == NULL || item == NULL) { return; } item->next = head; item->prev = head->prev; head->prev->next = item; head->prev = item; } /** * @brief Remove a node from the list * * @param item the node to be removed from the list. * This function does not free any memory within item. * @return None */ void OH_ListRemove(struct ListNode *item) { if (item == NULL) { return; } item->next->prev = item->prev; item->prev->next = item->next; } /** * @brief Add a node to the list with order * * @param head list head, make sure head is valid pointer * @param item new node to be added * @param compareProc comparison function for adding node * if it is ascending order, this function should return an integer less than, * equal to, or greater than zero if the first argument is considered to be * respectively less than, equal to, or greater than the second. * @return None */ void OH_ListAddWithOrder(struct ListNode *head, struct ListNode *item, ListCompareProc compareProc) { ListNode *match; int ret; if (head == NULL || item == NULL || compareProc == NULL) { return; } match = head->next; while ((match != NULL) && (match != head)) { ret = compareProc(match, item); if (ret > 0) { break; } match = match->next; } if (match == NULL) { return; } // Insert item->next = match; item->prev = match->prev; match->prev->next = item; match->prev = item; } /** * @brief Find a node by traversing the list * * @param head list head, make sure head is valid pointer. * @param data comparing data. * @param compareProc comparing function, return 0 if matched. * @return the found node; return NULL if none is found. */ ListNode *OH_ListFind(const ListNode *head, void *data, ListTraversalProc compareProc) { ListNode *match; if ((head == NULL) || (compareProc == NULL)) { return NULL; } match = head->next; while ((match != NULL) && (match != head)) { if (compareProc(match, data) == 0) { return match; } match = match->next; } return NULL; } #define IS_REVERSE_ORDER(flags) (((flags) & TRAVERSE_REVERSE_ORDER) != 0) #define IS_STOP_WHEN_ERROR(flags) (((flags) & TRAVERSE_STOP_WHEN_ERROR) != 0) /** * @brief Traversal the list with specified function * * @param head list head, make sure head is valid pointer. * @param cookie optional traversing data. * @param traversalProc comparing function, return 0 if matched. * @param flags optional traversing flags: * TRAVERSE_REVERSE_ORDER: traversing from last node to first node; * default behaviour is from first node to last node * TRAVERSE_STOP_WHEN_ERROR: stop traversing if traversalProc return non-zero * default behaviour will ignore traversalProc return values * @return return -1 for invalid input arguments. * when TRAVERSE_STOP_WHEN_ERROR is specified, it will return errors from traversalProc */ int OH_ListTraversal(ListNode *head, void *data, ListTraversalProc traversalProc, int flags) { int ret; ListNode *match; ListNode *next; if ((head == NULL) || (traversalProc == NULL)) { return -1; } if (IS_REVERSE_ORDER(flags)) { match = head->prev; } else { match = head->next; } while ((match != NULL) && (match != head)) { if (IS_REVERSE_ORDER(flags)) { next = match->prev; } else { next = match->next; } ret = traversalProc(match, data); if ((ret != 0) && IS_STOP_WHEN_ERROR(flags)) { return ret; } match = next; } return 0; } static int listDestroyTraversal(ListNode *node, void *data) { ListDestroyProc destroyProc = (ListDestroyProc)data; if (destroyProc == NULL) { free((void *)node); } else { destroyProc(node); } return 0; } /** * @brief Find a node by traversing the list * * @param head list head, make sure head is valid pointer. * @param destroyProc destroy function; if NULL, it will free each node by default. * @return None */ void OH_ListRemoveAll(ListNode *head, ListDestroyProc destroyProc) { if (head == NULL) { return; } OH_ListTraversal(head, (void *)destroyProc, listDestroyTraversal, 0); OH_ListInit(head); } /** * @brief Get list count * * @param head list head, make sure head is valid pointer. * @return the count of nodes in the list; return 0 if error */ int OH_ListGetCnt(const ListNode *head) { int cnt; ListNode *node; if (head == NULL) { return 0; } cnt = 0; ForEachListEntry(head, node) { cnt++; } return cnt; }