当前位置: 首页 > 工具软件 > Flite > 使用案例 >

[flite源码分析一]常用数据结构cst_val

方飞白
2023-12-01

flite里的基础数据结构,最常见的是cst_val.这个结构设计的很巧妙.

有如下特点

  1. 最基础的数据结构,可以用于存储int,float,string,和其他对象.同样可以存放列表和树.
  2. cst_val结构很巧妙的设计成只占用8字节(也可能是16字节在64位机器上). 
  3. cst_val内部分为栈类型(atomic)和堆类型(cons). 其中,堆类型是引用计数的.

有关cons,可以参考本文最后的一个小介绍.

cst_val定义


一个优雅的union体,能文能武.既可以当基础类型使用,也可以当作复合类型使用

typedef struct  cst_val_struct {
    union
    {
    cst_val_cons cc;
    cst_val_atom a;
    } c;
} cst_val;

堆类型

typedef struct  cst_val_cons_struct {
    struct cst_val_struct *car;
    struct cst_val_struct *cdr;
}  cst_val_cons;

栈类型

typedef struct  cst_val_atom_struct {
#ifdef WORDS_BIGENDIAN
    short ref_count;
    short type;  /* order is here important */
#else
#if (defined(__x86_64__) || defined(_M_X64))
    int type;  /* order is here important */
    int ref_count;
#else
    short type;  /* order is here important */
    short ref_count;
#endif
#endif
    union 
    {
#if (defined(__x86_64__) || defined(_M_X64))
        double fval;
        long long ival;
        void *vval;
#else
        float fval;
        int ival;
        void *vval;
#endif
    } v;
} cst_val_atom;

常用的宏定义

/* Only CONS can be an even number */
#define CST_VAL_TYPE_CONS    0
#define CST_VAL_TYPE_INT     1
#define CST_VAL_TYPE_FLOAT   3
#define CST_VAL_TYPE_STRING  5
#define CST_VAL_TYPE_FIRST_FREE 7
#define CST_VAL_TYPE_MAX     54

#define CST_VAL_STRING_LVAL(X) ((X)->c.a.v.vval)
#define CST_VAL_TYPE(X) ((X)->c.a.type)
#define CST_VAL_INT(X) ((X)->c.a.v.ival)
#define CST_VAL_FLOAT(X) ((X)->c.a.v.fval)
#define CST_VAL_STRING(X) ((const char *)(CST_VAL_STRING_LVAL(X)))
#define CST_VAL_VOID(X) ((X)->c.a.v.vval)
#define CST_VAL_CAR(X) ((X)->c.cc.car)
#define CST_VAL_CDR(X) ((X)->c.cc.cdr)

#define CST_VAL_REFCOUNT(X) ((X)->c.a.ref_count)


常用的基础类型转换

cst_val *int_val(int i)
{
    cst_val *v = new_val();
    CST_VAL_TYPE(v) = CST_VAL_TYPE_INT;
    CST_VAL_INT(v) = i;
    return v;
}
    
cst_val *float_val(float f)
{
    cst_val *v = new_val();
    CST_VAL_TYPE(v) = CST_VAL_TYPE_FLOAT;
    CST_VAL_FLOAT(v) = f;
    return v;
}

cst_val *string_val(const char *s)
{
    cst_val *v = new_val();
    CST_VAL_TYPE(v) = CST_VAL_TYPE_STRING;
    /* would be nice to note if this is a deletable string or not */
    CST_VAL_STRING_LVAL(v) = cst_strdup(s);
    return v;
}

int val_int(const cst_val *v)
{
    if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_INT))
    return CST_VAL_INT(v);
    else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT))
    return (int)CST_VAL_FLOAT(v);
    else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING))
    return atoi(CST_VAL_STRING(v));
    else
    {
    cst_errmsg("VAL: tried to access int in %d typed val\n",
           (v ? CST_VAL_TYPE(v) : -1));
    cst_error();
    }
    return 0;
}

float val_float(const cst_val *v)
{
    if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_INT))
    return (float)CST_VAL_INT(v);
    else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT))
    return CST_VAL_FLOAT(v);
    else if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING))
    return cst_atof(CST_VAL_STRING(v));
    else
    {
    cst_errmsg("VAL: tried to access float in %d typed val\n",
           (v ? CST_VAL_TYPE(v) : -1));
    cst_error();
    }
    return 0;
}

const char *val_string(const cst_val *v)
{
    if (v && (CST_VAL_TYPE(v) == CST_VAL_TYPE_STRING))
    return CST_VAL_STRING(v);
    else
    {
    cst_errmsg("VAL: tried to access string in %d typed val\n",
           (v ? CST_VAL_TYPE(v) : -1));
    cst_error();
    }
    return 0;
}

const cst_val *val_car(const cst_val *v)
{
    if (v && cst_val_consp(v))
    return CST_VAL_CAR(v);
    else
    {
    cst_errmsg("VAL: tried to access car in %d typed val\n",
           (v ? CST_VAL_TYPE(v) : -1));
    cst_error();
    }
    return 0;
}

