A Generic vector implementation in C

来源:互联网 发布:iphone广播软件 编辑:程序博客网 时间:2024/05/29 04:46

在被 linux 的 include/list.h 打击到彻底失去信心之前赶快贴过来,立此存照。

#include <string.h>#include <assert.h>#include <stdlib.h>#include <stdio.h>struct _elem_type_tag{  size_t _type_size;  int (*equals) (void *v1, void *v2, struct _elem_type_tag * tag);  int (*greater) (void *v1, void *v2, struct _elem_type_tag * tag);  void (*assign) (void *v1, void *v2, struct _elem_type_tag * tag);};intdefault_equals (void *v1, void *v2, struct _elem_type_tag *tag){  return memcmp (v1, v2, tag->_type_size) == 0;}intdefault_greater (void *v1, void *v2, struct _elem_type_tag *tag){  return memcmp (v1, v2, tag->_type_size) > 0;}voiddefault_assign (void *v1, void *v2, struct _elem_type_tag *tag){  memcpy (v1, v2, tag->_type_size);}#define vt(type) struct vector_##typestruct vector_op{  int (*push_back) (void *p, void *vp /* vt(type) * */ );  int (*pop_back) (void *p, void *vp);  int (*get_size) (int *sz, void *vp);};struct default_vector{  void *baseaddr;  size_t bufsz;  size_t elemcount;  struct _elem_type_tag *ttag;  struct vector_op *vop;};intdefault_push_back (void *p, void *vp){  struct default_vector *dv = (struct default_vector *) vp;  struct _elem_type_tag *ttag = dv->ttag;  unsigned char *baddr = dv->baseaddr;  size_t esz = ttag->_type_size;  if (dv->elemcount * esz == dv->bufsz)    {      /* insufficient buffer */      unsigned nelem = dv->elemcount * 1.5;      nelem = nelem == 0 ? 10 : nelem;      unsigned char *nbuf = calloc (nelem, ttag->_type_size);      if (!nbuf)        return 0;      memmove (nbuf, dv->baseaddr, dv->bufsz);      dv->ttag->assign (nbuf + dv->bufsz, p, ttag);      dv->baseaddr = nbuf;      dv->bufsz = nelem * ttag->_type_size;    }  else    {      dv->ttag->assign (baddr + dv->elemcount * ttag->_type_size, p, ttag);    }  dv->elemcount += 1;  return 1;}intdefault_pop_back (void *p, void *vp){  struct default_vector *dv = (struct default_vector *) vp;  struct _elem_type_tag *ttag = dv->ttag;  unsigned char *baddr = dv->baseaddr;  if (dv->elemcount > 0)    {      ttag->assign (p, baddr + (dv->elemcount - 1) * ttag->_type_size, ttag);      dv->elemcount -= 1;      return 1;    }  return 0;}intdefault_get_size (int *sz, void *vp){  struct default_vector *dv = (struct default_vector *) vp;  if (!sz)    return 0;  *sz = (int) dv->elemcount;  return 1;}#define def_vt(type) struct vector_##type { /  void *baseaddr; /  size_t bufsz; /  size_t elemcount; //  struct _elem_type_tag *ttag; /  struct vector_op *vop; /}#define define_vt(type,traits,tvop) /  { /    .baseaddr = NULL, /    .elemcount = 0, /    .ttag = &traits, /    .vop = &tvop, /  }def_vt (int);def_vt (double);struct _elem_type_tag default_ttag = {  .equals = default_equals,  .greater = default_greater,  .assign = default_assign,};struct vector_op default_vop = {  .push_back = default_push_back,  .pop_back = default_pop_back,  .get_size = default_get_size,};intmain (){  double dt;  int it;  int iv = 1;  vt (int) vint = define_vt (int, default_ttag, default_vop);  vint.ttag->_type_size = sizeof (int);  vt (double) vd = define_vt (double, default_ttag, default_vop);  vd.ttag->_type_size = sizeof (double);  vint.vop->push_back (&iv, &vint);  vint.vop->pop_back (&it, &vint);  printf ("Value poped: %d/n", it);  dt = 2.0;  vd.vop->push_back (&dt, &vd);  vd.vop->pop_back (&dt, &vd);  printf ("Value poped: %e/n", dt);  return 0;}

基本达到最初步的要求,可以在同一个编译单元内混和使用多种类型“实例化”的“模板类型”了。default_* 是利用 type size 做的假泛型。要真泛型的,自己定义 struct _elem_type_tag 和 struct vector_op 就可以。这里 _elem_type_tag 就相当于 STL 的 type traits 的作用。实际上,我的代码中 vector_op 使用了 template method 模式,调用 _elem_type_tag 里的赋值方法,应该基本少有重新定义 vector_op 的必要性。