[lua source code]ADT of TValue

在上一篇里,我們知道一個(gè)Lua的對(duì)象包含對(duì)象的值和對(duì)象的類型信息主卫√幽回顧一下:

typedef struct lua_TValue {
  Value value_;  
  int tt_;
}TValue;

其中,tt_是tag type的簡(jiǎn)寫簇搅,一共包含三個(gè)部分完域,分別是:

  • bit位0-3表示大類型
  • bit位4-5表示小類型
  • bit位6表示是否可以垃圾回收

顯然,既然Lua的所有類型統(tǒng)一用TValue表示瘩将,TValue就應(yīng)該具備一些基本的操作吟税,用來(lái)存取類型示例的基本屬性。從Lua的源碼來(lái)看姿现,可以把TValue的基本操作歸結(jié)如下:

  1. 判斷對(duì)象的具體類型
  2. 獲取對(duì)象的值
  3. 設(shè)置對(duì)象的值

如果用ADT來(lái)表示肠仪,可以寫成:

TValue:
   get_type()
   get_value()
   set_value()

我們逐個(gè)來(lái)看。

get type

Lua里备典,用了一組宏來(lái)判斷TValue的具體類型异旧,首先是四個(gè)萃取tt_信息的宏:

/* raw type tag of a TValue */
#define rttype(o)   ((o)->tt_)

/* tag with no variants (bits 0-3) */
#define novariant(x)    ((x) & 0x0F)

/* type tag of a TValue (bits 0-3 for tags + variant bits 4-5) */
#define ttype(o)    (rttype(o) & 0x3F)

/* type tag of a TValue with no variants (bits 0-3) */
#define ttnov(o)    (novariant(rttype(o)))

其中norariant是直接操作tt_字段的,其他三個(gè)參數(shù)都是TValue對(duì)象提佣,我們可以去掉novariant:

#define rttype(o)   ((o)->tt_)
#define ttype(o)     (rttype(o) & 0x3F)
#define ttnov(o)     (rttype(o) & 0x0F)

進(jìn)一步吮蛹,還可以把rttype展開(kāi):

#define rttype(o)   ((o)->tt_)
#define ttype(o)     ((o)->tt_ & 0x3F) 
#define ttnov(o)     ((o)->tt_ & 0x0F)

Lua并沒(méi)有針對(duì)tt_三個(gè)部分的萃取都單獨(dú)提供宏,萃取4-5bit以及萃取第6個(gè)bit由于后面各只被用到一次拌屏,所以不必單獨(dú)提供一個(gè)宏匹涮。當(dāng)然,如果單獨(dú)提供槐壳,則會(huì)讓api看上去更完備和對(duì)稱然低。

進(jìn)一步,Lua提供了兩個(gè)基本的check:

#define checktag(o,t)   (rttype(o) == (t))
#define checktype(o,t)   (ttnov(o) == (t))

現(xiàn)在务唐,就可以對(duì)每種TValue類型做判斷:

/* Macros to test type */
#define ttisnumber(o)         checktype((o), LUA_TNUMBER)
#define ttisfloat(o)           checktag((o), LUA_TNUMFLT)
#define ttisinteger(o)       checktag((o), LUA_TNUMINT)
#define ttisnil(o)           checktag((o), LUA_TNIL)
#define ttisboolean(o)       checktag((o), LUA_TBOOLEAN)
#define ttislightuserdata(o)   checktag((o), LUA_TLIGHTUSERDATA)
#define ttisstring(o)         checktype((o), LUA_TSTRING)
#define ttisshrstring(o)       checktag((o), ctb(LUA_TSHRSTR))
#define ttislngstring(o)       checktag((o), ctb(LUA_TLNGSTR))
#define ttistable(o)           checktag((o), ctb(LUA_TTABLE))
#define ttisfunction(o)     checktype(o, LUA_TFUNCTION)
#define ttisclosure(o)       ((rttype(o) & 0x1F) == LUA_TFUNCTION)
#define ttisCclosure(o)     checktag((o), ctb(LUA_TCCL))
#define ttisLclosure(o)     checktag((o), ctb(LUA_TLCL))
#define ttislcf(o)           checktag((o), LUA_TLCF)
#define ttisfulluserdata(o) checktag((o), ctb(LUA_TUSERDATA))
#define ttisthread(o)         checktag((o), ctb(LUA_TTHREAD))
#define ttisdeadkey(o)       checktag((o), LUA_TDEADKEY)

