tolua++ 源碼分析

tolua++ 源碼分析


圖中的黑色表示lua table, 灰色表示userdata, 淺灰=》light userdata, 綠色=》內存

tips:

1,  lua裏的userdata是一塊內存(lua_newuserdata時指定體積),有metatable,但是doesn't have any key。 所以, 每次訪問一個usrdata,都一定是到它的metatable裏找的。 

2,lightuserdata就是一個指針,沒key, 沒metatable.

3,  上圖中的userdata爲什麼存的也是c++ instance的內存地址呢。

  因爲tolua++就是這麼幹的,它申請了userdata,並且指定體積是一個指針的大小,然後往這個內存裏。  如此而已。

4,tolua++導出來的那些c++對象(或者我們在lua裏“new”出來的c++對象),我們在lua裏操作,是把它當做一個普通的table的(也就是上圖右側的灰色方塊)。如果你做過lua項目的話,你肯定往往這些“table”上寫過自定義的屬性, 但這也是由tolua++支持的,因爲他們是“userdata”,不是table。

 

-----------------------正文----------------------

  介紹之前,先貼一篇不錯的blog,可以作爲讀tolua++的綱要。

  今天把tolua++源碼裏的"tolua_pushusertype()"這個函數讀了一下,覺得這應該是tolua++裏最核心的一個函數了。

  顧名思義,就是你給我一個c++實例(value指針所指), 我生成一個與之對應的userdata,並push之

  但這個function完成的功能可不止這些,c++對象與其對應lua userdata的之所以能“對應”,基本就是在這個函數裏實現的。

  把這部分源碼貼出來吧,自己添了一些註釋:

/*@type        correspond to C++ class Name
 *@value     c++ instance pointer
 */
TOLUA_API void tolua_pushusertype (lua_State* L, void* value, const char* type)
{
    if (value == NULL)
        lua_pushnil(L);
    else
    {   /*usually, tolua++ build a correspoding lua table( say class table ) for each Class typein C++
         *now, we just fetch find this table by 'type'( tolua++ already build it somewhere else )
         */ 
        luaL_getmetatable(L, type);                                 /* stack: mt */
        if (lua_isnil(L, -1)) { /* NOT FOUND metatable */
            lua_pop(L, 1);
            return;
        }
        lua_pushstring(L,"tolua_ubox");        /*ubox means  userdata box*/
        lua_rawget(L,-2);                                           /* stack: mt ubox */
        if (lua_isnil(L, -1)) {
            lua_pop(L, 1);
            lua_pushstring(L, "tolua_ubox");
            lua_rawget(L, LUA_REGISTRYINDEX);    /*fetch from global registery, i don't know why either*/
        };
        
        lua_pushlightuserdata(L,value);                             /* stack: mt ubox key<value> */
        lua_rawget(L,-2);                                           /* stack: mt ubox ubox[value] */
        
        if (lua_isnil(L,-1))    /*if hasn't allocate a userdata for it*/
        {
            lua_pop(L,1);                                           /* stack: mt ubox */
            lua_pushlightuserdata(L,value);    
            *(void**)lua_newuserdata(L,sizeof(void *)) = value;     /* stack: mt ubox value newud */
            lua_pushvalue(L,-1);                                    /* stack: mt ubox value newud newud */
            lua_insert(L,-4);                                       /* stack: mt newud ubox value newud */
            /*ubox[ lightuserdata ] = userdata */
            lua_rawset(L,-3);                  /* ubox[value] = newud, stack: mt newud ubox */
            lua_pop(L,1);                                           /* stack: mt newud */
            lua_pushvalue(L, -2);                                   /* stack: mt newud mt */
            /*let the metatable of new userdata refer to 'Class table'*/
            lua_setmetatable(L,-2);                      /* update mt, stack: mt newud */

#ifdef LUA_VERSION_NUM
            lua_pushvalue(L, TOLUA_NOPEER);
            lua_setfenv(L, -2);
#endif
        }
        else    /*i don't care about this branch now*/
        {
            /* check the need of updating the metatable to a more specialized class */
            lua_insert(L,-2);                                       /* stack: mt ubox[u] ubox */
            lua_pop(L,1);                                           /* stack: mt ubox[u] */
            lua_pushstring(L,"tolua_super");
            lua_rawget(L,LUA_REGISTRYINDEX);                        /* stack: mt ubox[u] super */
            lua_getmetatable(L,-2);                                 /* stack: mt ubox[u] super mt */
            lua_rawget(L,-2);                                       /* stack: mt ubox[u] super super[mt] */
            if (lua_istable(L,-1))
            {
                lua_pushstring(L,type);                             /* stack: mt ubox[u] super super[mt] type */
                lua_rawget(L,-2);                                   /* stack: mt ubox[u] super super[mt] flag */
                if (lua_toboolean(L,-1) == 1)                       /* if true */
                {
                    lua_pop(L,3);                                   /* mt ubox[u]*/
                    lua_remove(L, -2);
                    return;
                }
            }
            /* type represents a more specilized type */
            /*luaL_getmetatable(L,type);             // stack: mt ubox[u] super super[mt] flag mt */
            lua_pushvalue(L, -5);                    /* stack: mt ubox[u] super super[mt] flag mt */
            lua_setmetatable(L,-5);                /* stack: mt ubox[u] super super[mt] flag */
            lua_pop(L,3);                          /* stack: mt ubox[u] */
        }
        lua_remove(L, -2);    /* stack: ubox[u]*/
    }
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章