tolua++技术分析 cocos2dx+lua,上一篇博客记录了 tolua++ 将 c++类型

前言

上一篇博客记录了 tolua++ 将 c++类型,变量,函数,以及对象导出到 lua
的历程,那篇博客就接着记录一下
c++对象的内存回收以及c++对象数据和艺术在lua中的扩张。


  1. 首先 tolua_reg_types() 在为 c++
    类型创立元表的时候,会在元表中创设一个key-value : __gc =
    tolua_gc_event

  2. 然后在 tolua_cclass ( … , lua_CFunction col)
    的历程中,会传来一个 c++ 对象的析构函数 , 以 .collector为key,
    以析构函数为value 创造一个键值对停放于 c++ 类型元表中,即
    type.mt.collector = col

  3. tolua++ 会为 c++对象的构造函数 创设相应的 new_local 方法,在 lua
    层调用 new_local 的时候, 会触发 tolua_register_gc
    即以c++指针为键,c++类型对应的元表为值,将那对key-value放于_R.tolua_gc中。

  4. 最后 lua 在废品回收的进程中,会触发 class_gc_event
    (lua_State* L) 来处理一个要被回收的 c++对象(userdata)。

    1. 先是检查 _R.tolua_gc 中是还是不是有
      以该userdata为key,以userdata的元表为value的键值对存在。
    2. 比方键值对存在于tolua_gc表中,就会在userdata的元表中取出.collector所对应的析构方法并且实施。
    3. 最后再以 _R.tolua_gc.userdata = nil
      的法子将键值对移除gc表。这样就足以兑现在lua中析构掉c++对象的内存。

前言

上一篇博客记录了 tolua++ 将 c++类型,变量,函数,以及对象导出到 lua
的进度,那篇博客就随之记录一下
c++对象的内存回收以及c++对象数据和措施在lua中的扩大。


  1. 首先 tolua_reg_types() 在为 c++
    类型制造元表的时候,会在元表中创制一个key-value : __gc =
    tolua_gc_event

  2. 然后在 tolua_cclass ( … , lua_CFunction col)
    的进程中,会流传一个 c++ 对象的析构函数 , 以 .collector为key,
    以析构函数为value 创立一个键值对停放于 c++ 类型元表中,即
    type.mt.collector = col

  3. tolua++ 会为 c++对象的构造函数 创建相应的 new_local 方法,在 lua
    层调用 new_local 的时候, 会触发 tolua_register_gc
    即以c++指针为键,c++类型对应的元表为值,将那对key-value放于_R.tolua_gc中。

  4. 说到底 lua 在垃圾回收的经过中,会触发 class_gc_event
    (lua_State* L) 来处理一个要被回收的 c++对象(userdata)。

    1. 率先检查 _R.tolua_gc 中是或不是有
      以该userdata为key,以userdata的元表为value的键值对存在。
    2. 假使键值对存在于tolua_gc表中,就会在userdata的元表中取出.collector所对应的析构方法并且实施。
    3. 末段再以 _R.tolua_gc.userdata = nil
      的点子将键值对移除gc表。那样就足以兑现在lua中析构掉c++对象的内存。

tolua++技术分析 cocos2dx+lua

lua扩展c++对象

lua扩展c++对象

前言

平素都利用 cocos2dx + lua 举行娱乐支付,用 Lua
开发能够小心于玩乐逻辑的贯彻,其它一边可以兑现热更新;而且 lua
是一个轻量级的脚本语言,库小可是作用齐全,所以在规范卓殊受欢迎。往日看了网上广大关于
c/c++ 怎么着与 lua 互调的讲课,也查看了 lua 官网的 lua api 和 c
api,感觉大有获取。近来这一段时间研讨了 tolua++ 里面 lua 层调用 c/c++
的技能完成,准备记录一下学习心得,那样可以让投机对 tolua++
工作机制理解的更是通畅,也愿意团结对规律和 api
的辨析能够对其旁人有扶持!


Lua5.1

