tolua++的一些api的

1:TOLUA_API void tolua_usertype (lua_State* L, const char* type)

 作用:注册type类型的用户类,建立table-->type和type-->table的双向映射。
源代码和分析:

TOLUA_API void tolua_usertype (lua_State* L, const char* type)
{
    char ctype[128] = "const ";
    strncat(ctype,type,120);

    /* create both metatables */
	//同时创建type类型和const type类型。并且const type为type的父类
    if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
        mapsuper(L,type,ctype);             /* 'type' is also a 'const type' */
}

static int tolua_newmetatable (lua_State* L, const char* name)
{
	//创建一个table,并且在注册表中与name对应 reg[name] = mt
    int r = luaL_newmetatable(L,name);

#ifdef LUA_VERSION_NUM /* only lua 5.1 */
    if (r) {
        lua_pushvalue(L, -1);
        lua_pushstring(L, name);
//同时建立反向映射,这样就可以根据一个name对应的用户类型变量找到该变量的类名
//将类名和某一种类名进行比较,就可以判断是不是某种类型。
 
 
        lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */
    };
#endif

    if (r)
        tolua_classevents(L); /* set meta events */ //向metatable中注册各种元方法,比如:__index,__newindex,__add等等
    lua_pop(L,1);
    return r;
}

2:static void mapsuper (lua_State* L, const char* name, const char* base)

 作用:将base设置成name的基类,并且将base的全部父类也设置成name的基类


源代码和分析:

static void mapsuper (lua_State* L, const char* name, const char* base)
{
    /* push registry.super */
    lua_pushstring(L,"tolua_super");//-1
    lua_rawget(L,LUA_REGISTRYINDEX);    /* stack: super */
    luaL_getmetatable(L,name);          /* stack: super mt */
    lua_rawget(L,-2);                   /* stack: super table */
    if (lua_isnil(L,-1))
    {
        /* create table */
        lua_pop(L,1);
        lua_newtable(L);                    /* stack: super table */
        luaL_getmetatable(L,name);          /* stack: super table mt */
        lua_pushvalue(L,-2);                /* stack: super table mt table */
        lua_rawset(L,-4);                   /* stack: super table */

<span style="white-space:pre">	</span>//tolua_super在 注册表中也对应一张表,表的内容为:
<span style="white-space:pre">	</span>//table[key] = value,key是:用户类型对应的表,value是:一张表 
<span style="white-space:pre">	</span>//以name = cc.Node为例,全局表:G_Table,tolua_super对应的表:Super_Table 
<span style="white-space:pre">	</span>//ta = G_Table[name] Super_Table[ta] = tb(tb就是name在Super_Table中对应的表),它的具体数据看下面

<span style="white-space:pre">	</span>//我们简称tb为name的父类表
    }
//开始往tb中塞数据
    /* set base as super class */
//先把直接父类塞进去
    lua_pushstring(L,base);
    lua_pushboolean(L,1);
    lua_rawset(L,-3);                    /* stack: super table */


//再把父类的所有父类塞进去,即将父类对应的父类表中所有的数据拷贝到子类的父类表中去
    /* set all super class of base as super class of name */
    luaL_getmetatable(L,base);          /* stack: super table base_mt */
//获取base对应的父类表,接下来就是遍历父类表吧
    lua_rawget(L,-3);                   /* stack: super table base_table */
    if (lua_istable(L,-1))
    {
        /* traverse base table */
        lua_pushnil(L);  /* first key */
        while (lua_next(L,-2) != 0)
        {
            /* stack: ... base_table key value */
            lua_pushvalue(L,-2);    /* stack: ... base_table key value key */
            lua_insert(L,-2);       /* stack: ... base_table key key value */
            lua_rawset(L,-5);       /* stack: ... base_table key */
        }
    }
    lua_pop(L,3);                       /* stack: <empty> */
}


3:TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col)

 作用:并且设置该lua类的父类,lname:我的理解是该lua类的模块名,name:类名, base:父类名


例子:cc.Node的表注册结构:

global_table

-cc_table

-Node_table

源码和分析:

TOLUA_API void tolua_cclass (lua_State* L, const char* lname, const char* name, const char* base, lua_CFunction col)
{
    char cname[128] = "const ";
    char cbase[128] = "const ";
    strncat(cname,name,120);
    strncat(cbase,base,120);



    mapinheritance(L,name,base);//设置base表为name表的元表,继承啊!!这样才可以访问到父类的成员。还有创建tolua_ubox表。
    mapinheritance(L,cname,name);

    mapsuper(L,cname,cbase);//拷贝父类
    mapsuper(L,name,base);

    lua_pushstring(L,lname);

    push_collector(L, name, col);//设置表的.collector函数
    /*
    luaL_getmetatable(L,name);
    lua_pushstring(L,".collector");
    lua_pushcfunction(L,col);

    lua_rawset(L,-3);
    */

    luaL_getmetatable(L,name);
	//向当前的模块进行注册 如果当前的模块名是cc,lname为Node,那么cc_module_table[lname] = name_table
    lua_rawset(L,-3);              /* assign class metatable to module */

    /* now we also need to store the collector table for the const
       instances of the class */
    push_collector(L, cname, col);
    /*
    luaL_getmetatable(L,cname);
    lua_pushstring(L,".collector");
    lua_pushcfunction(L,col);
    lua_rawset(L,-3);
    lua_pop(L,1);
    */
}

4:TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)

作用:尝试创建一个模块。
实现方式:以name为key,模块表为value放入到父模块表中。如果存在name的表,那么不做操作,否则创建一个呗。一般来说在tolua_cclass中已经注册过了。
源码和分析:

