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

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * System.Collections.Specialized.ListDictionary
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 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/crt.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/collections.h>
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * C equivalent of the C# ListDictionary Class:
Packit Service fa4841
 * http://msdn.microsoft.com/en-us/library/system.collections.specialized.listdictionary.aspx
Packit Service fa4841
 *
Packit Service fa4841
 * Internal implementation uses a singly-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 key/value pairs contained in the ListDictionary.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int ListDictionary_Count(wListDictionary* listDictionary)
Packit Service fa4841
{
Packit Service fa4841
	int count = 0;
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (item)
Packit Service fa4841
		{
Packit Service fa4841
			count++;
Packit Service fa4841
			item = item->next;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return count;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Lock access to the ListDictionary
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void ListDictionary_Lock(wListDictionary* listDictionary)
Packit Service fa4841
{
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Unlock access to the ListDictionary
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void ListDictionary_Unlock(wListDictionary* listDictionary)
Packit Service fa4841
{
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	LeaveCriticalSection(&listDictionary->lock);
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
 * Gets the list of keys as an array
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int ListDictionary_GetKeys(wListDictionary* listDictionary, ULONG_PTR** ppKeys)
Packit Service fa4841
{
Packit Service fa4841
	int index;
Packit Service fa4841
	int count;
Packit Service fa4841
	ULONG_PTR* pKeys = NULL;
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
Packit Service fa4841
	if (!ppKeys || !listDictionary)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	count = 0;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (item)
Packit Service fa4841
		{
Packit Service fa4841
			count++;
Packit Service fa4841
			item = item->next;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (count)
Packit Service fa4841
	{
Packit Service fa4841
		pKeys = (ULONG_PTR*)calloc(count, sizeof(ULONG_PTR));
Packit Service fa4841
Packit Service fa4841
		if (!pKeys)
Packit Service fa4841
		{
Packit Service fa4841
			if (listDictionary->synchronized)
Packit Service fa4841
				LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
			return -1;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	index = 0;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (item)
Packit Service fa4841
		{
Packit Service fa4841
			pKeys[index++] = (ULONG_PTR)item->key;
Packit Service fa4841
			item = item->next;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	*ppKeys = pKeys;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return count;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Adds an entry with the specified key and value into the ListDictionary.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL ListDictionary_Add(wListDictionary* listDictionary, const void* key, void* value)
Packit Service fa4841
{
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
	wListDictionaryItem* lastItem;
Packit Service fa4841
	BOOL ret = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	item = (wListDictionaryItem*)malloc(sizeof(wListDictionaryItem));
Packit Service fa4841
Packit Service fa4841
	if (!item)
Packit Service fa4841
		goto out_error;
Packit Service fa4841
Packit Service fa4841
	item->key = (void*)key;
Packit Service fa4841
	item->value = value;
Packit Service fa4841
	item->next = NULL;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		listDictionary->head = item;
Packit Service fa4841
	}
Packit Service fa4841
	else
Packit Service fa4841
	{
Packit Service fa4841
		lastItem = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (lastItem->next)
Packit Service fa4841
			lastItem = lastItem->next;
Packit Service fa4841
Packit Service fa4841
		lastItem->next = item;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	ret = TRUE;
Packit Service fa4841
out_error:
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Removes all entries from the ListDictionary.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void ListDictionary_Clear(wListDictionary* listDictionary)
Packit Service fa4841
{
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
	wListDictionaryItem* nextItem;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (item)
Packit Service fa4841
		{
Packit Service fa4841
			nextItem = item->next;
Packit Service fa4841
Packit Service fa4841
			if (listDictionary->objectKey.fnObjectFree)
Packit Service fa4841
				listDictionary->objectKey.fnObjectFree(item->key);
Packit Service fa4841
Packit Service fa4841
			if (listDictionary->objectValue.fnObjectFree)
Packit Service fa4841
				listDictionary->objectValue.fnObjectFree(item->value);
Packit Service fa4841
Packit Service fa4841
			free(item);
Packit Service fa4841
			item = nextItem;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		listDictionary->head = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Determines whether the ListDictionary contains a specific key.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL ListDictionary_Contains(wListDictionary* listDictionary, const void* key)
Packit Service fa4841
{
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
	OBJECT_EQUALS_FN keyEquals;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&(listDictionary->lock));
Packit Service fa4841
Packit Service fa4841
	keyEquals = listDictionary->objectKey.fnObjectEquals;
Packit Service fa4841
	item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
	while (item)
Packit Service fa4841
	{
Packit Service fa4841
		if (keyEquals(item->key, key))
Packit Service fa4841
			break;
Packit Service fa4841
Packit Service fa4841
		item = item->next;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&(listDictionary->lock));
Packit Service fa4841
Packit Service fa4841
	return (item) ? TRUE : FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Removes the entry with the specified key from the ListDictionary.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void* ListDictionary_Remove(wListDictionary* listDictionary, const void* key)
Packit Service fa4841
{
Packit Service fa4841
	void* value = NULL;
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
	wListDictionaryItem* prevItem;
Packit Service fa4841
	OBJECT_EQUALS_FN keyEquals;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	keyEquals = listDictionary->objectKey.fnObjectEquals;
Packit Service fa4841
	item = listDictionary->head;
Packit Service fa4841
	prevItem = NULL;
Packit Service fa4841
Packit Service fa4841
	while (item)
Packit Service fa4841
	{
Packit Service fa4841
		if (keyEquals(item->key, key))
Packit Service fa4841
		{
Packit Service fa4841
			if (!prevItem)
Packit Service fa4841
				listDictionary->head = item->next;
Packit Service fa4841
			else
Packit Service fa4841
				prevItem->next = item->next;
Packit Service fa4841
Packit Service fa4841
			value = item->value;
Packit Service fa4841
			free(item);
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		prevItem = item;
Packit Service fa4841
		item = item->next;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return value;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Removes the first (head) entry from the list
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void* ListDictionary_Remove_Head(wListDictionary* listDictionary)
Packit Service fa4841
{
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
	void* value = NULL;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
		listDictionary->head = listDictionary->head->next;
Packit Service fa4841
		value = item->value;
Packit Service fa4841
		free(item);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return value;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Get an item value using key
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void* ListDictionary_GetItemValue(wListDictionary* listDictionary, const void* key)
Packit Service fa4841
{
Packit Service fa4841
	void* value = NULL;
Packit Service fa4841
	wListDictionaryItem* item = NULL;
Packit Service fa4841
	OBJECT_EQUALS_FN keyEquals;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	keyEquals = listDictionary->objectKey.fnObjectEquals;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (item)
Packit Service fa4841
		{
Packit Service fa4841
			if (keyEquals(item->key, key))
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			item = item->next;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	value = (item) ? item->value : NULL;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return value;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Set an item value using key
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL ListDictionary_SetItemValue(wListDictionary* listDictionary, const void* key, void* value)
Packit Service fa4841
{
Packit Service fa4841
	BOOL status = FALSE;
Packit Service fa4841
	wListDictionaryItem* item;
Packit Service fa4841
	OBJECT_EQUALS_FN keyEquals;
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		EnterCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	keyEquals = listDictionary->objectKey.fnObjectEquals;
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->head)
Packit Service fa4841
	{
Packit Service fa4841
		item = listDictionary->head;
Packit Service fa4841
Packit Service fa4841
		while (item)
Packit Service fa4841
		{
Packit Service fa4841
			if (keyEquals(item->key, key))
Packit Service fa4841
				break;
Packit Service fa4841
Packit Service fa4841
			item = item->next;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (item)
Packit Service fa4841
		{
Packit Service fa4841
			if (listDictionary->objectValue.fnObjectFree)
Packit Service fa4841
				listDictionary->objectValue.fnObjectFree(item->value);
Packit Service fa4841
Packit Service fa4841
			item->value = value;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		status = (item) ? TRUE : FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (listDictionary->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&listDictionary->lock);
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL default_equal_function(const void* obj1, const void* obj2)
Packit Service fa4841
{
Packit Service fa4841
	return (obj1 == obj2);
Packit Service fa4841
}
Packit Service fa4841
/**
Packit Service fa4841
 * Construction, Destruction
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
wListDictionary* ListDictionary_New(BOOL synchronized)
Packit Service fa4841
{
Packit Service fa4841
	wListDictionary* listDictionary = NULL;
Packit Service fa4841
	listDictionary = (wListDictionary*)calloc(1, sizeof(wListDictionary));
Packit Service fa4841
Packit Service fa4841
	if (!listDictionary)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	listDictionary->synchronized = synchronized;
Packit Service fa4841
Packit Service fa4841
	if (!InitializeCriticalSectionAndSpinCount(&(listDictionary->lock), 4000))
Packit Service fa4841
	{
Packit Service fa4841
		free(listDictionary);
Packit Service fa4841
		return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	listDictionary->objectKey.fnObjectEquals = default_equal_function;
Packit Service fa4841
	listDictionary->objectValue.fnObjectEquals = default_equal_function;
Packit Service fa4841
	return listDictionary;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void ListDictionary_Free(wListDictionary* listDictionary)
Packit Service fa4841
{
Packit Service fa4841
	if (listDictionary)
Packit Service fa4841
	{
Packit Service fa4841
		ListDictionary_Clear(listDictionary);
Packit Service fa4841
		DeleteCriticalSection(&listDictionary->lock);
Packit Service fa4841
		free(listDictionary);
Packit Service fa4841
	}
Packit Service fa4841
}