一、概览
ltm.h/ltm.c的作用是提供查询元方法(元方法的值可能是函数,也可能是非函数的值)的API。
源码中把元方法称为标签方法(tag method)。
Lua的元方法有点像C++的运算符重载,用于覆盖一些Lua内部定义的默认行为。
参考链接:
1. LUA源码分析五:元表
http://lin-style.iteye.com/blog/1012138
2. Lua GC 的源码剖析 (2)
http://blog.codingnow.com/2011/03/lua_gc_2.html
查询元表的方式有两种:
* 方式一、查询某个元表(Table结构体)的元方法(见fasttm, gfasttm)
首先,把事件(类型是枚举值)转换为元方法名称(类型是TString *字符串)。
然后,通过查询Table结构体(相当于关联数组),获取元方法的值,
如果结果为空(nil值),则把这个信息缓存到Table结构体中(flags域),
下次查询时就可以直接返回空指针。
* 方式二、查询某个对象的元方法(见luaT_gettmbyobj)
首先,判断对象是表、用户数据还是其它基本类型
(TValue实际是个联合体,所以需要判断类型,
然后用hvalue和uvalue宏转换为正确的类型,
见lobject.h的TValue、Value结构体,lstate.h的GCObject联合体)
这里,根据类型用相应的宏取出作为元表的Table *指针:
* 表:hvalue(o)对应GCObject的struct Table h字段。元表是->metatable。
* 用户数据:uvalue(o)对应GCObject的union Udata u字段。元表是->metatable。
* 其它基本类型:G(L)对应lua_State的global_State *l_G字段,元表是->mt[ttype(o)],
ttype(o)是o的基本类型索引(定义在lua.h的LUA_TNIL到LUA_TTHREAD常量)。
然后,用类似情况一的方式查元表,但不缓存nil结果,也不读取Table的flags缓存标志。
二、相关结构体(均定义在ltm模块外)
* 元表内部实现是结构体Table:
lobject.h:
typedef struct Table {
CommonHeader;
lu_byte flags; /* 1<<p means tagmethod(p) is not present */
lu_byte lsizenode; /* log2 of size of `node' array */
struct Table *metatable;
...
其中flags用于缓存nil结果(位数组)。
* Table的flags域用于缓存元表的查询(加速判断元方法是否存在)
详细见gfasttm的宏定义以及luaT_gettm的实现
* global_State结构体携带元方法名称数组信息,用于快速把枚举值转换为TString *字符串。
lstate.h
...
struct Table *mt[NUM_TAGS]; /* metatables for basic types */
TString *tmname[TM_N]; /* array with tag-method names */
} global_State;
其中mt是把LUA_TNIL到LUA_TTHREAD的常量(定义在lua.h中)映射为基本类型的元表。
(基本类型的元表由lapi.c的lua_setmetatable修改)
tmname用于所有元方法枚举映射为TString *数组,
以便于查询元表时获取luaH_getstr()需要传入的作为键名的字符串指针参数。
三、头文件
#include <string.h>
#include "lua.h"
#include "lobject.h"
#include "lstate.h"
#include "lstring.h"
#include "ltable.h"
#include "ltm.h"
四、宏定义
1. #define ltm_c
表示源于ltm.c。
2. #define LUA_CORE
表示ltm作为Lua的底层实现。
五、全局的枚举值
1. TMS(元标签类型)
typedef enum {
TM_INDEX,
TM_NEWINDEX,
TM_GC,
TM_MODE,
TM_EQ, /* last tag method with `fast' access */
TM_ADD,
TM_SUB,
TM_MUL,
TM_DIV,
TM_MOD,
TM_POW,
TM_UNM,
TM_LEN,
TM_LT,
TM_LE,
TM_CONCAT,
TM_CALL,
TM_N
/* number of elements in the enum */
} TMS;
注意它的值分别对应luaT_init内的luaT_eventname数组
static const char *const luaT_eventname[] = { /* ORDER TM */
"__index", "__newindex",
"__gc", "__mode", "__eq",
"__add", "__sub", "__mul", "__div", "__mod",
"__pow", "__unm", "__len", "__lt", "__le",
"__concat", "__call"
};
另外,fasttm和gfasttm宏只支持查询TM_INDEX和TM_MODE之间元方法的值。
而luaT_gettmbyobj可以查所有TMS类型。
六、全局变量
1. const char *const luaT_typenames[] = {
"nil", "boolean", "userdata", "number",
"string", "table", "function", "userdata", "thread",
"proto", "upval"
};
这个数组是用来把LUA_TNIL到LUA_TTHREAD常量(定义在lua.h中)转换为字符串。
跟元方法的关系不大(配合ttype宏获取TValue结构体的类型信息)
七、全局宏
1. #define gfasttm(g,et,e) ((et) == NULL ? NULL : \
((et)->flags & (1u<<(e))) ? NULL : luaT_gettm(et, e, (g)->tmname[e]))
这个宏的作用是快速获取指定元方法对应的TValue *值。
给定——
* 全局状态g(类型为global_State结构体的L栈全局状态G(L),见lua_State的l_G域)、
* 表et(类型为Table结构体的元表,事件表?)、
* 事件e(类型为TMS的元方法枚举值),
返回获取的标签方法(元方法)的对应值(类型为TValue *)。
作用类似下面的伪代码(et可以看成是一个以字符串为下标的关联数组)。
tm gfasttm(g, et, event)
{
return et[g.metaname[event]]
}
由于lgc的traversetable方法要取__mode元方法的值,
但traversetable方法是直接以global_State类型作为参数,
所以需要定义这个gfasttm()宏(实际上它和fasttm是同等作用的)
2. #define fasttm(l,et,e)
gfasttm(G(l), et, e)
相当于gfasttm(G(L), et, event)。
和gfasttm作用相同,都是快速获取指定元方法对应的TValue *值。
除了lgc的traversetable函数外,Lua其它代码(分布在lgc, ltm, lvm三个模块)
都使用它从元表中取出元方法的值。
八、全局导出函数
1. void luaT_init (lua_State *L) {
由于需要查Table的值(使用luaH_getstr),要用到TString *的键,需要缓存元方法常数。
同时确保每个常数都不会被回收。
2. const TValue *luaT_gettm (Table *events, TMS event, TString *ename) {
作为gfasttm和fasttm的内部实现(判断nil缓存的工作交给宏处理)
当发现结果为nil,该函数会对events的flags做标记(把某个位从0变成1)以达到缓存效果。
返回的TM值可能是闭包、值或者是空指针。
3. const TValue *luaT_gettmbyobj (lua_State *L, const TValue *o, TMS event) {
查询o的event元方法,如果o既不是表也不是用户数据,则查询L的event元方法。
九、关键代码
1. luaT_gettm / luaT_gettmbyobj
实际上它们都使用luaH_getstr进行索引查询,
不同的是,前者使用元表的位数组缓存查询到的nil结果,
但是只支持__index, __newindex, __gc和__mode,
而后者没有做结果的缓存处理,所以没有限制元方法的类型范围。
分享到:
相关推荐
├─5.1 │ └─bin │ liblua51.lib │ lua.exe │ lua51.dll │ lua51.lib │ luac.exe │ luadec.exe │ luaopswap.exe │ luareplace.exe │ ├─5.2 │ └─bin │ liblua52.lib │ lua.exe │ lua52.dll │ ...
a utf-8 support module for Lua and LuaJIT 源码地址:https://github.com/starwing/luautf8 编译后可用的库: Linux版:lua-utf8.so Windows版:lua-utf8.dll(若是用在openresty中,openresty版本需使用32位版本...
Praxis 是基于 Lua,Lisp 和 Forth 的在线编码环境。 特性 OpenGL 实时音频生成 Midi 立体引擎 可编程的文本编辑器 等等 Introduction: https://www.youtube.com/watch?v=1VRtRazMYSA Running the ...
本文件包括Lua5.1的《Lua Programming》第二版的中文版、英文版以及Lua5.1的中文手册。
ZeroBrane Studio是一个免费、开源、跨平台(Windows、MacOSX和Linux)的Lua集成开发环境(IDE),它提供了代码提示、远程调试、代码分析、语法高亮等功能,支持Lua 5.1、Lua 5.2、Lua 5.3、LuaJIT和其他Lua引擎1。
木头Cocos2d-x教程 Lua篇 Demo源代码。 教程地址: 第1章:http://blog.csdn.net/musicvs/article/details/8440707 第2章:http://blog.csdn.net/musicvs/article/details/8440919 第3章:...
Lua 5.1 Reference Manual.是5.1的版本的Rerfence Manual.希望可以给大家提供帮助.
lua.pas+lua5.1.dll即可以调用.lua 此处是lua5.1.dll
lua5.1.lib文件缺失,LNK1181
lsqlite3 链接 lua 使用了LuaForWindows v5.1.4 的 lua5.1.lib 库,故运行时需要 lua5.1.dll 1. lsqlite3 链接 sqlite 使用的 sqlite3.lib 来源于 M$ 的 lib.exe 应用,参阅 ...
NULL 博文链接:https://lua.iteye.com/blog/1139611
图书馆goluago旨在成为Go语言工具链(最早的8c / 6c / 5c,最终可能是纯Go语言)的Lua 5.1解释器的移植端口。 该库尚处于开发的早期阶段(功能尚未完善/尚未投入生产),但一些重要目标已经成功完成:状态截至2016年...
windows下使用的luac 基于5.1版本 lua51.dll luac.exe tolua++.exe
这个程序是基于 nginx lua module . 运行平台是 linux freebsd 的 nginx 。。 WIN 的 你可以用个 linux 的 nginx 做反向代理 保护后面的服务。 Belial 目前包含的模块有 : GET 、 POST 、 COOKIE SQL注入防御、...
cjson.dll 需要lua5.1.dll 调用require “cjson” cjson.dll 需要lua5.1.dll 调用require “cjson”
lua 5.1 manual.chm lua 5.1 manual.chm lua 5.1 manual.chm
这个是云风大侠翻译的 Lua5.1 参考手册 翻译在云风个人网站上,地址为http://www.codingnow.com/2000/download/lua_manual.html#pdf-require 并非全部翻译,但是前面的大部分和重点都翻译,真的很有用,所以转换成...
Lua-5.1.5-部分源码注释.rar
( Lua 5.1 参考手册.doc )游戏编程必备参考手册