在lua 5.1中有 tolua.getpeer tolua.setpeer
七个章程可以在lua扩充c++对象。因为在lua中可以成立四个c++对象的实例,四个实例共享同一个c++类型所对应元表的其中安装的主意,可是四个实例的数码成员是相互独立,所以
tolua 就弄了一个peer表来存储c++在lua中的新增方法和数码。那么getpeer 和
setpeer方法就可以对那个peer表存取访问。

1 setpeer 一般用法: tolua.setpeer(c++_object,lua_table)
即将lua_table设置为c++_object的peer表
,之后对实例对象开展get/set操作的时候首先会去遍历这些lua_table,然后再去遍历c++类对应的元表;那么这么些lua_table中的数据和章程就属于当前实例对象自我的,与同一个c++类的别样实例无关。
2 getpeer 一般用法: tolua.getpeer(c++_object)
获取c++_object的peer表。

Lua5.1

在lua 5.1中有 tolua.getpeer tolua.setpeer
多个艺术可以在lua伸张c++对象。因为在lua中可以创立多少个c++对象的实例,几个实例共享同一个c++类型所对应元表的里边安装的法子,不过五个实例的多少成员是并行独立,所以
tolua 就弄了一个peer表来存储c++在lua中的新增方法和数目。那么getpeer 和
setpeer方法就可以对那几个peer表存取访问。

1 setpeer 一般用法: tolua.setpeer(c++_object,lua_table)
即将lua_table设置为c++_object的peer表
,之后对实例对象开展get/set操作的时候首先会去遍历这几个lua_table,然后再去遍历c++类对应的元表;那么那些lua_table中的数据和章程就属于当前实例对象自我的,与同一个c++类的别样实例非亲非故。
2 getpeer 一般用法: tolua.getpeer(c++_object)
获取c++_object的peer表。

tolua++要求将 c/c++ 中的类型,变量,函数,对象导出到lua

  1. 通过 tolua_reg_types(lua_State* tolua_S)
    将品种导出,效能是为每一个要求导出到 lua 中的 c++ 类型创造元表,比如
    CCNode 那种类型,就会在注册表中开创一个元表 CCNode_mt。( 之后会用
    _R 代表注册表 , _G 表示全局表 , type_mt 表示类型为type的元表。 )

  2. 通过 tolua_cclass (lua_State* L, const char* lname, const char*
    name, const char* base, lua_CFunction col)
    把基类设为子类的元表;同时在 _R.tolua_super
    中以子类的元表为键,成立一张表作为值,而那张表会以基类,基类的基类(递归下去)为键,true/false
    为值 ; 还会让基类和子类共同所有平等张tolua_ubox表(以c++指针为键 ,
    fulluserdata为值)。 末了让 _G 持有 name_mt,即:_G.lname =
    name_mt。所以对于一个 c++ 类型,tolua++
    为其创设的元表最后会让全局表和注册表共同所有。

  3. 通过 tolua_function (lua_State* L, const char* name,
    lua_CFunction func) 将成员方法导出到 步骤1
    创设的元表中;即:_G.type_mt.name = func

  4. 通过 tolua_variable(lua_State* L, const char* name,
    lua_CFunction get, lua_CFunction set)
    在c++类型对象的元表中准备两张表_G.type_mt.get = {} ,
    _G.type_mt.set = {} ; 两张表以变量名为键,get/set方法为值。

Lua低版本

lua版本小于5.1 ,是平素不tolua.getpeer tolua.setpeer七个艺术的,
低版本在lua中增添c++对象的主意如下:

1 在注册表中准备一张 tolua_peers 的表 ,
那张表以userdata为键,以c++对象在lua中新增的成员变量和方法的聚合为值。
2
之后对实例对象开展get/set操作的时候会从tolua_peers表中找出userdata对应的分子变量与办法的联谊,再从集合中寻觅对应的积极分子变量或形式。

Lua低版本

lua版本小于5.1 ,是不曾tolua.getpeer tolua.setpeer多个方法的,
低版本在lua中扩充c++对象的办法如下:

