好记性不如铅笔头

C && C++, Lua, 编程

cocos2dx-Lua学习笔记:tolua_map.c

最近在学习cocos2dx和Lua的交互,这里笔记下学习心得。

CONTENTS

备注:

1 作者对于Lua的使用较少,纯粹从使用出发,对它的理解较浅,可能有错误,还请路过的各位大牛多多指正。
2 本笔记代码部分参考cocos2dx2.2.3代码,代码版权归原作者所有。
3 由于作者时间,经验,能力有限,笔记可能不完整,以后随用随补充吧。

tolua_map.c:

文件内容较多,这里一点点笔记:

TOLUA_API void tolua_open (lua_State* L)
{
    int top = lua_gettop(L);  //先保存下当前堆栈的数目,这样返回时可以直接清理栈。
    lua_pushstring(L,"tolua_opened");   
    //LUA_REGISTRYINDEX是一个伪索引,代表的是注册表所在的table,参考网址:【 http://116.62.110.235/blog/lua-basic-notes-save-status-in-c/ 】
    
    lua_rawget(L,LUA_REGISTRYINDEX);//将 注册表["tolua_opened"]的值压入堆栈
    if (!lua_isboolean(L,-1))//查一下注册表["tolua_opened"]是否为true,如果是true,说明已经打开过了,无需再次处理,直接返回。
    {//如果没有打开过,就需要进入该if
    	  //更新注册表将注册表["tolua_opened"]设置为true
        lua_pushstring(L,"tolua_opened");
        lua_pushboolean(L,1);
        lua_rawset(L,LUA_REGISTRYINDEX);
        
        
        /** create value root table
         */
         //新建一个table添加到注册表中,即注册表[TOLUA_VALUE_ROOT] = new table;
        lua_pushstring(L, TOLUA_VALUE_ROOT);
        lua_newtable(L);
        lua_rawset(L, LUA_REGISTRYINDEX);

#ifndef LUA_VERSION_NUM /* only prior to lua 5.1 */
        /* create peer object table */
        lua_pushstring(L, "tolua_peers");
        lua_newtable(L);
        /* make weak key metatable for peers indexed by userdata object */
        lua_newtable(L);
        lua_pushliteral(L, "__mode");
        lua_pushliteral(L, "k");
        lua_rawset(L, -3);                /* stack: string peers mt */
        lua_setmetatable(L, -2);   /* stack: string peers */
        lua_rawset(L,LUA_REGISTRYINDEX);
#endif

        /* create object ptr -> udata mapping table */
        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"); //当前堆栈:tolua_box table1 table2 __mode v
        lua_rawset(L, -3);       /* stack: string ubox mt *///当前堆栈:tolua_box table1 table2其中table2["__mode"] = "v"
        lua_setmetatable(L, -2);  /* stack: string ubox */ //当前堆栈:tolua_box table1,table1的metatable是table2
        lua_rawset(L,LUA_REGISTRYINDEX);//然后把table1也作为value放入map中,key是"tolua_box"
        //这样table1就是弱引用表,参考网址:http://116.62.110.235/blog/lua-basic-notes-weak-table/
        
        
//        /* create object ptr -> class type mapping table */
//        lua_pushstring(L, "tolua_ptr2type");
//        lua_newtable(L);
//        lua_rawset(L, LUA_REGISTRYINDEX);

				//新建一个table添加到注册表中,即注册表["tolua_super"] = new table;
        lua_pushstring(L,"tolua_super");
        lua_newtable(L);
        lua_rawset(L,LUA_REGISTRYINDEX);
 				//新建一个table添加到注册表中,即注册表["tolua_gc"] = new table;
        lua_pushstring(L,"tolua_gc");
        lua_newtable(L);
        lua_rawset(L,LUA_REGISTRYINDEX);

        /* create gc_event closure */
        lua_pushstring(L, "tolua_gc_event");
        lua_pushstring(L, "tolua_gc");   //当前堆栈:tolua_gc_event tolua_gc
        lua_rawget(L, LUA_REGISTRYINDEX);//当前堆栈:tolua_gc_event map["tolua_gc"]
        lua_pushstring(L, "tolua_super");//当前堆栈:tolua_gc_event map["tolua_gc"] tolua_super
        lua_rawget(L, LUA_REGISTRYINDEX);//当前堆栈:tolua_gc_event map["tolua_gc"] map["tolua_super"]
        lua_pushcclosure(L, class_gc_event, 2);//创建一个C closure,当前堆栈:tolua_gc_event,C closure
        lua_rawset(L, LUA_REGISTRYINDEX);//把C closure也作为value放入map中,key是"tolua_gc_event"
				
				//新建一个metatable,用来保存自定义的访问方式
        tolua_newmetatable(L,"tolua_commonclass");

				//新建一个匿名表
        tolua_module(L,NULL,0);
        //把匿名表放到栈顶
        tolua_beginmodule(L,NULL);
        //新建一个tolua表
        tolua_module(L,"tolua",0);
        //把tolua表放到栈顶
        tolua_beginmodule(L,"tolua");
        //把下面的所有函数全部注册到tolua表中
        tolua_function(L,"type",tolua_bnd_type);
        tolua_function(L,"takeownership",tolua_bnd_takeownership);
        tolua_function(L,"releaseownership",tolua_bnd_releaseownership);
        tolua_function(L,"cast",tolua_bnd_cast);
        tolua_function(L,"isnull",tolua_bnd_isnulluserdata);
        tolua_function(L,"inherit", tolua_bnd_inherit);
#ifdef LUA_VERSION_NUM /* lua 5.1 */
        tolua_function(L, "setpeer", tolua_bnd_setpeer);
        tolua_function(L, "getpeer", tolua_bnd_getpeer);
#endif
				//清理栈
        tolua_endmodule(L);
        tolua_endmodule(L);
    }
    lua_settop(L,top);
}

