图中的黑色表示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]*/
}
}
至少三种方法及相应的参考实现:from multiprocessing.dummy import Pool as ThreadPooldef worker(n):return n + 2numbers = range(100)pool = ThreadPool(processes=10)result = pool.map(worker, numbers)pool.close()pool.join(...
场景设计-设置结果文件保存路径by:授客 QQ:1033553122Results->Results settingsResults Name结果文件夹名称Directory指定结果文件夹所在目录Automaticallycreate a results directory for each scenario ex...
以下是一个帖子的全部内容及回复,经常翻翻,用以自励及反思。阅读次数:774,帖子内容如下: 79 年生人,毕业于没落的重点大学大专,学经贸专业,爱好计算机互联网,毕业后先从事业务2年,财务半年,熟悉了肉食、建材商品后,最终还是因爱好从事了网站开发,知识技术全靠自学,从html、dreamweaver、photoshop到css、asp、JavaScript,目前a
[BZOJ1082][SCOI2005]栅栏
1)概述 原型模式通过给出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的办法创建出更多同类型的新的对象。其实就是从一个对象再创建另一个可定制的对象,而且不需要知道任何创建的细节,核心就是克隆。 相似的情形有: 1.鸣人使用影分身之术,一下子出现无数的鸣人来 2.每当市场出现了一款新的iphone手机,各大厂家就会争先去模仿出一模一样的手机出来,只是它们和我们的原来
1.按照输入输出分为 输入流 和 输出流2.按照传输单位分为 字节流 和 字符流3.按照功能分为 节点流(低级流) 和 处理流(高级流)还有一种说法是按照流是否直接与特定的地方(如磁盘、内存、设备等)相连,分为节点流和处理流两类。节点流:可以从或向一个特定的地方(节点)读写数据。如FileReader.通俗的讲就是 两个端口直接读或者写 数据处理流:是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如BufferedReader.处理流的构造方法总是要带一个其他的流对象做参数
实战可以参考Spring Security OAuth2--密码模式 实战_爱撸铁的程序猿的博客-程序员秘密_oauth2密码模式用户登录
先上界面:实现功能及流程:1:从摄像头获取图像,框选要识别的区域2:对选区进行图像处理,方便识别3:识别文字4:获取芯片上的内容(使用客户提供的芯片解码程序)5:比较两个内容是否一致6:写入数据库(带图片)7:对历史数据进行查阅、导出Word(导出时带图片)此版本将4~7功能去除了获取图像:使用AForge组件(参考项目:http
问题捕获了异常后,如何获取完整的堆栈轨迹(stack trace)精华回答String fullStackTrace = org.apache.commons.lang.exception.ExceptionUtils.getFullStackTrace(e)stackoverflow原址:http://stackoverflow.com/quest
冷备如果条件允许的情况下,可以使用传统冷备操作,步骤十分简单,停止数据库后,将需要备份的数据文件、控制文件、日志文件等拷贝一份即可。热备前提开启归档模式查询一下用户对应关系,我们用SCOTT测试,所在表空间为USERSoracle 查看用户所在的表空间:select username,default_tablespace from dba_users orde...
01我是一个苦b的轨范员,今晚加班到快今夜了,困得快睁不开眼了,女上司很关怀,问我要不要吃宵夜。我没好气地说,宵夜就算了,能让我睡一觉就行了。女上司红着脸说了句讨厌啊,然后坐在我身边不动,仿佛间隔我很近,搞得我很严峻,莫非她创造我的轨范出了bug?02某人发帖子:“列位JR,我想做一个轨范猿,请问有什么要注意的……”某猿:“等我放工跟你细说……”然后……就没有然后了。0...
PP你认为最强大的是哪部分?你们现在在用的是哪部分? 我们主要用的是BOM和生产订单.计划策略是sap里面最有搞头的,最后自己配需求类型配出新的策略是粉有成就感的,但是从功能 上讲,sap的pp功能没什么出彩的地方,还是i2强大,i2+sap的sfc才是完美的生产计划与控制, 强烈建议sap废掉apo,收购i2 最强大的是MRP,即物料需求计划,其实PP模块分为计划板块及生