view LinkedList.c @ 42:05e5dc4817a4

Warning: Breaking API/ABI changes. New optimizations to decouple update loop from number of buffers queued in audio streaming to allow more for more and smaller buffers to be processed in a loop. This also has the benefit for access_data callback buffer sizes not to be dictated by the performance tuning. Note that the Load APIs break and add a new parameter to specify the target number of buffers to queue per update pass. Also, I changed the access_data from ALboolean to ALuint for possible future use since I'm already breaking the API. The motivation for this is for the feature request of allowing for data callbacks on buffer queue to modify the input data right before submission.
author Eric Wing <ewing@anscamobile.com>
date Tue, 30 Aug 2011 19:42:31 -0700
parents 14c22fc3c753
children
line wrap: on
line source

#include "LinkedList.h"
#include <stddef.h> /* for NULL */
#include <stdlib.h> /* for malloc/free */
#include <stdio.h> /* for debugging */

struct LinkedListNode
{
	LinkedListNode* nextNode;
	LinkedListNode* previousNode;
	void* dataPtr;
};

struct LinkedList
{
	size_t currentSize;
	LinkedListNode* headPtr;
	LinkedListNode* tailPtr;
};


LinkedListNode* LinkedListNode_Create()
{
	LinkedListNode* list_node;
	list_node = (LinkedListNode*)calloc(1, sizeof(LinkedListNode));
	if(NULL == list_node)
	{
		/* Very bad, but not sure what to do here. */
		return NULL;
	}

	return list_node;
}


void LinkedListNode_Free(LinkedListNode* list_node)
{
	if(NULL == list_node)
	{
		return;
	}
	free(list_node);
}


LinkedList* LinkedList_Create()
{
	LinkedList* linked_list;
	linked_list = (LinkedList*)calloc(1, sizeof(LinkedList));
	if(NULL == linked_list)
	{
		/* Very bad, but not sure what to do here. */
		return NULL;
	}

	return linked_list;
}

void LinkedList_Free(LinkedList* linked_list)
{
	/* Both functions check for NULL */
	LinkedList_Clear(linked_list);
	free(linked_list);
}


/**
 * Returns 1 if successful, 0 if failure.
 */
unsigned int LinkedList_PushFront(LinkedList* linked_list, void* new_item)
{
	LinkedListNode* new_node;
	
	if(NULL == linked_list)
	{
		return 0;
	}

	new_node = LinkedListNode_Create();
	if(NULL == new_node)
	{
		return 0;
	}

	new_node->dataPtr = new_item;

	if(0 == linked_list->currentSize)
	{
		linked_list->tailPtr = new_node;
	}
	else
	{
		LinkedListNode* head_node = linked_list->headPtr;
		new_node->nextNode = head_node;
		head_node->previousNode = new_node;
	}

	linked_list->headPtr = new_node;
	linked_list->currentSize++;
	return 1;
}

unsigned int LinkedList_PushBack(LinkedList* linked_list, void* new_item)
{
	LinkedListNode* new_node;
	
	if(NULL == linked_list)
	{
		return 0;
	}

	new_node = LinkedListNode_Create();
	if(NULL == new_node)
	{
		return 0;
	}

	new_node->dataPtr = new_item;

	if(0 == linked_list->currentSize)
	{
		linked_list->headPtr = new_node;
	}
	else
	{
		LinkedListNode* tail_node = linked_list->tailPtr;
		new_node->previousNode = tail_node;
		tail_node->nextNode = new_node;
	}

	linked_list->tailPtr = new_node;
	linked_list->currentSize++;
	return 1;

}

void* LinkedList_PopFront(LinkedList* linked_list)
{
	LinkedListNode* head_node;
	void* return_data;
	
	if(NULL == linked_list)
	{
		return 0;
	}
	if(0 == linked_list->currentSize)
	{
		return NULL;
	}

	head_node = linked_list->headPtr;
	return_data = head_node->dataPtr;
	
	if(1 ==  linked_list->currentSize)
	{
		LinkedList_Clear(linked_list);
	}
	else
	{
		LinkedListNode* next_node = head_node->nextNode;
		next_node->previousNode = NULL;
		LinkedListNode_Free(head_node);
		linked_list->headPtr = next_node;
		linked_list->currentSize = linked_list->currentSize - 1;

	}
	return return_data;
}