實(shí)際上雳攘,我們可以針對(duì)上一篇的類型列表做一個(gè)縮進(jìn):

#define ttisnil(o)               checktag((o), LUA_TNIL)
#define ttislightuserdata(o)     checktag((o), LUA_TLIGHTUSERDATA)
#define ttisboolean(o)           checktag((o), LUA_TBOOLEAN)
#define ttisnumber(o)            checktype((o), LUA_TNUMBER) // 1          
    #define ttisfloat(o)         checktag((o), LUA_TNUMFLT)
    #define ttisinteger(o)       checktag((o), LUA_TNUMINT)
#define ttisfunction(o)          checktype(o, LUA_TFUNCTION) // 2
    #define ttislcf(o)           checktag((o), LUA_TLCF)
    #define ttisclosure(o)       ((rttype(o) & 0x1F) == LUA_TFUNCTION) // **4**
        #define ttisCclosure(o)  checktag((o), ctb(LUA_TCCL))
        #define ttisLclosure(o)  checktag((o), ctb(LUA_TLCL))
#define ttisstring(o)            checktype((o), LUA_TSTRING) // 3
    #define ttisshrstring(o)     checktag((o), ctb(LUA_TSHRSTR))
    #define ttislngstring(o)     checktag((o), ctb(LUA_TLNGSTR))
#define ttisfulluserdata(o)      checktag((o), ctb(LUA_TUSERDATA))
#define ttistable(o)             checktag((o), ctb(LUA_TTABLE))
#define ttisthread(o)            checktag((o), ctb(LUA_TTHREAD))
#define ttisdeadkey(o)           checktag((o), LUA_TDEADKEY)

可以看到,1,2,3三個(gè)地方判斷大類型枫笛,用的是checktype吨灭,也就是只需判斷0-3bit即可;而4這個(gè)地方判斷則使用的是4-5bit判斷小類型刑巧。其余的地方使用的是0-6bit喧兄;不過(guò)還差一點(diǎn)无畔,那就是cbt宏。展開(kāi)看一下:

/* Bit mark for collectable types */
#define BIT_ISCOLLECTABLE    (1 << 6)

/* mark a tag as collectable */
#define ctb(t)            ((t) | BIT_ISCOLLECTABLE)

可見(jiàn)吠冤,ctb宏的作用是設(shè)置6個(gè)bit浑彰,表示這是一個(gè)可垃圾回收類型。此外拯辙,針對(duì)GCObject郭变,Lua還提供了一個(gè)判斷TValue里的tag type和GCObject里的tag type是否一致的判斷:

/* Macros for internal tests */
#define righttt(obj)        (ttype(obj) == gcvalue(obj)->tt)

get value

獲取無(wú)類型信息的Value:

#define val_(o)     ((o)->value_)

進(jìn)一步,根據(jù)上一節(jié)的類型判斷涯保,就可以實(shí)現(xiàn)帶類型校驗(yàn)的值獲取方法诉濒,依然是一組宏:

/* Macros to access values */
#define ivalue(o)    check_exp(ttisinteger(o), val_(o).i)
#define fltvalue(o)  check_exp(ttisfloat(o), val_(o).n)
#define nvalue(o)    check_exp(ttisnumber(o), \
   (ttisinteger(o) ? cast_num(ivalue(o)) : fltvalue(o)))
#define gcvalue(o)   check_exp(iscollectable(o), val_(o).gc)
#define pvalue(o)    check_exp(ttislightuserdata(o), val_(o).p)
#define tsvalue(o)   check_exp(ttisstring(o), gco2ts(val_(o).gc))
#define uvalue(o)    check_exp(ttisfulluserdata(o), gco2u(val_(o).gc))
#define clvalue(o)   check_exp(ttisclosure(o), gco2cl(val_(o).gc))
#define clLvalue(o)  check_exp(ttisLclosure(o), gco2lcl(val_(o).gc))
#define clCvalue(o)  check_exp(ttisCclosure(o), gco2ccl(val_(o).gc))
#define fvalue(o)    check_exp(ttislcf(o), val_(o).f)
#define hvalue(o)    check_exp(ttistable(o), gco2t(val_(o).gc))
#define bvalue(o)    check_exp(ttisboolean(o), val_(o).b)
#define thvalue(o)   check_exp(ttisthread(o), gco2th(val_(o).gc))

/* a dead value may get the 'gc' field, but cannot access its contents */
#define deadvalue(o)   check_exp(ttisdeadkey(o), cast(void *, val_(o).gc))

