/**
* @file single_linked_list.c
* @author libra
* @date 2016年2月24日
* @version 初稿
*/
#include <stdlib.h>
#include <string.h>
#include "single_linked_list.h"
/**
*@brief: list_init
*@details: Initializes the linked list specified by list. This operation must be called for a linked list before the list can be used with any other operation.
* Thedestroyargument provides a way to free dynamically allocated data when list_destroy is called. For example, if the list contains data dynamically allocated
* usingmalloc, destroyshould be set to free to free the data as the linked list is destroyed. For structured data containing several dynamically allocated members,
* destroyshould be set to a user-defined function that callsfree for each dynamically allocated member as well as for the structure itself.
* For a linked list containing data that should not be freed, destroyshould be set to NULL.
*@param[in][out] List *list
*@param[in] void (*destroy)(void *data)
*@retval: None
*/
void list_init(List *list, void (*destroy)(void *data))
{
/*Initialize the list.*/
list->size = 0;
list->destroy = destroy;
list->head = NULL;
list->tail = NULL;
return;
}
/**
*@brief: list_destroy
*@details: Destroys the linked list specified bylist. No other operations are permitted after calling list_destroy unless list_init is called again.
* The list_destroyoperation removes all elements from a linked list and calls the function passed asdestroyto list_init once for each element as it is removed,
* provided destroywas not set to NULL.
*@param[in][out] List *list
*@retval: None
*/
void list_destroy(List *list)
{
void *data;
/*Remove each element.*/
while (list_size(list) > 0)
{
if (list_rem_next(list, NULL, (void **)&data) == 0 && list->destroy != NULL)
{
/*Call a user-defined function to free dynamically allocated data.*/
list->destroy(data);
}
}
/*No operations are allowed now, but clear the structure as a precaution.*/
memset(list, 0, sizeof(List));
return;
}
/**
*@brief: list_ins_next
*@details: Inserts an element just after elementin the linked list specified bylist.Ifelementis NULL, the new element is inserted at the head of the list.
* The new element contains a pointer todata, so the memory referenced by data should remain valid as long as the element remains in the list.
* It is the responsibility of the caller to manage the storage associated with data.
*@param[in][out] List *list
*@param[in][out] ListElmt *element
*@param[in] const void *data
*@retval: 0 if inserting the element is successful, or –1 otherwise.
*/
int list_ins_next(List *list, ListElmt *element, const void *data)
{
ListElmt *new_element;
/*Allocate storage for the element.*/
if ((new_element = (ListElmt *)malloc(sizeof(ListElmt))) == NULL)
{
return -1;
}
/*Insert the element into the list.*/
new_element->data = (void *)data;
if (element == NULL)
{
/*Handle insertion at the head of the list.*/
if (list_size(list) == 0)
{
list->tail = new_element;
}
new_element->next = list->head;
list->head = new_element;
}
else
{
/* Handle insertion somewhere other than at the head. */
if (element->next == NULL)
{
list->tail = new_element;
}
new_element->next = element->next;
element->next = new_element;
}
/*Adjust the size of the list to account for the inserted element.*/
list->size++;
return 0;
}
/**
*@brief: list_rem_next
*@details: Removes the element just afterelementfrom the linked list specified by list.Ifelementis NULL, the element at the head of the list is removed.
* Upon return,datapoints to the data stored in the element that was removed. It is
* the responsibility of the caller to manage the storage associated with the data.
*@param[in][out] List *list
*@param[in][out] ListElmt *element
*@param[out] void **data
*@retval: 0 if removing the element is successful, or –1 otherwise.
*/
int list_rem_next(List *list, ListElmt *element, void **data)
{
ListElmt *old_element;
/*Do not allow removal from an empty list.*/
if (list_size(list) == 0)
{
return -1;
}
/* Remove the element from the list.*/
if (element == NULL)
{
/*Handle removal from the head of the list.*/
*data = list->head->data;
old_element = list->head;
list->head = list->head->next;
if (list_size(list) == 1)
{
list->tail = NULL;
}
}
else
{
/*Handle removal from somewhere other than the head.*/
if (element->next == NULL)
{
return -1;
}
*data = element->next->data;
old_element = element->next;
element->next = element->next->next;
if (element->next == NULL)
{
list->tail = element;
}
}
/*Free the storage allocated by the abstract data type. */
free(old_element);
/*Adjust the size of the list to account for the removed element.*/
list->size--;
return 0;
}