//创建一个metatable,用来自定义各种访问方式。
/* Create metatable
    * Create and register new metatable
*/
static int tolua_newmetatable (lua_State* L, const char* name)
{
    int r = luaL_newmetatable(L,name);

#ifdef LUA_VERSION_NUM /* only lua 5.1 */
    if (r) {
        lua_pushvalue(L, -1);
        lua_pushstring(L, name);
        lua_settable(L, LUA_REGISTRYINDEX); /* reg[mt] = type_name */
    };
#endif

    if (r)
        tolua_classevents(L); /* set meta events */
    lua_pop(L,1);
    return r;
}

//将指定名称的table放入栈顶,如果名字为NULL,把全局变量表放入栈顶
/* Begin module
    * It pushes the module (or class) table on the stack
*/
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);
}

//简单的弹一下栈即可。
/* End module
    * It pops the module (or class) from the stack
*/
TOLUA_API void tolua_endmodule (lua_State* L)
{
    lua_pop(L,1);
}


//新建一个table加入lua中。name为名称,此时默认当前堆栈顶部为全局变量表
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命名的table
        if (!lua_istable(L,-1))  /* check if module already exists */
        {//如果没有,就新建一个table,命名为name
            lua_pop(L,1);
            lua_newtable(L);
            lua_pushstring(L,name);
            lua_pushvalue(L,-2);
            //将table命名为name,放入全局变量表中
            lua_rawset(L,-4);       /* assing module into module */
        }
    }
    else
    {
    	//如果名字为空,说明放入全局变量表。
        /* global table */
        lua_pushvalue(L,LUA_GLOBALSINDEX);
    }
    //如果有自定义变量,那就要修改table的默认访问方式,即metatable
    if (hasvar)
    {
        if (!tolua_ismodulemetatable(L))  /* check if it already has a module metatable */
        {
            /* create metatable to get/set C/C++ variable */
            lua_newtable(L);
            tolua_moduleevents(L);
            if (lua_getmetatable(L,-2))
                lua_setmetatable(L,-2);  /* set old metatable as metatable of metatable */
            lua_setmetatable(L,-2);
        }
    }
    lua_pop(L,1);               /* pop module */
}

//将C函数注册到当前的table中,注意这里栈顶应该是一个table,然后调用该方法
/* Map function
    * It assigns a function into the current module (or class)
*/
TOLUA_API void tolua_function (lua_State* L, const char* name, lua_CFunction func)
{
		//当前堆栈: table
    lua_pushstring(L,name);
    lua_pushcfunction(L,func);
    //当前堆栈 table, name, func
    lua_rawset(L,-3);
    //当前堆栈:table 
    //table["name"] = func
}

//注册一个用户类,这里同时注册该类型的常量类。
//实际工作其实就是在注册表中注册一个metatable,绑定了各种自定义的访问方法。
/* Register a usertype
    * It creates the correspoding metatable in the registry, for both 'type' and 'const type'.
    * It maps 'const type' as being also a 'type'
*/
TOLUA_API void tolua_usertype (lua_State* L, const char* type)
{
    char ctype[128] = "const ";
    strncat(ctype,type,120);

    /* create both metatables */
    //创建两个metatable
    if (tolua_newmetatable(L,ctype) && tolua_newmetatable(L,type))
        mapsuper(L,type,ctype);             /* 'type' is also a 'const type' */
}


//把base关联的metatable复制一份放到name中
/* Map super classes
    * It sets 'name' as being also a 'base', mapping all super classes of 'base' in 'name'
*/
static void mapsuper (lua_State* L, const char* name, const char* base)
{
    /* push registry.super */
    lua_pushstring(L,"tolua_super");
    lua_rawget(L,LUA_REGISTRYINDEX);    /* stack: super */
    luaL_getmetatable(L,name);          /* stack: super mt */
    lua_rawget(L,-2);                   /* stack: super table */
    //首先看下tolua_super表中有没有以metatableA为key的表B 。
    //即 metatableA = 注册表["name"]  表B = tolua_super[metatableA]
    //如果没有,就新建一个(进入if)
    if (lua_isnil(L,-1))
    {
    	//新建一个普通表作为value,metatableA为key,插入到tolua_supe中
        /* 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 */
    }

		//设置 表B["base"] = 1
    /* 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 */
    lua_rawget(L,-3);                   /* stack: super table base_table */
    //首先看下tolua_super表中有没有以metatableB为key的表D 。
    //即 metatableB = 注册表["base"]  表D = tolua_super[metatableB]
    //如果有这个表D,进入下面的if        
    if (lua_istable(L,-1))
    {
				//把表D中的所有内容全部复制到表B中。
				//参考网址:http://www.codingnow.com/2000/download/lua_manual.html#lua_next
        /* 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> */
}

//添加一个基类
/* Add base
    * It adds additional base classes to a class (for multiple inheritance)
    * (not for now)
    */
TOLUA_API void tolua_addbase(lua_State* L, char* name, char* base) {

    char cname[128] = "const ";
    char cbase[128] = "const ";
    strncat(cname,name,120);
    strncat(cbase,base,120);

    mapsuper(L,cname,cbase);
    mapsuper(L,name,base);
};

 

发表评论

20 + 5 =

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据