1 在注册表中准备一张 tolua_peers 的表 ,
那张表以userdata为键,以c++对象在lua中新增的积极分子变量和措施的集纳为值。
2
之后对实例对象举行get/set操作的时候会从tolua_peers表中找出userdata对应的成员变量与措施的集结,再从集合中摸索对应的积极分子变量或格局。

地点c++数据的导出步骤就是 tolua_Cocos2d_open(lua_State* tolua_S) 的完结,在CCLuaStack 开端化的时候做到。

tolua_Cocos2d_open (lua_State* tolua_S)内容分析

1: tolua_open(tolua_S) 创立一名目繁多全局的table

  • _R.tolua_opened = true

  • _R.tolua_value_root = { }

  • _R.tolua_ubox = { }

  • setmetatable(_R.tolua_ubox,{__mode = v })

  • _R.tolua_super = { }

  • _R.tolua_gc = { }

  • _R.tolua_gc_event = class_gc_event(_R.tolua_gc ,
    _R.tolua_super)

  • _R.tolua_commonclass = { }

  • _G.tolua = { type = tolua_bnd_type , takeownership =
    tolua_bnd_takeownership , releaseownership =
    tolua_bnd_releaseownership , cast = tolua_bnd_cast ,isnull =
    tolua_bnd_isnulluserdata , inherit = tolua_bnd_inherit }

  • 如果lua版本是5.1: _G.tolua.setpeer = tolua_bnd_setpeer ;
    _G.tolua.getpeer = tolua_bnd_getpeer ;

2: tolua_reg_types (lua_State* tolua_S) 为索要导出到lua中的c++类型注册元表

  • 对每一个要导出的c++类型调用tolua_usertype落成元表的登记。跟进tolua_usertype可以窥见它做了两件工作。

    Step1: 调用 tolua_newmetatable
    创制元表,并且给元表设置一文山会海的元方法。
    Step2: 调用 mapsuper( L , derived_type , base_type )
    在tolua_super表中以
    derived_mt(子类型的元表)作为一个字段建立一张映射表 t ,
    那一个t以父类,父类的父类(递归下去)的元表为键,布尔变量为值。
    用伪代码可以表示为 tolua_super.derived_mt = { base_type = true
    , base_type_B = true , base_type_C = true}
    ,那样可以就足以判断四个类的继承关系。

3 tolua_cclass( L , lname , name , base ,col ) 达成类之间的涉嫌,让子类可以持续父类

  • mapinheritance(L,derived,base)
    将base设为derived的元表,那样就足以认为derived派生于base.

    1: 内部会调用 set_ubox(L)
    落成基类与派生类共享同一份tolua_ubox表
    2: 然后将基类设置为子类的metatable,假设基类为nil , 就将
    _R.tolua_commonclass 设置为子类的元表。

  • mapsuper(L,derived,base)这几个方法在上头提到了,就是在
    _R.tolua_super
    表中创建一个索引表可以用来判断多少个类之间是还是不是有一连关系。

    tolua_super.derived_mt = { base_type = true , base_type_B =
    true , base_type_C = true}

  • push_collector(L,type,col)
    那几个地方的col是个lua_CFunction类型;type_mt.collector = col
    将col函数设为type的元表collector字段所对应的元方法。c++
    对象释放的时候会要触发那么些函数。

  • _G.lname = name_mt
    最终这几个手续就是把前边c++类型在注册表中开创的元表让全局表也享有一份。