void* LinkedList_PopBack(LinkedList* linked_list)
{
	LinkedListNode* tail_node;
	void* return_data;
	
	if(NULL == linked_list)
	{
		return NULL;
	}
	if(0 == linked_list->currentSize)
	{
		return NULL;
	}

	tail_node = linked_list->tailPtr;
	return_data = tail_node->dataPtr;
	
	if(1 == linked_list->currentSize)
	{
		LinkedList_Clear(linked_list);
	}
	else
	{
		LinkedListNode* previous_node = tail_node->previousNode;
		previous_node->nextNode = NULL;
		LinkedListNode_Free(tail_node);
		linked_list->tailPtr = previous_node;
		linked_list->currentSize = linked_list->currentSize - 1;
	}
	return return_data;
}


void* LinkedList_Front(LinkedList* linked_list)
{
	LinkedListNode* head_node;
	void* return_data;
	
	if(NULL == linked_list)
	{
		return 0;
	}
	if(0 == linked_list->currentSize)
	{
		return NULL;
	}
	
	head_node = linked_list->headPtr;
	return_data = head_node->dataPtr;
	
	return return_data;
}

void* LinkedList_Back(LinkedList* linked_list)
{
	LinkedListNode* tail_node;
	void* return_data;
	
	if(NULL == linked_list)
	{
		return NULL;
	}
	if(0 == linked_list->currentSize)
	{
		return NULL;
	}
	
	tail_node = linked_list->tailPtr;
	return_data = tail_node->dataPtr;

	return return_data;
}


size_t LinkedList_Size(LinkedList* linked_list)
{
	if(NULL == linked_list)
	{
		return 0;
	}
	return linked_list->currentSize;
}

void LinkedList_Clear(LinkedList* linked_list)
{
	LinkedListNode* current_node;
	LinkedListNode* next_node;
	if(NULL == linked_list)
	{
		return;
	}

	current_node = linked_list->headPtr;
	while(NULL != current_node)
	{
		next_node = current_node->nextNode;
		LinkedListNode_Free(current_node);
		current_node = next_node;
	}
	linked_list->headPtr = NULL;
	linked_list->tailPtr = NULL;
	linked_list->currentSize = 0;
}

void* LinkedListNode_GetData(LinkedListNode* list_node)
{
	if(NULL == list_node)
	{
		return NULL;
	}
	return list_node->dataPtr;
}

LinkedListNode* LinkedList_Find(LinkedList* linked_list, void* the_data, LinkedListNode* start_node)
{
	LinkedListNode* current_node;
	if(NULL == linked_list)
	{
		return NULL;
	}
	if(NULL == start_node)
	{
		start_node = linked_list->headPtr;
	}
	
	for(current_node = start_node; NULL != current_node; current_node = current_node->nextNode)
	{
		if(current_node->dataPtr == the_data)
		{
			return current_node;
		}
	}
	return current_node;
}

/* Make sure your LinkedListNode is actually connected to the 
 * LinkedList instance you pass.
 */
unsigned int LinkedList_Remove(LinkedList* linked_list, LinkedListNode* list_node)
{
	LinkedListNode* previous_node;
	LinkedListNode* next_node;
	if(NULL == linked_list)
	{
		return 0;
	}
	if(NULL == list_node)
	{
		return 0;
	}
		
	if(1 ==  linked_list->currentSize)
	{
		LinkedList_Clear(linked_list);
	}
	else if(list_node == linked_list->headPtr)
	{
		LinkedList_PopFront(linked_list);
	}
	else if(list_node == linked_list->tailPtr)
	{
		LinkedList_PopBack(linked_list);
	}
	else
	{
		previous_node = list_node->previousNode;
		next_node = list_node->nextNode;

		previous_node->nextNode = next_node;
		next_node->previousNode = previous_node;
		LinkedListNode_Free(list_node);

		linked_list->currentSize = linked_list->currentSize - 1;
	}

	return 1;

}