General Darray Implement by C
/*typedef.h*/ #ifndef _TYPEDEFS #define _TYPEDEFS typedef enum _Ret { RET_OK, RET_OOM, RET_STOP, RET_FAIL, RET_INVALID_PARAMS } Ret; typedef void (*DataDestroyFunc)(void* ctx, void* data); typedef int (*DataCompareFunc)(void* ctx, void* data); typedef Ret (*DataVisitFunc)(void* ctx, void* data); #ifdef __cplusplus #define DECLS_BEGIN extern "c" { #define DECLS_END } #else #define DECLS_BEGIN #define DECLS_END #endif #define return_val_if_fail(p, ret) if(!(p)) \ { printf("%d:%s Warning:"#p" failed.\n",\ __LINE__, __func__); return (ret);} #define return_if_fail(p) if(!(p)) \ { printf("%d:%s Warning:"#p" failed.\n",\ __LINE__, __func__); return;} #endif /*_TYPEDEFS*/ /*darray.h*/ #include <stdio.h> #include "typedefs.h" #ifndef _DARRAY_H #define _DARRAY_H DECLS_BEGIN struct _DArray; typedef struct _DArray DArray; DArray* darray_create(DataDestroyFunc data_destroy, void* ctx); Ret darray_insert(DArray* thiz, size_t index, void* data); Ret darray_append(DArray* thiz, void* data); Ret darray_prepend(DArray* thiz, void* data); size_t darray_length(DArray* thiz); Ret darray_get_by_index(DArray* thiz, size_t index, void** data); Ret darray_set_by_index(DArray* thiz, size_t index, void* data); int darray_find(DArray* thiz, DataCompareFunc cmp, void* data); Ret darray_delete(DArray* thiz, size_t index); Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx); void darray_destroy(DArray* thiz); DECLS_END #endif /*_DARRAY_H*/ /*darray.c*/ #include <stdlib.h> #include "darray.h" #define MIN_PRE_RELLOCATE_SIZE 10 struct _DArray { void** data; size_t size; size_t alloc_size; void* data_destroy_ctx; DataDestroyFunc data_destroy; }; static void darray_data_destroy(DArray* thiz, void* data) { if (thiz->data_destroy != NULL) { thiz->data_destroy(thiz->data_destroy_ctx, data); } return; } DArray* darray_create(DataDestroyFunc data_destroy, void* ctx) { DArray* thiz = malloc(sizeof(DArray)); if (thiz != NULL) { thiz->data = NULL; thiz->size = 0; thiz->alloc_size = 0; thiz->data_destroy = data_destroy; thiz->data_destroy_ctx = ctx; } return thiz; } static Ret darray_expand(DArray* thiz, size_t need_size) { return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); if (need_size + thiz->size > thiz->alloc_size) { size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_RELLOCATE_SIZE; void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size); if (data != NULL) { thiz->alloc_size = alloc_size; thiz->data = data; } } return (thiz->data == NULL) ? RET_FAIL : RET_OK; } Ret darray_insert(DArray* thiz, size_t index, void* data) { size_t cursor = index; Ret ret = RET_OOM; return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); cursor = cursor > thiz->size ? thiz->size : cursor; if (darray_expand(thiz, 1) == RET_OK) { size_t i = 0; for (i = thiz->size; i > cursor; i--) { thiz->data[i] = thiz->data[i-1]; } thiz->data[cursor] = data; thiz->size++; ret = RET_OK; } return ret; } Ret darray_append(DArray* thiz, void* data) { return darray_insert(thiz, -1, data); } Ret darray_prepend(DArray* thiz, void* data) { return darray_insert(thiz, 0, data); } size_t darray_length(DArray* thiz) { return_val_if_fail(thiz != NULL, 0); return thiz->size; } Ret darray_get_by_index(DArray* thiz, size_t index, void** data) { return_val_if_fail(thiz != NULL && thiz->data != NULL && index < thiz->size, RET_INVALID_PARAMS); *data = thiz->data[index]; return RET_OK; } Ret darray_set_by_index(DArray* thiz, size_t index, void* data) { return_val_if_fail(thiz != NULL && thiz->data != NULL && index < thiz->size, RET_INVALID_PARAMS); thiz->data[index] = data; return RET_OK; } int darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx) { size_t i = 0; return_val_if_fail(thiz != NULL && cmp != NULL, -1); for (i = 0; i < thiz->size; i++) { if (!cmp(ctx, thiz->data[i])) { break; } } return i; } static Ret darray_shrink(DArray* thiz) { return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); if ((thiz->size < (thiz->alloc_size>>1)) && (thiz->alloc_size > MIN_PRE_RELLOCATE_SIZE)) { size_t alloc_size = thiz->size + (thiz->size>>1); void** data = (void**)realloc(thiz->data ,sizeof(void*) * alloc_size); if (data != NULL) { thiz->alloc_size = alloc_size; thiz->data = data; } } return RET_OK; } Ret darray_delete(DArray* thiz, size_t index) { size_t i = 0; return_val_if_fail(thiz != NULL && thiz->data != NULL && index < thiz->size, RET_INVALID_PARAMS); darray_data_destroy(thiz, thiz->data[index]); for (i = index; i < thiz->size - 1; i++) { thiz->data[i] = thiz->data[i+1]; } thiz->size--; darray_shrink(thiz); return RET_OK; } void darray_destroy(DArray* thiz) { size_t i = 0; if (thiz != NULL) { for (i = 0; i < thiz->size; i++) { darray_data_destroy(thiz, thiz->data[i]); } } free(thiz->data); free(thiz); thiz->data = NULL; thiz = NULL; return; } Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx) { size_t i = 0; Ret ret = RET_OK; return_val_if_fail(thiz != NULL && thiz->data != NULL && visit != NULL, RET_INVALID_PARAMS); for (i = 0; i < thiz->size; i++) { ret = visit(ctx, thiz->data[i]); } return ret; } #ifdef DARRAY_TEST #include <assert.h> static void data_destroy(void* ctx, void* data) { return; } static int data_compare(void* ctx, void* data) { return (int)(ctx) - (int)data; } static Ret data_visit(void* ctx, void* data) { int* expected = (int*)ctx; assert((*expected) == (int)data); (*expected)--; return RET_OK; } static void test_int_darray() { DArray* thiz = darray_create(data_destroy, NULL); int n = 100; int data; int i = 0; for (i = 0; i < n; i++) { assert(RET_OK == darray_append(thiz, (void*)i)); assert(darray_length(thiz) == (i + 1)); assert(RET_OK == darray_get_by_index(thiz, i, (void**)&data)); assert(data == i); assert(RET_OK == darray_set_by_index(thiz, i, (void*)(2*i))); assert(RET_OK == darray_get_by_index(thiz, i, (void**)&data)); assert(data == 2*i); assert(RET_OK == darray_set_by_index(thiz, i, (void*)i)); assert(i == darray_find(thiz, data_compare, (void*)i)); } for (i = 0; i < n; i++) { assert(RET_OK == darray_get_by_index(thiz, 0, (void**)&data)); assert(data == i); assert(darray_length(thiz) == (n - i)); assert(RET_OK == darray_delete(thiz, 0)); if (i+1 < n) { assert(RET_OK == darray_get_by_index(thiz, 0, (void**)&data)); assert(data == (i+1)); } } assert(darray_length(thiz) == 0); for (i = 0; i < n; i++) { assert(RET_OK == darray_prepend(thiz, (void*)i)); assert(darray_length(thiz) == (i+1)); assert(RET_OK == darray_get_by_index(thiz, 0, (void**)&data)); assert(data == i); } i = n - 1; assert(RET_OK == darray_foreach(thiz, data_visit, (void*)&i)); darray_destroy(thiz); return; } static void test_invalid_params() { assert(RET_INVALID_PARAMS == darray_insert(NULL, 0, NULL)); assert(0 == darray_length(NULL)); assert(RET_INVALID_PARAMS == darray_prepend(NULL, NULL)); assert(RET_INVALID_PARAMS == darray_append(NULL, NULL)); assert(darray_find(NULL, NULL, NULL) < 0); assert(RET_INVALID_PARAMS == darray_foreach(NULL, NULL, NULL)); assert(RET_INVALID_PARAMS == darray_delete(NULL, 0)); assert(RET_INVALID_PARAMS == darray_set_by_index(NULL, 0, NULL)); assert(RET_INVALID_PARAMS == darray_get_by_index(NULL, 0, NULL)); } int main() { test_int_darray(); test_invalid_params(); return 0; } #endif /*DARRAY_TEST*/
不积跬步无以至千里,不积小流无以成江河。