利用C实现泛型效果(generics)---vector

一般来说,数据(比如一个struct)在内存中,有的部分是定长的(比如int,double或指针),有的数据不定长(比如c字符串),不定长的部分一般通过指针链接到定长的部分中。


对于一个通用的vector,一般包含四部分,每个元素占内存的大小elemSize,已分配内存的元素个数allocatedSize,实际存储元素个数logicalSize,指向已分配内存的指针void* data,其中的指针可通过运算指向vector中任一元素。


情况1:如果数据不包含不定长部分,使用vector时只需将数据拷贝到vector中就可以了。

情况2:如果数据包含不定长部分,由用户负责不定长部分的内存分配和释放,使用vector方法与情况1类似。

情况3:数据包含不定长部分,由vector负责整个数据的内存分配与释放,将数据拷贝到vector中时,vector要申请额外内存空间复制不定长的部分,当从vector中删除数据时,vector要首先释放不定长部分的内存,然后删除定长的部分。


再赋予vector自动排序和检索的功能,因此vector中添加了三个额外的函数,分别是:

提供两数据地址比较两数据大小的cmpfn

提供数据地址释放其不定长部分内存空间的freefn

提供源数据和目的数据的地址,为目的数据中不定长部分申请内存空间,将源数据中不定长部分拷贝到目的数据中不定长部分的copyfn。


以下是通用vector的头文件,实现文件与简单测试文件:

#ifndef _VECTOR_H_
#define _VECTOR_H_

typedef int (*VectorCompareFunction)(const void* elemAddr1, const void* elemAddr2);
typedef void (*VectorMapFunction)(void* elemAddr, void* auxData);
typedef void (*VectorFreeFunction)(void* elemAddr);
typedef void (*VectorCopyFunction)(void* destAddr, const void* srcAddr);

typedef struct{
void* data;
int elemSize;
int allocatedSize;
int logicalSize;
VectorFreeFunction freefn;
VectorCopyFunction copyfn;
VectorCompareFunction cmpfn;
} vector;

void VectorNew(vector* v, int elemSize, VectorFreeFunction freefn, VectorCopyFunction copyfn, VectorCompareFunction cmpfn);
void VectorDispose(vector* v);
int VectorLength(const vector* v);
void* VectorNth(const vector* v, int position);
void VectorInsert(vector* v, const void* elemAddr, int position);
void VectorAppend(vector* v, const void* elemAddr);
void VectorReplace(vector* v, const void* elemAddr, int position);
void VectorDelete(vector* v, int position);
int VectorSearch(vector* v, const void* key, int startIndex, bool isSorted);
void VectorSort(vector* v);
void VectorMap(vector* v, VectorMapFunction mapfn, void* auxData);

#endif
#include "vector.h"
#include <stdlib.h>
#include <assert.h>
#include <string.h>

void VectorNew(vector* v, int elemSize, VectorFreeFunction freefn, VectorCopyFunction copyfn, VectorCompareFunction cmpfn) {
    v->elemSize = elemSize;
    v->allocatedSize = 4;
    v->logicalSize = 0;
    v->data = malloc(v->allocatedSize * v->elemSize);
    assert(v->data != NULL);
    v->freefn = freefn;
	v->copyfn = copyfn;
    v->cmpfn = cmpfn;
}

void VectorDispose(vector* v) {
	if(v->freefn != NULL) {
		for(int i=0; i<v->logicalSize; i++) {
			void* elemAddr = (char*)v->data + i * v->elemSize;
			v->freefn(elemAddr);
		}
	}
	free(v->data);
}

int VectorLength(const vector* v) {
    return v->logicalSize;
}

void* VectorNth(const vector* v, int position) {
    assert((position>=0) && (position<v->logicalSize));
    return (char*)v->data + position * v->elemSize;
}

static void VectorGrow(vector* v) {
    v->data = realloc(v->data, 2*v->allocatedSize*v->elemSize);
    assert(v->data != NULL);
    v->allocatedSize *= 2;
}

void VectorInsert(vector* v, const void* elemAddr, int position) {
    assert((position>=0) && (position<=v->logicalSize));
    if(v->logicalSize == v->allocatedSize)
        VectorGrow(v);
	void* srcAddr = (char*)v->data + position * v->elemSize;
    int byteCount = (v->logicalSize - position) * v->elemSize;
    memmove((char*)srcAddr+v->elemSize, srcAddr, byteCount);
    memcpy(srcAddr, elemAddr, v->elemSize);
	if(v->copyfn != NULL)
		v->copyfn(srcAddr, elemAddr);
    v->logicalSize++;
}

void VectorAppend(vector* v, const void* elemAddr) {
    if(v->logicalSize == v->allocatedSize)
        VectorGrow(v);
    void* destAddr = (char*)v->data + v->logicalSize * v->elemSize;
    memcpy(destAddr, elemAddr, v->elemSize);
	if(v->copyfn != NULL)
		v->copyfn(destAddr, elemAddr);
    v->logicalSize++;
}

void VectorReplace(vector* v, const void* elemAddr, int position) {
    assert((position>=0) && (position<v->logicalSize));
    void* destAddr = (char*)v->data + position * v->elemSize;
	if(v->freefn !=	NULL)
		v->freefn(destAddr);
	memcpy(destAddr, elemAddr, v->elemSize);
	if(v->copyfn != NULL)
		v->copyfn(destAddr, elemAddr);
}

void VectorDelete(vector* v, int position) {
    assert((position>=0) && (position<v->logicalSize));
    void* destAddr = (char*)v->data + position * v->elemSize;
    if(v->freefn != NULL)
		v->freefn(destAddr);
	int byteCount = (v->logicalSize-1 - position) * v->elemSize;
    memmove(destAddr, (char*)destAddr+v->elemSize, byteCount);
    v->logicalSize--;
}