TOLUA_API void tolua_module (lua_State* L, const char* name, int hasvar)
{
    if (name)
    {
        /* tolua module */
        lua_pushstring(L,name);
        lua_rawget(L,-2);//拿到name在当前模块表中是否进行了注册
        if (!lua_istable(L,-1))  /* check if module already exists */
        {
			//没有注册过,new一个
            lua_pop(L,1);
            lua_newtable(L);
            lua_pushstring(L,name);
            lua_pushvalue(L,-2);
			//注册到当前模块表中去
            lua_rawset(L,-4);       /* assing module into module */
        }
    }
    else
    {
        /* global table */
		//这个是全局表,会被最先放入到栈中去。因为它是所有其他根模块的进行注册的地方
        lua_pushvalue(L,LUA_GLOBALSINDEX);
    }
   .......
    lua_pop(L,1);               /* pop module */
}

5:TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)

作用:顾名思义,开始一个模块

实现方式:将name对应的模块表放入到栈顶。

源码和分析:(这个貌似不需要解释吧,很简单)

TOLUA_API void tolua_beginmodule (lua_State* L, const char* name)
{
    if (name)
    {
        lua_pushstring(L,name);
        lua_rawget(L,-2);
    }
    else
        lua_pushvalue(L,LUA_GLOBALSINDEX);
}


6:int lua_isusertype (lua_State* L, int lo, const char* type)

源码和分析:(不多说,都在代码中)

//作用:判断在lua栈中的lo位置的类型是不是type(不要忘了父类哟!!)。
//type:要比较的类型名
int lua_isusertype (lua_State* L, int lo, const char* type)
{
	
    if (!lua_isuserdata(L,lo)) {
        if (!push_table_instance(L, lo)) {
            return 0;
        };
    };
    {
        /* check if it is of the same type */
        int r;
        const char *tn;
		//获取到lo位置的userdata的metatable表
        if (lua_getmetatable(L,lo))        /* if metatable? */
        {
			//当创建类的时候,会进行双向映射,所以可以根据table获取类名
            lua_rawget(L,LUA_REGISTRYINDEX);  /* get registry[mt] */
            tn = lua_tostring(L,-1);
            r = tn && (strcmp(tn,type) == 0);//如果对应的类名就是type,那么loc位置的userdata就是对应type类型 
            lua_pop(L, 1);
            if (r)
                return 1;
            else
            {
		//不要忘了所有的父类哟!!还记得父类是怎么实现的么,详细请参考:tolua_map.mapsuper()

                /* check if it is a specialized class */
                lua_pushstring(L,"tolua_super");
                lua_rawget(L,LUA_REGISTRYINDEX); /* get super */
                lua_getmetatable(L,lo);
                lua_rawget(L,-2);                /* get super[mt] */
                if (lua_istable(L,-1))
                {
                    int b;
                    lua_pushstring(L,type);
                    lua_rawget(L,-2);                /* get super[mt][type] */
                    b = lua_toboolean(L,-1);
                    lua_pop(L,3);
                    if (b)
                        return 1;
                }
            }
        }
    }
    return 0;
}

大概流程是这样的:先获取该位置的userdata的metatable,再根据注册表拿到它对应的类型,判断该类型是不是type或者type是它的父类。


7:static void mapinheritance (lua_State* L, const char* name, const char* base)

static void mapinheritance (lua_State* L, const char* name, const char* base)
{
    /* set metatable inheritance */
    luaL_getmetatable(L,name);

    if (base && *base)
        luaL_getmetatable(L,base);
    else {

        if (lua_getmetatable(L, -1)) { /* already has a mt, we don't overwrite it */
            lua_pop(L, 2);
            return;
        };
        luaL_getmetatable(L,"tolua_commonclass");
    };

    set_ubox(L);

    lua_setmetatable(L,-2);
    lua_pop(L,1);
}

这个比较简单,就是两个功能。提前说一下:set_ubox是设置该表的tolua_ubox表,具体tolua_ubox数据是什么样的下面再讲。还有就是设置name表的metatable为base表。


8:static void set_ubox(lua_State* L)

static void set_ubox(lua_State* L) {

    /* mt basemt */
    if (!lua_isnil(L, -1)) {
        lua_pushstring(L, "tolua_ubox");
        lua_rawget(L,-2);//获取base表中的tolua_ubox值
    } else {
        lua_pushnil(L);
    };

    /* mt basemt base_ubox */
    if (!lua_isnil(L,-1)) {
		//得到父类tolua_ubox表
        lua_pushstring(L, "tolua_ubox");
        lua_insert(L, -2);
        /* mt basemt key ubox */
        lua_rawset(L,-4);
        /* (mt with ubox) basemt */
    } else {
        /* mt basemt nil */
		//如果不存在base或者base中没有tolua_ubox,那么为子类创建一个弱引用的tolua_ubox表
        lua_pop(L, 1);
        lua_pushstring(L,"tolua_ubox");
        lua_newtable(L);
        /* make weak value metatable for ubox table to allow userdata to be
        garbage-collected */
        lua_newtable(L);
        lua_pushliteral(L, "__mode");
        lua_pushliteral(L, "v");//值为弱引用
        lua_rawset(L, -3);               /* stack: string ubox mt */
        lua_setmetatable(L, -2);  /* stack:mt basemt string ubox */
        lua_rawset(L,-4);
    };

};

创建tolua_ubox表,这是一个弱值表,里面的数据是:ptr--->userdata。这个在这里是看不出来的,要到生成C++对象的时候才会知道。子类的tolua_ubox表是父类的tolua_ubox表或者是创建的一个新的表(没有父类的时候)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值