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*/


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