startup_init/services/utils/list.c
chengjinsong af6d736d0d codex
Signed-off-by: chengjinsong <chengjinsong2@huawei.com>
2022-09-23 10:10:18 +08:00

233 lines
5.9 KiB
C

/*
* 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 <stddef.h>
#include <stdlib.h>
/**
* @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;
if (head == NULL || item == NULL || compareProc == NULL) {
return;
}
match = head->next;
while ((match != NULL) && (match != head)) {
if (compareProc(match, item) > 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, unsigned int flags)
{
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;
}
int 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;
}