General Dlist Implement by C

/*dlist.c by xianjimli*/
#include <stdio.h>
#include <stdlib.h>
#include "dlist.h"

typedef struct _DListNode
{
	struct _DListNode* next;
	struct _DListNode* prev;

	void* data;
} DListNode;

struct _DList
{
	DListNode* first;
	void* data_destroy_ctx;
	DListDataDestroyFunc data_destroy;
};

static void dlist_destroy_data(DList* thiz, void* data)
{
	if (NULL != thiz->data_destroy) {
		thiz->data_destroy(thiz->data_destroy_ctx, data);
	}
	
	return;
}

static DListNode* dlist_node_create(DList* thiz, void* data)
{
	DListNode* node	= (DListNode*)malloc(sizeof(DListNode));
	if (NULL != node) {
		node->next = NULL;
		node->prev = NULL;
		node->data = data;
	}
	
	return node;
}

static void dlist_node_destroy(DList* thiz, DListNode* node)
{
	if (NULL != node) {
		node->next = NULL;
		node->prev = NULL;
		dlist_destroy_data(thiz, node->data);
	}
	free(node);
	
	return;
}

DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx)
{
	DList* thiz = malloc(sizeof(DList));
	if (NULL != thiz) {
		thiz->first = NULL;
		thiz->data_destroy = data_destroy;
		thiz->data_destroy_ctx = data_destroy_ctx;
	}

	return thiz;
}

static DListNode* dlist_get_node(DList* thiz, size_t index, int fail_return_last)
{
	DListNode* iter = NULL;
	return_val_if_fail(thiz != NULL, NULL);
	
	iter = thiz->first;
	while (iter != NULL && iter->next != NULL && index > 0) {
		iter = iter->next;
		index--;
	}

	if (!fail_return_last) {
		iter = index > 0 ? NULL : iter;
	}

	return iter;
}

DListRet dlist_insert(DList* thiz, size_t index, void* data)
{
	DListNode* node = NULL;
	DListNode* cursor = NULL;

	return_val_if_fail(NULL != thiz, DLIST_RET_INVALID_PARAMS);
	
	if ((node = dlist_node_create(thiz, data)) == NULL) {
		return DLIST_RET_OOM;
	}	

	if (thiz->first == NULL) {
		thiz->first = node;
		return DLIST_RET_OK;
	}	

	cursor = dlist_get_node(thiz, index, 1);
	if (index < dlist_length(thiz)) {
		if (cursor == thiz->first) {
			thiz->first = node;
		} else {
			cursor->prev->next = node;
			node->prev = cursor->prev;
		}
		node->next = cursor;
		cursor->prev = node;
	} else {
		cursor->next = node;
		node->prev = cursor;
	}

	return DLIST_RET_OK;
}

DListRet dlist_prepend(DList* thiz, void* data)
{
	return dlist_insert(thiz, 0, data);
}

DListRet dlist_append(DList* thiz, void* data)
{
	return dlist_insert(thiz, -1, data);
}

DListRet dlist_delete(DList* thiz, size_t index)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);
	
	return_val_if_fail(NULL != thiz, DLIST_RET_INVALID_PARAMS);
	
	if (cursor != NULL) {
		if (cursor == thiz->first) {
			thiz->first = cursor->next;
		}
		if (cursor->next != NULL) {
			cursor->next->prev = cursor->prev;
		}
		if (cursor->prev != NULL) {
			cursor->prev->next = cursor->next;
		}
		
		dlist_node_destroy(thiz, cursor);
	}
	
	return DLIST_RET_OK;
}

DListRet dlist_get_by_index(DList* thiz, size_t index, void** data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);
	
	return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS);
	
	*data = cursor->data;
	
	return DLIST_RET_OK;
}

DListRet dlist_set_by_index(DList* thiz, size_t index, void* data)
{
	DListNode* cursor = dlist_get_node(thiz, index, 0);
	
	return_val_if_fail(cursor != NULL, DLIST_RET_INVALID_PARAMS);
	
	cursor->data = data;
	
	return DLIST_RET_OK;
}

size_t dlist_length(DList* thiz)
{
	size_t length = 0;
	DListNode* iter = NULL;
	
	return_val_if_fail(thiz != NULL, 0);
	
	iter = thiz->first;
	while (iter != NULL)
	{
		length++;
		iter = iter->next;
	}
	
	return length;
}

DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx)
{
	DListNode* iter = NULL;
	DListRet ret = DLIST_RET_OK;	

	return_val_if_fail(thiz != NULL && visit != NULL, DLIST_RET_INVALID_PARAMS);
	
	iter = thiz->first;
	while (iter != NULL) {
		ret = visit(ctx, iter->data);
		iter = iter->next;
	}
	
	return ret;
}

int dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx)
{
	int index = 0;
	DListNode* iter = NULL;

	return_val_if_fail(thiz != NULL && cmp != NULL, -1);

	iter = thiz->first;
	while (iter != NULL) {
		if (0 == cmp(ctx, iter->data)) {
			break;
		}
		index++;
		iter = iter->next;
	}

	return index;
}	

void dlist_destroy(DList* thiz)
{
	DListNode* iter = NULL;
	DListNode* next = NULL;
	return_if_fail(thiz != NULL);
	
	iter = thiz->first;
	while (iter != NULL) {
		next = iter->next;
		dlist_destroy_data(thiz, iter);
		iter = next;
	}
	thiz->first = NULL;
	free(thiz);

	return;
}

#ifdef DLIST_TEST
#include <assert.h>
static void dlist_data_destroy(void* ctx, void* data)
{
	
}

static int dlist_data_cmp(void* ctx, void* data)
{
	return (int)ctx - (int)data;
}

static DListRet dlist_data_visit(void* ctx, void* data)
{
	int* expected = (int*)ctx;
	assert((*expected) == (int)data);
	(*expected)--;
	return DLIST_RET_OK;
}

void test_int_dlist(void)
{
	int i = 0;
	int data = 0;
	int n = 100;
	int s = 0;

	DList* dlist = dlist_create(NULL, NULL);
	for (i = 0; i < n; i++) {
		assert(DLIST_RET_OK == dlist_append(dlist, (void*)i));
		assert(dlist_length(dlist) == i+1);
		assert(DLIST_RET_OK == dlist_get_by_index(dlist, i, (void**)&data));
		assert(i == data);
		assert(DLIST_RET_OK == dlist_set_by_index(dlist, i, (void*)(i*2)));
		assert(DLIST_RET_OK == dlist_get_by_index(dlist, i, (void**)&data));
		assert(data == 2*i);
		assert(DLIST_RET_OK == dlist_set_by_index(dlist, i, (void*)i));
		assert(i == dlist_find(dlist, dlist_data_cmp, (void*)i));		
	}

	data = dlist_length(dlist);
	for (i = 0; i < n; i++) {
		assert(DLIST_RET_OK == dlist_get_by_index(dlist, 0, (void**)&data));
		assert(i == data);
		assert(dlist_length(dlist) == (n-i));
		assert(dlist_delete(dlist, 0) == DLIST_RET_OK);
		assert(dlist_length(dlist) == (n-i-1));
		if ((i + 1) < n) {
			assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
			assert(data == (i+1));
		}
	}

	assert(dlist_length(dlist) == 0);
	for (i = 0; i < n; i++) {
		assert(dlist_prepend(dlist, (void*)i) == DLIST_RET_OK);
		assert(dlist_length(dlist) == i+1);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, 0 ,(void*)(2*i)) == DLIST_RET_OK);
		assert(dlist_get_by_index(dlist, 0, (void**)&data) == DLIST_RET_OK);
		assert(data == 2*i);
		assert(DLIST_RET_OK == dlist_set_by_index(dlist, 0, (void*)i));
	}
	i = n - 1;
	assert(DLIST_RET_OK == dlist_foreach(dlist, dlist_data_visit, &i));

	s = dlist_length(dlist);
	for (i = 0; i < n; i++) {
		assert(dlist_insert(dlist, i, (void*)i) == DLIST_RET_OK);
		assert(dlist_length(dlist) == (s+i+1));
		assert(dlist_get_by_index(dlist, i, (void**)&data) == DLIST_RET_OK);
		assert(data == i);
		assert(dlist_set_by_index(dlist, i, (void*)(2*i)) == DLIST_RET_OK);
		assert(dlist_get_by_index(dlist, i, (void**)&data) == DLISech(NULL, NULL, NULL) == DLIST_RET_INVALID_RET_OK);
		assert(data == 2*i);
	}	
	dlist_destroy(dlist);
		
	return;
}

static void test_invalid_params(void)
{
	assert(dlist_length(NULL) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_prepend(NULL, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_delete(NULL, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_insert(NULL, 0, NULL) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_set_by_index(NULL, 0, NULL) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_get_by_index(NULL, 0, NULL) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_find(NULL, NULL, NULL) < 0);
	assert(dlist_append(NULL, 0) == DLIST_RET_INVALID_PARAMS);
	assert(dlist_foreach(NULL, NULL, NULL) == DLIST_RET_INVALID_PARAMS);
}

int main(int argc,char** argv)
{
	printf("%s\n", "test_dlist_begin");
	test_int_dlist();
	return 0;
}

#endif /*DLIST_TEST*/


/*dlist.h*/
#include <stdio.h>

#ifndef _DLIST_H
#define _DLIST_H

#ifdef __cplusplus
extern "c" {
#endif /*__cplusplus*/

typedef enum _DListRet
{
    DLIST_RET_OK,
    DLIST_RET_OOM,
    DLIST_RET_STOP,
    DLIST_RET_INVALID_PARAMS,
    DLIST_RET_FAIL
} DListRet;

struct _DList;
typedef struct _DList DList;

typedef void (*DListDataDestroyFunc)(void* ctx, void* data);
typedef int (*DListDataCompareFunc)(void* ctx, void* data);
typedef DListRet (*DListDataVisitFunc)(void* ctx, void* data);

DList* dlist_create(DListDataDestroyFunc data_destroy, void* data_destroy_ctx);
DListRet dlist_insert(DList* thiz, size_t index, void* data);
DListRet dlist_prepend(DList* thiz, void* data);
DListRet dlist_append(DList* thiz, void* data);
DListRet dlist_delete(DList* thiz, size_t index);
DListRet dlist_get_by_index(DList* thiz, size_t index, void** data);
DListRet dlist_set_by_index(DList* thiz, size_t index, void* data);

size_t     dlist_length(DList* thiz);
int     dlist_find(DList* thiz, DListDataCompareFunc cmp, void* ctx);
DListRet dlist_foreach(DList* thiz, DListDataVisitFunc visit, void* ctx);

void dlist_destroy(DList* thiz);

#define return_if_fail(p) if (!(p)) \
    {printf("%s:%d Warning:"#p" failed.\n", \
        __func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if (!(p)) \
    {printf("%s:%d Warning:"#p" failed.\n", \
        __func__, __LINE__); return (ret);}

#ifdef __cplusplus
}
#endif /*__cplusplus*/

#endif /*_DLIST_H*/


/*Makefile*/all:    gcc -g -shared dlist.c -o libdlist.so    gcc -g -DDLIST_TEST dlist.c -o dlist_testclean:    rm  *test *.exe *.so *.o

   
posted @ 2011-08-14 23:06  $逝水无痕$  阅读(144)  评论(0编辑  收藏  举报