void VectorSort(vector* v) {
    assert(v->cmpfn != NULL);
	qsort(v->data, v->logicalSize, v->elemSize, v->cmpfn);
}

int VectorSearch(vector* v, const void* key, int startIndex, bool isSorted) {
	assert(v->cmpfn != NULL);
	assert((startIndex>=0) && (startIndex<=v->logicalSize));
	void* base = (char*)v->data + startIndex * v->elemSize;
	int num = v->logicalSize - startIndex;
	int keyIndex = -1;
	if(isSorted == true) {
		void* result = bsearch(key, base, num, v->elemSize, v->cmpfn);
		if(result != NULL)
			keyIndex = ((char*)result - (char*)v->data) / v->elemSize;
		return keyIndex;
	}
	for(int i=0; i<num; i++) {
		void* elemAddr = (char*)base + i * v->elemSize;
		if(v->cmpfn(elemAddr, key) == 0) {
			keyIndex = i + startIndex;
			break;
		}
	}
	return keyIndex;
}

void VectorMap(vector* v, VectorMapFunction mapfn, void* auxData) {
	for(int i=0; i<v->logicalSize; i++) {
		void* elemAddr = (char*)v->data + i * v->elemSize;
		mapfn(elemAddr, auxData);
	}
}
#include "vector.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

int int_cmp(const void* elemAddr1, const void* elemAddr2) {
	return *(int*)elemAddr1 - *(int*)elemAddr2;
}

int cstr_cmp(const void* elemAddr1, const void* elemAddr2) {
	return strcmp(*(char**)elemAddr1, *(char**)elemAddr2);
}

void cstr_copy(void* destAddr, const void* srcAddr) {
	*(char**)destAddr = strdup(*(char**)srcAddr);
}

void cstr_free(void* elemAddr) {
	free(*(char**)elemAddr);
}

void int_accumulation(void* elemAddr, void* auxData) {
	*(int*)auxData += *(int*)elemAddr;
}

void cstr_total_lens(void* elemAddr, void* auxData) {
	*(int*)auxData += strlen(*(char**)elemAddr);
}

void cstr_concat_all(void* elemAddr, void* auxData) {
	strcat((char*)auxData, *(char**)elemAddr);
}

int main(int argc, char** argv) {
	vector v;
	int int_array[] = {0, 1, 2, 3, 4, 5};
	VectorNew(&v, sizeof(int), NULL, NULL, int_cmp);
	printf("Initialize an int vector.\n");
	printf("VectorLength:%d.\n", VectorLength(&v));
	for(int i=0; i<sizeof(int_array)/sizeof(int); i++) {
		VectorInsert(&v, &int_array[i], 0);
		VectorAppend(&v, &int_array[i]);
	}
	printf("Elements in vector:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%d ", *(int*)VectorNth(&v, i));
	}
	printf("\n");
	for(int i=11; i>5; i--) {
		VectorReplace(&v, (char*)v.data+i*v.elemSize, 11-i);
		VectorDelete(&v, i);
	}
	printf("Elements in vector after replace/delete:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%d ", *(int*)VectorNth(&v, i));
	}
	printf("\n");
	VectorSort(&v);
	printf("first search:%d\n", VectorSearch(&v, &int_array[2], 1, false));
	printf("second search:%d\n", VectorSearch(&v, &int_array[3], 1, true));
	printf("third search:%d\n", VectorSearch(&v, &int_array[4], 6, false));
	printf("forth search:%d\n", VectorSearch(&v, &int_array[5], 6, true));
	int sum = 0;
	VectorMap(&v, int_accumulation, &sum);
	printf("sum of the vector:%d\n", sum);
	VectorDispose(&v);
	
	char* cstr_array[] = {"wo", "ai", "tian", "an", "men", "hahha"};
	VectorNew(&v, sizeof(char*), cstr_free, cstr_copy, cstr_cmp);
	printf("Initialize an int vector.\n");
	printf("VectorLength:%d.\n", VectorLength(&v));
	for(int i=0; i<sizeof(cstr_array)/sizeof(char*); i++) {
		VectorInsert(&v, &cstr_array[i], 0);
		VectorAppend(&v, &cstr_array[i]);
	}
	printf("Elements in vector:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%s ", *(char**)VectorNth(&v, i));
	}
	printf("\n");
	for(int i=11; i>5; i--) {
		VectorReplace(&v, (char*)v.data+i*v.elemSize, 11-i);
		VectorDelete(&v, i);
	}
	VectorSort(&v);
	printf("Elements in vector after replace/delete/sort:");
	for(int i=0; i<VectorLength(&v); i++) {
		printf("%s ", *(char**)VectorNth(&v, i));
	}
	printf("\n");
	printf("first search %s from index 1:%d\n", cstr_array[2], VectorSearch(&v, cstr_array+2, 1, false));
	printf("second search %s from index 1:%d\n", cstr_array[3], VectorSearch(&v, cstr_array+3, 1, true));
	int total_lens = 0;
	VectorMap(&v, cstr_total_lens, &total_lens);
	printf("toatal of the vector:%d\n", total_lens);
	char* str_all = (char*)malloc(total_lens + 1);
	str_all[0] = 0;
	VectorMap(&v, cstr_concat_all, str_all);
	printf("str_all is %s\n", str_all);
	VectorDispose(&v);
	return 0;
}
另外VectorMapFunction仿照函数式编程的风格,可将一个函数应用在vector遍历数据中,并将返回结果存入*auxData。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值