4 接下去就是c++类中的方法和成员变量的导出,就以导出 ccColor3B类中的成员方法和变量 为例子

  • tolua_cclass(tolua_S,”ccColor3B”,”ccColor3B”,””,tolua_collect_ccColor3B)
    先将类导出到_G中,并且安装好持续关系.

  • tolua_beginmodule(tolua_S,”ccColor3B”); 将 _G.ccColor3B
    压入栈中(此时lua栈负1地方是ccColor3B_mt,负2位置是_G).

  • tolua_function(tolua_S,”new”,tolua_Cocos2d_ccColor3B_new00);
    将方法导出到c++类型所对应的元表中即:
    _G.ccColor3B.new = tolua_Cocos2d_ccColor3B_new00

  • tolua_function(tolua_S,”new_local”,tolua_Cocos2d_ccColor3B_new00_local);
    _G.ccColor3B.new_local = tolua_Cocos2d_ccColor3B_new00_local
    同理上面的一密密麻麻tolua_function都会将c++方法注册到相应品种的元表中。

  • tolua_variable(tolua_S,”r”,tolua_get_ccColor3B_unsigned_r,tolua_set_ccColor3B_unsigned_r)
    tolua_variable(tolua_S,”g”,tolua_get_ccColor3B_unsigned_g,tolua_set_ccColor3B_unsigned_g);
    tolua_variable(tolua_S,”b”,tolua_get_ccColor3B_unsigned_b,tolua_set_ccColor3B_unsigned_b);

tolua_variable
的逻辑是为每一个连串创立一张get表,一张set表,然后将变量对应的 get / set
方法放到 get表 /
set表中;那样在lua层访问成员变量最后就会索引到对应的存取方法。
即:_G.ccColor3B.get = { “r” = tolua_get_ccColor3B_unsigned_r , “g”
= tolua_get_ccColor3B_unsigned_g , “b” =
tolua_get_ccColor3B_unsigned_b }

_G.ccColor3B.set = { “r” = tolua_set_ccColor3B_unsigned_r , “g” =
tolua_set_ccColor3B_unsigned_g , “b” =
tolua_set_ccColor3B_unsigned_b }

tolua++ 胶水函数分析 , 依旧以ccColor3B为例

1. tolua_Cocos2d_ccColor3B_new00(lua_State* tolua_S) 将C++对象的指针以full userdata 的格局传播到 lua 层

  • ccColor3B* tolua_ret = (ccColor3B*)
    Mtolua_new((ccColor3B)())先创立一个c++对象,获取到指针。
  • tolua_pushusertype(tolua_S,(void*)tolua_ret,”ccColor3B”) 函数在
    c++ 层创造对象,然后创设full userdata压入栈中,函数最终会把 userdata
    地址再次回到到lua层,lua 要想操作c++对象就得操作 fulluserdata,
    又因为fulluserdata 的元表是 c++对象在lua中的元表,所以最终 lua
    就是经过操作c++类型对应的元表来控制c++对象。那也是后面一星罗棋布步骤的意思。

    压入c++对象时候,以 light userdata 为键,full userdata
    为值把这一对key-value存入tolua_ubox中。 即:
    ccColor3B_mt.tolua_ubox.tolua_ret = userdata
    setmetatable(userdata,ccColor3B_mt)

2. tolua_Cocos2d_ccColor3B_new00_local 与前者比较多了一个tolua_register_gc方法,其余的都同样

  • tolua_register_gc :
    以c++指针为键,c++类型对应的元表为值,将那对key-value放于_R.tolua_gc中。

3. tolua_get_ccColor3B_unsigned_r(lua_State* tolua_S) 获取ccColor3B类中的r值

  • 先是通过 tolua_tousertype 从栈顶获得userdata中的指针ptr, 把 ptr
    转型为(ccColor3B*)
  • 然后将 (lua_Number)ptr->r 压入栈中,最终回到给lua层。

总结

  1. tolua++ 为急需导出到lua中的 c++类型 创制元表,这些元表由 注册表 和
    全局表共同享有,同时在元表中登记了一层层元方法。

  2. tolua++
    将父类型设为子类型的元表;父子类一起享有同一份tolua_ubox;同时在tolua_super中为c++类型准备了一张类型映射表,可以透过该表来询问本人有怎么着父类。
    这样就可以在lua层完成类的存续。

  3. 因而调用 tolua_register_gc
    方法,以c++类型的指针为键,c++类型对应的元表为值
    作为key-value插入到_R.tolua_gc中 来管理成立c++对象的内存。

  4. tolua++ 对 c++ 对象内存的保管,以及
    c++对象在lua层的伸张准备放下一篇小说再写!

相关文章