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

浙公网安备 33010602011771号