#define l_isfalse(o)   (ttisnil(o) || (ttisboolean(o) && bvalue(o) == 0))

#define iscollectable(o)   (rttype(o) & BIT_ISCOLLECTABLE)

注意到,里面用到了幾個(gè)gco2x的宏夕春,這組宏的作用是把GCObject的子類型轉(zhuǎn)為更具體的類型未荒,再次展開(kāi):

#define cast_u(o)   cast(union GCUnion *, (o))

/* macros to convert a GCObject into a specific value */
#define gco2ts(o)  \
    check_exp(novariant((o)->tt) == LUA_TSTRING, &((cast_u(o))->ts))
#define gco2u(o)  check_exp((o)->tt == LUA_TUSERDATA, &((cast_u(o))->u))
#define gco2lcl(o)  check_exp((o)->tt == LUA_TLCL, &((cast_u(o))->cl.l))
#define gco2ccl(o)  check_exp((o)->tt == LUA_TCCL, &((cast_u(o))->cl.c))
#define gco2cl(o)  \
    check_exp(novariant((o)->tt) == LUA_TFUNCTION, &((cast_u(o))->cl))
#define gco2t(o)  check_exp((o)->tt == LUA_TTABLE, &((cast_u(o))->h))
#define gco2p(o)  check_exp((o)->tt == LUA_TPROTO, &((cast_u(o))->p))
#define gco2th(o)  check_exp((o)->tt == LUA_TTHREAD, &((cast_u(o))->th))

出現(xiàn)了一個(gè)新的聯(lián)合體:GCUnion,這個(gè)是啥及志?展開(kāi)看:

/*
** Union of all collectable objects (only for conversions)
*/
union GCUnion {
  GCObject gc;  /* common header */
  struct TString ts;
  struct Udata u;
  union Closure cl;
  struct Table h;
  struct Proto p;
  struct lua_State th;  /* thread */
};

哦片排,原來(lái)這個(gè)是上一篇的補(bǔ)丁。所有的GCObject都有共同的頭部困肩,也就是CommonHeader划纽,所以可以把GCObject轉(zhuǎn)為GCUnion之后,再轉(zhuǎn)為具體類型的指針锌畸,安全性由check_exp保證勇劣。

反之,又具體類型轉(zhuǎn)為GCObject也應(yīng)該提供:

/* macro to convert a Lua object into a GCObject */
#define obj2gco(v) \
    check_exp(novariant((v)->tt) < LUA_TDEADKEY, (&(cast_u(v)->gc)))

set value

顯然潭枣,設(shè)置TValue的值比默,應(yīng)該同時(shí)設(shè)置Value和tag type。

/* Macros to set values */
#define settt_(o,t) ((o)->tt_=(t))  // 必須每次賦值都重新設(shè)置具體類型

#define setfltvalue(obj,x) \
  { TValue *io=(obj); val_(io).n=(x); settt_(io, LUA_TNUMFLT); }

#define setivalue(obj,x) \
  { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }

#define setnilvalue(obj) settt_(obj, LUA_TNIL)

#define setfvalue(obj,x) \
  { TValue *io=(obj); val_(io).f=(x); settt_(io, LUA_TLCF); }

#define setpvalue(obj,x) \
  { TValue *io=(obj); val_(io).p=(x); settt_(io, LUA_TLIGHTUSERDATA); }

#define setbvalue(obj,x) \
  { TValue *io=(obj); val_(io).b=(x); settt_(io, LUA_TBOOLEAN); }

#define setgcovalue(L,obj,x) \
  { TValue *io = (obj); GCObject *i_g=(x); \
    val_(io).gc = i_g; settt_(io, ctb(i_g->tt)); }

#define setsvalue(L,obj,x) \
  { TValue *io = (obj); TString *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
    checkliveness(G(L),io); }

#define setuvalue(L,obj,x) \
  { TValue *io = (obj); Udata *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TUSERDATA)); \
    checkliveness(G(L),io); }

#define setthvalue(L,obj,x) \
  { TValue *io = (obj); lua_State *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTHREAD)); \
    checkliveness(G(L),io); }

#define setclLvalue(L,obj,x) \
  { TValue *io = (obj); LClosure *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TLCL)); \
    checkliveness(G(L),io); }

#define setclCvalue(L,obj,x) \
  { TValue *io = (obj); CClosure *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TCCL)); \
    checkliveness(G(L),io); }

