Blame winpr/libwinpr/utils/collections/LinkedList.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * System.Collections.Generic.LinkedList<T>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/collections.h>
Packit 1fb8d4
Packit 1fb8d4
typedef struct _wLinkedListItem wLinkedListNode;
Packit 1fb8d4
Packit 1fb8d4
struct _wLinkedListItem
Packit 1fb8d4
{
Packit 1fb8d4
	void* value;
Packit 1fb8d4
	wLinkedListNode* prev;
Packit 1fb8d4
	wLinkedListNode* next;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
struct _wLinkedList
Packit 1fb8d4
{
Packit 1fb8d4
	int count;
Packit 1fb8d4
	int initial;
Packit 1fb8d4
	wLinkedListNode* head;
Packit 1fb8d4
	wLinkedListNode* tail;
Packit 1fb8d4
	wLinkedListNode* current;
Packit 1fb8d4
	wObject object;
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * C equivalent of the C# LinkedList<T> Class:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/he2s3bh7.aspx
Packit 1fb8d4
 *
Packit 1fb8d4
 * Internal implementation uses a doubly-linked list
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Properties
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Gets the number of nodes actually contained in the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
int LinkedList_Count(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	return list->count;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Gets the first node of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void* LinkedList_First(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list->head)
Packit 1fb8d4
		return list->head->value;
Packit 1fb8d4
	else
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Gets the last node of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void* LinkedList_Last(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list->tail)
Packit 1fb8d4
		return list->tail->value;
Packit 1fb8d4
	else
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Methods
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Determines whether the LinkedList contains a specific value.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL LinkedList_Contains(wLinkedList* list, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedListNode* item;
Packit 1fb8d4
	OBJECT_EQUALS_FN keyEquals;
Packit 1fb8d4
Packit 1fb8d4
	if (!list->head)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	item = list->head;
Packit 1fb8d4
	keyEquals = list->object.fnObjectEquals;
Packit 1fb8d4
Packit 1fb8d4
	while (item)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (keyEquals(item->value, value))
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		item = item->next;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (item) ? TRUE : FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static wLinkedListNode* LinkedList_FreeNode(wLinkedList* list, wLinkedListNode* node)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedListNode* next = node->next;
Packit 1fb8d4
	wLinkedListNode* prev = node->prev;
Packit 1fb8d4
Packit 1fb8d4
	if (prev)
Packit 1fb8d4
		prev->next = next;
Packit 1fb8d4
Packit 1fb8d4
	if (next)
Packit 1fb8d4
		next->prev = prev;
Packit 1fb8d4
Packit 1fb8d4
	if (node == list->head)
Packit 1fb8d4
		list->head = node->next;
Packit 1fb8d4
Packit 1fb8d4
	if (node == list->tail)
Packit 1fb8d4
		list->tail = node->prev;
Packit 1fb8d4
Packit 1fb8d4
	if (list->object.fnObjectUninit)
Packit 1fb8d4
		list->object.fnObjectUninit(node);
Packit 1fb8d4
Packit 1fb8d4
	if (list->object.fnObjectFree)
Packit 1fb8d4
		list->object.fnObjectFree(node);
Packit 1fb8d4
Packit 1fb8d4
	free(node);
Packit 1fb8d4
	list->count--;
Packit 1fb8d4
	return next;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Removes all entries from the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void LinkedList_Clear(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedListNode* node;
Packit 1fb8d4
Packit 1fb8d4
	if (!list->head)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	node = list->head;
Packit 1fb8d4
Packit 1fb8d4
	while (node)
Packit 1fb8d4
		node = LinkedList_FreeNode(list, node);
Packit 1fb8d4
Packit 1fb8d4
	list->head = list->tail = NULL;
Packit 1fb8d4
	list->count = 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static wLinkedListNode* LinkedList_Create(wLinkedList* list, void* value)
Packit 1fb8d4
{
Packit Service 5a9772
	wLinkedListNode* node = (wLinkedListNode*)calloc(1, sizeof(wLinkedListNode));
Packit 1fb8d4
Packit 1fb8d4
	if (!node)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (list->object.fnObjectNew)
Packit 1fb8d4
		node->value = list->object.fnObjectNew(value);
Packit 1fb8d4
	else
Packit 1fb8d4
		node->value = value;
Packit 1fb8d4
Packit 1fb8d4
	if (list->object.fnObjectInit)
Packit 1fb8d4
		list->object.fnObjectInit(node);
Packit 1fb8d4
Packit 1fb8d4
	return node;
Packit 1fb8d4
}
Packit 1fb8d4
/**
Packit 1fb8d4
 * Adds a new node containing the specified value at the start of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL LinkedList_AddFirst(wLinkedList* list, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedListNode* node = LinkedList_Create(list, value);
Packit 1fb8d4
Packit 1fb8d4
	if (!node)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!list->head)
Packit 1fb8d4
	{
Packit 1fb8d4
		list->tail = list->head = node;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		list->head->prev = node;
Packit 1fb8d4
		node->next = list->head;
Packit 1fb8d4
		list->head = node;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	list->count++;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Adds a new node containing the specified value at the end of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL LinkedList_AddLast(wLinkedList* list, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedListNode* node = LinkedList_Create(list, value);
Packit 1fb8d4
Packit 1fb8d4
	if (!node)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!list->tail)
Packit 1fb8d4
	{
Packit 1fb8d4
		list->head = list->tail = node;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		list->tail->next = node;
Packit 1fb8d4
		node->prev = list->tail;
Packit 1fb8d4
		list->tail = node;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	list->count++;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Removes the first occurrence of the specified value from the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL LinkedList_Remove(wLinkedList* list, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedListNode* node;
Packit 1fb8d4
	OBJECT_EQUALS_FN keyEquals;
Packit 1fb8d4
	keyEquals = list->object.fnObjectEquals;
Packit 1fb8d4
	node = list->head;
Packit 1fb8d4
Packit 1fb8d4
	while (node)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (keyEquals(node->value, value))
Packit 1fb8d4
		{
Packit 1fb8d4
			LinkedList_FreeNode(list, node);
Packit 1fb8d4
			return TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		node = node->next;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Removes the node at the start of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void LinkedList_RemoveFirst(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list->head)
Packit 1fb8d4
		LinkedList_FreeNode(list, list->head);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Removes the node at the end of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void LinkedList_RemoveLast(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list->tail)
Packit 1fb8d4
		LinkedList_FreeNode(list, list->tail);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Sets the enumerator to its initial position, which is before the first element in the collection.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void LinkedList_Enumerator_Reset(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	list->initial = 1;
Packit 1fb8d4
	list->current = list->head;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * Gets the element at the current position of the enumerator.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void* LinkedList_Enumerator_Current(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list->initial)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (list->current)
Packit 1fb8d4
		return list->current->value;
Packit 1fb8d4
	else
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/*
Packit 1fb8d4
 * Advances the enumerator to the next element of the LinkedList.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL LinkedList_Enumerator_MoveNext(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list->initial)
Packit 1fb8d4
		list->initial = 0;
Packit 1fb8d4
	else if (list->current)
Packit 1fb8d4
		list->current = list->current->next;
Packit 1fb8d4
Packit 1fb8d4
	if (!list->current)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL default_equal_function(const void* objA, const void* objB)
Packit 1fb8d4
{
Packit 1fb8d4
	return objA == objB;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Construction, Destruction
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
wLinkedList* LinkedList_New(void)
Packit 1fb8d4
{
Packit 1fb8d4
	wLinkedList* list = NULL;
Packit Service 5a9772
	list = (wLinkedList*)calloc(1, sizeof(wLinkedList));
Packit 1fb8d4
Packit 1fb8d4
	if (list)
Packit 1fb8d4
	{
Packit 1fb8d4
		list->object.fnObjectEquals = default_equal_function;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return list;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void LinkedList_Free(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (list)
Packit 1fb8d4
	{
Packit 1fb8d4
		LinkedList_Clear(list);
Packit 1fb8d4
		free(list);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
wObject* LinkedList_Object(wLinkedList* list)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!list)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	return &list->object;
Packit 1fb8d4
}