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

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * System.Collections.Stack
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/collections.h>
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * C equivalent of the C# Stack Class:
Packit Service fa4841
 * http://msdn.microsoft.com/en-us/library/system.collections.stack.aspx
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 elements contained in the Stack.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int Stack_Count(wStack* stack)
Packit Service fa4841
{
Packit Service fa4841
	int ret;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		EnterCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	ret = stack->size;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Gets a value indicating whether access to the Stack is synchronized (thread safe).
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL Stack_IsSynchronized(wStack* stack)
Packit Service fa4841
{
Packit Service fa4841
	return stack->synchronized;
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
 * Removes all objects from the Stack.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void Stack_Clear(wStack* stack)
Packit Service fa4841
{
Packit Service fa4841
	int index;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		EnterCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	for (index = 0; index < stack->size; index++)
Packit Service fa4841
	{
Packit Service fa4841
		if (stack->object.fnObjectFree)
Packit Service fa4841
			stack->object.fnObjectFree(stack->array[index]);
Packit Service fa4841
Packit Service fa4841
		stack->array[index] = NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	stack->size = 0;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&stack->lock);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Determines whether an element is in the Stack.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
BOOL Stack_Contains(wStack* stack, void* obj)
Packit Service fa4841
{
Packit Service fa4841
	int i;
Packit Service fa4841
	BOOL found = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		EnterCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	for (i = 0; i < stack->size; i++)
Packit Service fa4841
	{
Packit Service fa4841
		if (stack->object.fnObjectEquals(stack->array[i], obj))
Packit Service fa4841
		{
Packit Service fa4841
			found = TRUE;
Packit Service fa4841
			break;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	return found;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Inserts an object at the top of the Stack.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void Stack_Push(wStack* stack, void* obj)
Packit Service fa4841
{
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		EnterCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	if ((stack->size + 1) >= stack->capacity)
Packit Service fa4841
	{
Packit Service fa4841
		int new_cap;
Packit Service fa4841
		void** new_arr;
Packit Service fa4841
		new_cap = stack->capacity * 2;
Packit Service fa4841
		new_arr = (void**)realloc(stack->array, sizeof(void*) * new_cap);
Packit Service fa4841
Packit Service fa4841
		if (!new_arr)
Packit Service fa4841
			return;
Packit Service fa4841
Packit Service fa4841
		stack->array = new_arr;
Packit Service fa4841
		stack->capacity = new_cap;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	stack->array[(stack->size)++] = obj;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&stack->lock);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Removes and returns the object at the top of the Stack.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void* Stack_Pop(wStack* stack)
Packit Service fa4841
{
Packit Service fa4841
	void* obj = NULL;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		EnterCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	if (stack->size > 0)
Packit Service fa4841
		obj = stack->array[--(stack->size)];
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	return obj;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Returns the object at the top of the Stack without removing it.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void* Stack_Peek(wStack* stack)
Packit Service fa4841
{
Packit Service fa4841
	void* obj = NULL;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		EnterCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	if (stack->size > 0)
Packit Service fa4841
		obj = stack->array[stack->size - 1];
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized)
Packit Service fa4841
		LeaveCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
	return obj;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL default_stack_equals(const void* obj1, const void* obj2)
Packit Service fa4841
{
Packit Service fa4841
	return (obj1 == obj2);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Construction, Destruction
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
wStack* Stack_New(BOOL synchronized)
Packit Service fa4841
{
Packit Service fa4841
	wStack* stack = NULL;
Packit Service fa4841
	stack = (wStack*)calloc(1, sizeof(wStack));
Packit Service fa4841
Packit Service fa4841
	if (!stack)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	stack->object.fnObjectEquals = default_stack_equals;
Packit Service fa4841
	stack->synchronized = synchronized;
Packit Service fa4841
	stack->capacity = 32;
Packit Service fa4841
	stack->array = (void**)calloc(stack->capacity, sizeof(void*));
Packit Service fa4841
Packit Service fa4841
	if (!stack->array)
Packit Service fa4841
		goto out_free;
Packit Service fa4841
Packit Service fa4841
	if (stack->synchronized && !InitializeCriticalSectionAndSpinCount(&stack->lock, 4000))
Packit Service fa4841
		goto out_free_array;
Packit Service fa4841
Packit Service fa4841
	return stack;
Packit Service fa4841
out_free_array:
Packit Service fa4841
	free(stack->array);
Packit Service fa4841
out_free:
Packit Service fa4841
	free(stack);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void Stack_Free(wStack* stack)
Packit Service fa4841
{
Packit Service fa4841
	if (stack)
Packit Service fa4841
	{
Packit Service fa4841
		if (stack->synchronized)
Packit Service fa4841
			DeleteCriticalSection(&stack->lock);
Packit Service fa4841
Packit Service fa4841
		free(stack->array);
Packit Service fa4841
		free(stack);
Packit Service fa4841
	}
Packit Service fa4841
}