#define sethvalue(L,obj,x) \
  { TValue *io = (obj); Table *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(LUA_TTABLE)); \
    checkliveness(G(L),io); }

#define setdeadvalue(obj)   settt_(obj, LUA_TDEADKEY)


#define setobj(L,obj1,obj2) \
    { TValue *io1=(obj1); *io1 = *(obj2); \
      (void)L; checkliveness(G(L),io1); }

這組宏在內(nèi)部都先重新引用下參數(shù)再操作盆犁,我想是為了避免宏展開(kāi)的副作用命咐,到處加小括號(hào),例如:

#define setsvalue(L,obj,x) \
  { TValue *io = (obj); TString *x_ = (x); \
    val_(io).gc = obj2gco(x_); settt_(io, ctb(x_->tt)); \
    checkliveness(G(L),io); }

這里把objx分別先賦值給iox_谐岁,再使用醋奠,但下面的x_則因?yàn)橹挥昧艘淮尉蜎](méi)做這個(gè)賦值動(dòng)作:

#define setivalue(obj,x) \
  { TValue *io=(obj); val_(io).i=(x); settt_(io, LUA_TNUMINT); }

此外,這組宏里面伊佃,對(duì)GCObject窜司,都要通過(guò)obj2gco把具體類型轉(zhuǎn)型后再賦值給val_(io).gc字段。

待續(xù)

下一篇希望分析下Lua State對(duì)象航揉,也就是所謂的Thread总棵。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末航瞭,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌睹逃,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡产捞,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門捅位,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)轧葛,“玉大人搂抒,你說(shuō)我怎么就攤上這事艇搀。” “怎么了求晶?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵焰雕,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我芳杏,道長(zhǎng)矩屁,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任爵赵,我火速辦了婚禮吝秕,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘空幻。我一直安慰自己烁峭,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布秕铛。 她就那樣靜靜地躺著约郁,像睡著了一般。 火紅的嫁衣襯著肌膚如雪但两。 梳的紋絲不亂的頭發(fā)上鬓梅,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音谨湘,去河邊找鬼绽快。 笑死,一個(gè)胖子當(dāng)著我的面吹牛紧阔,可吹牛的內(nèi)容都是我干的坊罢。 我是一名探鬼主播,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼寓辱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼艘绍!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起秫筏,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤诱鞠,失蹤者是張志新(化名)和其女友劉穎挎挖,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體航夺,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蕉朵,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了阳掐。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片始衅。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖缭保,靈堂內(nèi)的尸體忽然破棺而出汛闸,到底是詐尸還是另有隱情,我是刑警寧澤艺骂,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布诸老,位于F島的核電站,受9級(jí)特大地震影響钳恕,放射性物質(zhì)發(fā)生泄漏别伏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一忧额、第九天 我趴在偏房一處隱蔽的房頂上張望厘肮。 院中可真熱鬧,春花似錦睦番、人聲如沸类茂。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)大咱。三九已至,卻和暖如春注益,著一層夾襖步出監(jiān)牢的瞬間碴巾,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工丑搔, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留厦瓢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓啤月,卻偏偏與公主長(zhǎng)得像煮仇,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子谎仲,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 開(kāi)篇 介紹了基本運(yùn)算之后浙垫,我們發(fā)現(xiàn)還沒(méi)有正式地去介紹 Lua 的基本類型。今天我們趁機(jī)歇息一下,不往下講新的 AP...
    碼上說(shuō)閱讀 1,389評(píng)論 0 2
  • 開(kāi)篇 上一節(jié)分析了 lua_arith 的大部分代碼夹姥,由于篇幅原因杉武,留到本節(jié)將繼續(xù)講解剩余的部分: 解析 現(xiàn)在我們...
    碼上說(shuō)閱讀 812評(píng)論 0 1
  • Nginx API for Lua Introduction ngx.arg ngx.var.VARIABLE C...
    吃瓜的東閱讀 5,773評(píng)論 0 5
  • 版本號(hào):Lua 5.3 Lua Type lua 的類型定義在lobject.h這個(gè)文件里,主要的類型如下: no...
    ffl閱讀 1,542評(píng)論 1 5
  • 歲月像拍在岸上的浪花辙售,美麗過(guò)轻抱、閃耀過(guò),即使轉(zhuǎn)瞬即逝旦部,仍會(huì)偶爾在我們的記憶中閃現(xiàn)祈搜。 一篇渺無(wú)人煙的花田,兀自美麗著士八。...
    花悠然閱讀 418評(píng)論 0 0