Search code examples
c++luagarbage-collectiontolua++

How to make tolua++ call custom code in collect function


The title pretty much explains it all. I don't want tolua++ to generate code that just calls

delete self;

in collect function. I want it to do something like this:

some_custom_collector(self);

Is this possible to specify in .pkg file?


Solution

  • After few days I was back on this problem, and I needed quick solution. I realized that there is no way to do this. So I made a patch for tolua++, but for version I found in CEGUI source. So it was done in really ugly way, but it's pretty easy to use and it works.

    Suppose you have class SomeClass, and you want lua function delete and collect function to call SomeClass_CustomFinalizer, you can specify that in you SomeClass.pkg file like this:

    tolua_outside void ~SomeClass @ SomeClass_CustomFinalizer();
    

    so instead of generating code like this:

    delete self;
    

    it will generate code like this:

    SomeClass_CustomFinalizer(self);
    

    Here is patch. Even if you fail to apply it, it should be pretty easy to get the general idea and apply manually.

    diff --git a/lua/basic.lua b/lua/basic.lua
    index 99fc961..b4983e3 100644
    --- a/lua/basic.lua
    +++ b/lua/basic.lua
    @@ -67,7 +67,8 @@ _basic_raw_push = {}
     _usertype = {}
    
     -- List of types that have to be collected
    -_collect = {}
    +_collect = {{}}
    +_collect_custom_finalizers_index = 1
    
     -- List of types
     _global_types = {n=0}
    
    diff --git a/lua/class.lua b/lua/class.lua
    index 8580ce8..c8f275e 100644
    --- a/lua/class.lua
    +++ b/lua/class.lua
    @@ -78,7 +78,10 @@ function classClass:requirecollection (t)
        -- classes that export constructors need to have a collector (overrided by -D flag on command line)
        if self._delete or ((not flags['D']) and self._new) then
            --t[self.type] = "tolua_collect_" .. gsub(self.type,"::","_")
    -       t[self.type] = "tolua_collect_" .. clean_template(self.type)
    +        t[self.type] = "tolua_collect_" .. clean_template(self.type)
    +        if self.custom_finalizer then
    +          t[_collect_custom_finalizers_index][self.type] = self.custom_finalizer
    +        end
            r = true
        end
      return r
    
    diff --git a/lua/function.lua b/lua/function.lua
    index ce73cf8..0db9b2f 100644
    --- a/lua/function.lua
    +++ b/lua/function.lua
    @@ -322,7 +322,11 @@ function classFunction:supcode (local_constructor)
    
      -- call function
      if class and self.name=='delete' then
    -  output('  delete self;')
    +   if self.custom_finalizer then
    +       output('  ' .. self.custom_finalizer .. '(self);')
    +   else
    +       output('  delete self;')
    +   end
      elseif class and self.name == 'operator&[]' then
       if flags['1'] then -- for compatibility with tolua5 ?
        output('  self->operator[](',self.args[1].name,'-1) = ',self.args[2].name,';')
    
    
    @@ -679,14 +684,20 @@ function _Function (t)
    
      append(t)
      if t:inclass() then
    - --print ('t.name is '..t.name..', parent.name is '..t.parent.name)
    +
    +--print ('t.name is '..t.name..', parent.name is '..t.parent.name)
    +
       if string.gsub(t.name, "%b<>", "") == string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then
        t.name = 'new'
        t.lname = 'new'
        t.parent._new = true
        t.type = t.parent.name
        t.ptr = '*'
    -  elseif string.gsub(t.name, "%b<>", "") == '~'..string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then
    + elseif string.gsub(t.name, "%b<>", "") == '~'..string.gsub(t.parent.original_name or t.parent.name, "%b<>", "") then
    +   if t.lname ~= t.name then
    +     t.parent.custom_finalizer = t.lname
    +     t.custom_finalizer = t.lname
    +   end
        t.name = 'delete'
        t.lname = 'delete'
        t.parent._delete = true
    
    diff --git a/lua/package.lua b/lua/package.lua
    index 6ba30fb..edc791a 100644
    --- a/lua/package.lua
    +++ b/lua/package.lua
    @@ -135,12 +135,20 @@ function classPackage:preamble ()
            output('/* function to release collected object via destructor */')
            output('#ifdef __cplusplus\n')
            for i,v in pairs(_collect) do
    -        output('\nstatic int '..v..' (lua_State* tolua_S)')
    -           output('{')
    -           output(' '..i..'* self = ('..i..'*) tolua_tousertype(tolua_S,1,0);')
    -           output('    delete self;')
    -           output('    return 0;')
    -           output('}')
    +            if i ~= _collect_custom_finalizers_index then
    +
    +            output('\nstatic int '..v..' (lua_State* tolua_S)')
    +            output('{')
    +            output(' '..i..'* self = ('..i..'*) tolua_tousertype(tolua_S,1,0);')
    +            if _collect[_collect_custom_finalizers_index][i] then
    +                output('  ' .. _collect[_collect_custom_finalizers_index][i] .. '(self);')
    +            else
    +                output('  delete self;')
    +            end
    +            output('   return 0;')
    +            output('}')
    +
    +            end
            end
            output('#endif\n\n')
        end
    

    You should remake binding code for tolua++ and recompile it.