const cst_val *val_cdr(const cst_val *v)
{
    if (v && cst_val_consp(v))
    return CST_VAL_CDR(v);
    else
    {
    cst_errmsg("VAL: tried to access cdr in %d typed val\n",
           (v ? CST_VAL_TYPE(v) : -1));
    cst_error();
    }
    return 0;
}

void *val_generic(const cst_val *v, int type, const char *stype)
{   /* a generic access function that checks the expected type */
    if (v && CST_VAL_TYPE(v) == type)
    return CST_VAL_VOID(v);
    else
    {
        cst_errmsg("VAL: tried to access %s in %d type val\n",
                       stype,
                       (v ? CST_VAL_TYPE(v) : -1));
        cst_error();
    }
    return NULL;
}

void *val_void(const cst_val *v)
{
    /* The scary, do anything function, this shouldn't be called by mortals */
    if ((v == NULL) ||
    (CST_VAL_TYPE(v) == CST_VAL_TYPE_CONS) ||
    (CST_VAL_TYPE(v) == CST_VAL_TYPE_INT) ||
    (CST_VAL_TYPE(v) == CST_VAL_TYPE_FLOAT))
    {
    cst_errmsg("VAL: tried to access void in %d typed val\n",
           (v ? CST_VAL_TYPE(v) : -1));
    cst_error();
    return NULL;
    }
    else 
    return CST_VAL_VOID(v);
}

 

cons类型与cst_val转换
 

cst_val *cons_val(const cst_val *a, const cst_val *b)
{
    cst_val *v = new_val();
    CST_VAL_CAR(v)=((!a || cst_val_consp(a)) ? 
            (cst_val *)(void *)a:val_inc_refcount(a));
    CST_VAL_CDR(v)=((!b || cst_val_consp(b)) ? 
            (cst_val *)(void *)b:val_inc_refcount(b));
    return v;
}

const cst_val *val_car(const cst_val *v)
{
    if (v && cst_val_consp(v))
	return CST_VAL_CAR(v);
    else
    {
	cst_errmsg("VAL: tried to access car in %d typed val\n",
		   (v ? CST_VAL_TYPE(v) : -1));
	cst_error();
    }
    return 0;
}

const cst_val *val_cdr(const cst_val *v)
{
    if (v && cst_val_consp(v))
	return CST_VAL_CDR(v);
    else
    {
	cst_errmsg("VAL: tried to access cdr in %d typed val\n",
		   (v ? CST_VAL_TYPE(v) : -1));
	cst_error();
    }
    return 0;
}

const cst_val *set_cdr(cst_val *v1, const cst_val *v2)
{
    /* destructive set cdr, be careful you have a pointer to current cdr */
    
    if (!cst_val_consp(v1))
    {
	cst_errmsg("VAL: tried to set cdr of non-consp cell\n");
	cst_error();
	return NULL;
    }
    else
    {
        if (CST_VAL_CDR(v1))
        {
            val_dec_refcount(CST_VAL_CDR(v1));
            val_inc_refcount(v1);
        }
	CST_VAL_CDR(v1) = (cst_val *)v2;
    }
    return v1;
}

const cst_val *set_car(cst_val *v1, const cst_val *v2)
{
    /* destructive set car, be careful you have a pointer to current car */
    
    if (!cst_val_consp(v1))
    {
	cst_errmsg("VAL: tried to set car of non-consp cell\n");
	cst_error();
	return NULL;
    }
    else
    {
	val_dec_refcount(CST_VAL_CAR(v1));
	val_inc_refcount(v1);
	CST_VAL_CAR(v1) = (cst_val *)v2;
    }
    return v1;
}

 

基础使用样例

atomic类型使用

    cst_val* val1 = int_val(1);
    printf("%lld\n", CST_VAL_INT(val1));

    cst_val* val2 = string_val("this is test");
    printf("%s\n", CST_VAL_STRING(val2));

    delete_val(val1);
    delete_val(val2);

cons类型使用

    cst_val* val1 = int_val(1);
    cst_val* val2 = string_val("this is test");
    
    cst_val* con1 = cons_val(val1, val2);

    const cst_val* tmp1 = val_car(con1);
    printf("%lld\n", CST_VAL_INT(tmp1));

    const cst_val* tmp2 = val_cdr(con1);
    printf("%s\n", CST_VAL_STRING(tmp2));

//    delete_val(val1);
//    delete_val(val2);
    delete_val(con1);

什么是cons,car,cdr?

这三个名词是LISP语音的, cons是construct的简写,是指从堆上分配内存的类型

car,发音/kɑːr/ 是"Contents of the Address part of the Register"的缩写,而cdr,发音/ˈkʌdər/,是"Contents of the Decrement Register"的缩写.

car从cons中取出第一个指针;cdr从cons中取出第二个.

 

更多历史故事,请参考CAR and CDR

 类似资料: