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
不积跬步无以至千里,不积小流无以成江河。