#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "linklist.h"
#define _empty(list) ((list)->tail ? AD_FALSE : AD_TRUE)
#define APPEND 1
#define PREPEND !(APPEND)
/* Linklist */
struct _LLNODE
{
struct _LLNODE *next;
void *data;
};
struct _LINKLIST
{
unsigned int count;
struct _LLNODE *tail; /* tail of the circular linklist */
pthread_mutex_t mutex;
};
typedef struct _LLNODE LLNODE;
#define LLNODE_SIZE sizeof(LLNODE)
LINKLIST *ll_init(void)
{
LINKLIST *list;
if ((list = calloc(1, LINKLIST_SIZE)))
pthread_mutex_init(&(list->mutex), NULL);
return list;
}
AD_BOOLEAN ll_empty(LINKLIST *list)
{
if (!list) return AD_TRUE;
return _empty(list);
}
static LINKLIST *_add(LINKLIST *list, void *newdata, int insertType)
{
LLNODE *newnode;
if (list != NULL) {
pthread_mutex_lock(&(list->mutex));
if ((newnode = malloc(LLNODE_SIZE))) {
newnode->data = newdata;
if (_empty(list) == AD_TRUE) {
newnode->next = newnode;
list->tail = newnode;
} else {
newnode->next = list->tail->next;
list->tail->next = newnode;
if (insertType == APPEND)
list->tail = list->tail->next;
}
list->count++;
}
pthread_mutex_unlock(&(list->mutex));
}
return list;
}
LINKLIST *ll_prepend (LINKLIST *list, void *newdata)
{
return _add(list, newdata, PREPEND);
}
LINKLIST *ll_append (LINKLIST *list, void *newdata)
{
return _add(list, newdata, APPEND);
}
static LLNODE *find_node(LINKLIST *list, void *key, AD_COMPARE_FUNC *match, LLNODE **prev)
{
LLNODE *current, *head, *find = NULL;
/* begin current at the start of the list */
current = head = list->tail->next;
*prev = list->tail;
do {
if (match(current->data, key) == AD_EQUAL) {
find = current;
break;
}
*prev = current;
current = current->next;
} while (current != head); /* end when you return to head */
return find;
}
int ll_swapline(LINKLIST *list, void *k1, void *k2, AD_LOCK lock_f, AD_COMPARE_FUNC *match)
{
LLNODE *key1_prev, *key1, *key2_prev, *key2, *tmp;
LLNODE *prev;
int result = -1;
if (list) {
if (lock_f)
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
if ((key1 = find_node(list, k1, match, &prev))) {
/* 5 */
key1_prev = prev;
/* ex: */
/* k1:6 <=========> k2:9 */
/* first find 6, and 9 */
if ((key2 = find_node(list, k2, match, &prev))) {
if (key1 == list->tail)
list->tail = key2;
else if (key2 == list->tail)
list->tail = key1;
/* 8 */
key2_prev = prev;
/* 1. 5->next = 9, 8->next = 6 */
key1_prev->next = key2, key2_prev->next = key1;
/* 2. 9->next <=> 6->next */
tmp = key2->next;
key2->next = key1->next;
key1->next = tmp;
result = 0;
}
}
}
if (lock_f)
pthread_mutex_unlock(&(list->mutex));
}
return result;
}
void *ll_find(LINKLIST *list, void *key, AD_LOCK lock_f, AD_COMPARE_FUNC *match)
{
LLNODE *current, *head;
void *data = NULL;
if (!list) return NULL;
if (lock_f)
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
/* begin current at the start of the list */
current = head = list->tail->next;
do {
if (match(current->data, key) == AD_EQUAL) {
data = current->data;
break;
}
current = current->next;
} while (current != head); /* end when you return to head */
}
if (lock_f)
pthread_mutex_unlock(&(list->mutex));
return data;
}
void *ll_delete(LINKLIST *list, void *key, AD_COMPARE_FUNC *match)
{
LLNODE *current, *prev, *head;
void *data = NULL;
if (!list) return NULL;
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
current = head = list->tail->next;
prev = list->tail;
do {
if (match(current->data, key) == AD_EQUAL) {
if (current == prev) /* only node */
list->tail = NULL;
else {
prev->next = current->next; /* unlink the node to be deleted */
if (current == list->tail) /* last node is to be deleted */
list->tail = prev;
}
list->count--;
data = current->data;
free(current);
break;
}
prev = current;
current = current->next;
} while (current != head);
}
pthread_mutex_unlock(&(list->mutex));
return data;
}
void *ll_get(LINKLIST *list, void **n, AD_LOCK lock_f)
{
void *data = NULL;
LLNODE *current, **node = (LLNODE **)n;
if (!list || (*node == list->tail))
return NULL;
if (lock_f)
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
current = (*node == NULL) ? list->tail->next : (*node)->next;
data = current->data;
*node = (void *) current;
}
if (lock_f)
pthread_mutex_unlock(&(list->mutex));
return data;
}
AD_BOOLEAN ll_traverse(LINKLIST *list, AD_LOCK lock_f, AD_TRAV_FUNC *travFunc, void *param)
{
LLNODE *current, *head;
AD_BOOLEAN FIN_OK = AD_FALSE;
if (!list) return AD_FALSE;
if (lock_f)
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
FIN_OK = AD_TRUE;
head = list->tail->next;
current = head;
do {
if (travFunc(current->data, param) == AD_FALSE) {
FIN_OK = AD_FALSE;
break;
}
current = current->next;
} while (current != head);
}
if (lock_f)
pthread_mutex_unlock(&(list->mutex));
return FIN_OK;
}
void ll_free(LINKLIST *list)
{
LLNODE *current, *temp;
if (!list) return;
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
/* initialise */
current = list->tail->next; /* start at the head */
list->tail->next = NULL; /* break the circular nature */
while(current != NULL) {
temp = current;
current = current->next;
free(temp);
}
}
pthread_mutex_unlock(&(list->mutex));
pthread_mutex_destroy(&(list->mutex));
free(list);
list = NULL;
}
/* to be used by the deque data type */
void *ll_delete_head(LINKLIST *list)
{
void *outdata = NULL;
LLNODE *head;
if (!list) return NULL;
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
head = list->tail->next;
outdata = head->data;
if (head == list->tail) /* only one node */
list->tail = NULL;
else /* more than one one */
list->tail->next = head->next;
list->count--;
free(head);
}
pthread_mutex_unlock(&(list->mutex));
return outdata;
}
void *ll_delete_tail(LINKLIST *list)
{
LLNODE *previous;
void *data = NULL;
if (!list) return NULL;
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE) {
data = list->tail->data;
/* locate the node prior to the tail */
previous = list->tail;
do {
previous = previous->next;
} while (previous->next != list->tail);
/* only one element in the list */
if(previous == list->tail) {
free(list->tail);
list->tail = NULL;
}
/* general case of more than one element */
else {
previous->next = list->tail->next;
free(list->tail);
list->tail = previous;
}
list->count--;
}
pthread_mutex_unlock(&(list->mutex));
return data;
}
void *ll_head(LINKLIST *list)
{
void *data = NULL;
if (!list) return NULL;
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE)
data = list->tail->next->data;
pthread_mutex_unlock(&(list->mutex));
return data;
}
void *ll_tail(LINKLIST *list)
{
void *data = NULL;
if (!list) return NULL;
pthread_mutex_lock(&(list->mutex));
if (_empty(list) == AD_FALSE)
data = list->tail->data;
pthread_mutex_unlock(&(list->mutex));
return data;
}
unsigned ll_count(LINKLIST *list)
{
unsigned count = 0;
if (list != NULL) {
pthread_mutex_lock(&(list->mutex));
count = list->count;
pthread_mutex_unlock(&(list->mutex));
}
return count;
}
linklist.c
訂閱:
文章 (Atom)
沒有留言:
張貼留言