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

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