亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 開發 > 綜合 > 正文

Lua源碼中字符串類型的實現

2024-07-21 23:04:27
字體:
來源:轉載
供稿:網友

 概述

    Lua完全采用8位編碼,Lua字符串中的字符可以具有任何數值編碼,包括數值0。也就是說,可以將任意二進制數據存儲到一個字符串中。Lua的字符串是不可變的值(immutable values)。如果修改,實質上是新建一個字符串。根據上文《Lua中數據類型的源碼實現》中知道,在Lua中,字符串是自動內存管理機制所管理的對象,并且由聯合體TString來實現存儲字符串值的。下面將通過Lua 5.2.1的源碼來看字符串的實現以及總結了在Lua中使用字符串的注意事項。

    源碼實現

    首先來看字符串對應的數據結構TString,其源碼如下(lobject.h):

410 /* 411 ** Header for string value; string bytes follow the end of this structure 412 */ 413 typedef union TString { 414  L_Umaxalign dummy; /* ensures maximum alignment for strings */ 415  struct { 416   CommonHeader; 417   lu_byte extra; /* reserved words for short strings; "has hash" for longs */ 418   unsigned int hash; 419   size_t len; /* number of characters in string */ 420  } tsv; 421 } TString; 

對這個聯合體定義,有幾點值得說明:

    I、聯合體TString中成員L_Umaxalign dummy是用來保證與最大長度的C類型進行對齊,其定義如下(llimits.h):

48 /* type to ensure maximum alignment */ 49 #if !defined(LUAI_USER_ALIGNMENT_T) 50 #define LUAI_USER_ALIGNMENT_T  union { double u; void *s; long l; } 51 #endif 52    53 typedef LUAI_USER_ALIGNMENT_T L_Umaxalign; 

在其他可會回收的對象(比如table)的實現中,也可看到這個聯合體成員,這樣做的目的是通過內存對齊,加快CPU訪問內存的速度。

    II、聯合體中成員tsv才是真正用來實現字符串的。其中成員CommonHeader用于GC,它會以宏的形式在所有的可回收對象中定義,代碼如下(lobject.h):

74 /* 75 ** Common Header for all collectable objects (in macro form, to be 76 ** included in other objects) 77 */ 78 #define CommonHeader  GCObject *next; lu_byte tt; lu_byte marked 

這個宏對應的結構體形式如下(lobject.h):

81 /* 82 ** Common header in struct form 83 */ 84 typedef struct GCheader { 85  CommonHeader; 86 } GCheader; 

結構體GCheader在通用的可回收對象union GCObject的定義中有用到。

 III、lu_byte extra對于短字符串,用來記錄這個字符串是否為保留字,對于長字符串,可以用于惰性求Hash值;unsigned int hash成員是字符串對應的Hash值(在后面會具體講Lua是怎么計算字符串的Hash值的);size_t len用來表示字符串的長度。

 IV、上面的結構體只是描述了一個字符串的結構,真正的字符串數據保存是緊隨在結構體后面保存。

 在Lua5.2.1之前,不區分字符串長和短的字符串,所有的字符串保存在一個全局的Hash表中,對于Lua虛擬機來說,相同的字符串只有一份數據,從Lua5.2.1開始,只是把短的字符串字符串(當前定義是長度小于等于40)放在全局Hash表中,而長字符串都是獨立生成,同時在計算Hash值時,引入一個隨機種子,這樣做的目的防止Hash Dos——攻擊者構造出非常多相同Hash值的不同字符串,從而降低Lua從外部壓入字符串進入全局的字符串Hash表的效率。下面是Lua5.2.1中,生成一個新字符串的步驟,其相應的代碼都在lstring.c中:

 (1)若字符串長度大于LUAI_MAXSHORTLEN(默認值是40),則是長字符串,直接調用創建字符串接口的函數createstrobj(當然字符串的長度需要能保存在成員size_t len中,否則直接返回),代碼如下(lstring.c):

 95 /*  96 ** creates a new string object  97 */                                                   98 static TString *createstrobj (lua_State *L, const char *str, size_t l,                 99                int tag, unsigned int h, GCObject **list) {              100  TString *ts;                                            101  size_t totalsize; /* total size of TString object */                       102  totalsize = sizeof(TString) + ((l + 1) * sizeof(char));                      103  ts = &luaC_newobj(L, tag, totalsize, list, 0)->ts; 104  ts->tsv.len = l; 105  ts->tsv.hash = h; 106  ts->tsv.extra = 0;                                         107  memcpy(ts+1, str, l*sizeof(char)); 108  ((char *)(ts+1))[l] = '/0'; /* ending 0 */                            109  return ts; 110 }  

可以看到把傳入的字符串具體內存放在緊隨結構體TString內存后面,并且注意108行,字符串以”/0”結束與C語言字符串兼容的。

 (2)若字符串是短字符串,首先計算字符串的Hash值,找到對應的鏈表(短字符串的全局Hash表,使用的是鏈接法的方法,即把所有沖突的元素放在同一個鏈表中),查找當前要創建的字符串是否已經在Hash表中,若已經存在,則直接返回這個字符串。否則會調用函數newshrstr,而函數newshrstr會調用上面的createstrobj函數創建新字符串,并把新創建的字符串放到Hash表中,代碼如下(lstring.c)):

130 /* 131 ** checks whether short string exists and reuses it or creates a new one 132 */ 133 static TString *internshrstr (lua_State *L, const char *str, size_t l) { 134  GCObject *o; 135  global_State *g = G(L); 136  unsigned int h = luaS_hash(str, l, g->seed); 137  for (o = g->strt.hash[lmod(h, g->strt.size)]; 138    o != NULL; 139    o = gch(o)->next) { 140   TString *ts = rawgco2ts(o); 141   if (h == ts->tsv.hash && 142     ts->tsv.len == l && 143     (memcmp(str, getstr(ts), l * sizeof(char)) == 0)) { 144    if (isdead(G(L), o)) /* string is dead (but was not collected yet)? */ 145     changewhite(o); /* resurrect it */ 146    return ts; 147   } 148  } 149  return newshrstr(L, str, l, h); /* not found; create a new string */ 150 } 

全局的字符串Hash表是保存在虛擬機全局狀態成員strt中的(lstate.h):

119  stringtable strt; /* hash table for strings */ 

而類型stringtable是一個結構體,其定義如下(lstate.h):

59 typedef struct stringtable {                                     60  GCObject **hash; 61  lu_int32 nuse; /* number of elements */ 62  int size; 63 } stringtable; 

其中成員GCObject **hash是一個指針數組,數組中每個成員實質指向TString(注意TString中包括宏CommonHeader,該宏中的next成員可以構造出Hash表中開散的鏈表);nuse是數組hash中已經被使用的元素個數;size是當前數組hash的大小。

在函數newshrstr插入新的字符串前,都會判斷nuse值是否大于size,若大于,表明Hash表大小不夠需要擴充,則把Hash表的大小擴充到原來的2倍,對應的代碼如下(lstring.c):

121  if (tb->nuse >= cast(lu_int32, tb->size) && tb->size <= MAX_INT/2)                 122   luaS_resize(L, tb->size*2); /* too crowded */  

在gc的時候,會判斷nuse是否比size/2還?。ㄔ贚ua 5.1中是把nuse與size/4比較),如果是的話就重新resize這個stringtable的大小為原來的一半。對應的代碼如下(lgc.c):

783   int hs = g->strt.size / 2; /* half the size of the string table */               784   if (g->strt.nuse < cast(lu_int32, hs)) /* using less than that half? */            785    luaS_resize(L, hs); /* halve its size */ 

對于字符串比較,首先比較類型,若是不同類型字符串,則肯定不相同,然后區分短字符串和長字符串,對于短字符串,若兩者指針值相等,則相同,否則不相同;對應長字符串,則首先比較指針值,若不同,則比較長度值和內容逐字符比較。

  總結

 (1)Lua中的保留字和元方法名都是做為短字符串的,他們在虛擬機啟動的時候就已經放入到全局短的字符串Hash表,并且是不回收的。

 (2)查找字符是比較高效的,但是修改或插入字符串都是比較低效的,這里面除了計算外,至少要把外面的字符串拷貝到虛擬機中。

 (3)對應長字符串的Hash值,Lua是不會考察每個字符的,因而能避免快速計算長字符串的散列值,其相應的代碼如下(lstring.c):

51 unsigned int luaS_hash (const char *str, size_t l, unsigned int seed) {               52  unsigned int h = seed ^ l;                                     53  size_t l1;                                             54  size_t step = (l >> LUAI_HASHLIMIT) + 1;                              55  for (l1 = l; l1 >= step; l1 -= step)                                56   h = h ^ ((h<<5) + (h>>2) + cast_byte(str[l1 - 1]));                       57  return h;                                             58 }  21 /*                                                 22 ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a string to                 23 ** compute its hash                                         24 */                                                  25 #if !defined(LUAI_HASHLIMIT)                                     26 #define LUAI_HASHLIMIT   5                                    27 #endif 

 (4)當有多個字符串連接時,不應該直接用字符串連接運算符”..”,而是用table.concat操作或者是string.format來加快字符串連接的操作。

 (5)Lua中字符串Hash算法用的是JSHash,關于字符串的各種Hash函數,網絡有篇文章對它進行了總結:https://www.byvoid.com/blog/string-hash-compare

以上所述誰就是本文的全部內容了,希望能對大家學習lua有所幫助。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
国产精品网址在线| 成人黄色在线观看| 色偷偷噜噜噜亚洲男人的天堂| 中文字幕日韩电影| 久久99久久久久久久噜噜| 狠狠躁夜夜躁人人躁婷婷91| 法国裸体一区二区| 欧美成人免费全部| 疯狂蹂躏欧美一区二区精品| 欧美激情亚洲自拍| 欧美电影免费观看网站| 国产精品午夜视频| 国产精品高潮粉嫩av| 午夜精品蜜臀一区二区三区免费| 欧美激情视频网址| www.日韩视频| 性色av香蕉一区二区| 国产成人亚洲精品| 成人激情视频网| 一区二区中文字幕| 欧美精品免费在线| 国产精品高潮呻吟久久av黑人| 国产成人精品最新| 91夜夜未满十八勿入爽爽影院| 亚洲毛片在线看| 国产精品天天狠天天看| www.久久色.com| 亚洲精品中文字幕有码专区| 日韩在线观看视频免费| 日韩女优人人人人射在线视频| 日韩精品极品在线观看播放免费视频| 国产精品色婷婷视频| 97精品欧美一区二区三区| 一区二区亚洲欧洲国产日韩| 欧美激情在线播放| 国产999在线| 成人欧美一区二区三区在线湿哒哒| 国产日韩欧美自拍| 欧美肥老太性生活视频| 大荫蒂欧美视频另类xxxx| 2019国产精品自在线拍国产不卡| 亚洲欧美成人在线| 亚洲国产精品成人精品| 国产综合福利在线| 久久精品国产亚洲7777| 亚洲人成电影网站色…| 成人精品久久久| 欧美成人午夜免费视在线看片| 国产午夜精品一区二区三区| 亚洲精品久久久久久久久久久久| 欧美一区二区三区……| 亚洲第一视频网| 夜夜嗨av一区二区三区免费区| 亚洲精品福利在线| 久久久久99精品久久久久| 欧美性精品220| 久久久久久亚洲精品不卡| 欧美夫妻性生活xx| 亚洲精品美女在线观看播放| 国产www精品| 亚洲欧洲xxxx| 成人高h视频在线| 国产激情综合五月久久| 亚洲国产一区二区三区在线观看| 在线观看欧美成人| 亚洲欧美精品一区| 久久精品一偷一偷国产| 午夜精品久久久久久久99热| 欧美激情喷水视频| 亚洲欧美另类人妖| 国产免费亚洲高清| xxxxx91麻豆| 亚洲精品日韩在线| 欧美在线免费观看| 亚洲无限乱码一二三四麻| 国产黑人绿帽在线第一区| 青青在线视频一区二区三区| 日本亚洲精品在线观看| 日韩av中文字幕在线播放| 国产午夜一区二区| 国产日韩在线看片| 日本精品久久久久影院| 91日韩在线视频| 国产欧美日韩最新| 欧美激情videoshd| 久久免费精品视频| 久久精品夜夜夜夜夜久久| 亚洲精品国精品久久99热一| 红桃av永久久久| 日本精品视频在线播放| 亚洲一区二区久久久久久| 国产在线观看91精品一区| 亚洲国产精品va在线观看黑人| 97人人爽人人喊人人模波多| 在线视频精品一| 成人97在线观看视频| 91在线观看免费网站| 国产精品人成电影在线观看| 国内揄拍国内精品少妇国语| 久久九九免费视频| 欧美一级bbbbb性bbbb喷潮片| 欧美性xxxxhd| 日韩激情av在线播放| 久99久在线视频| 久久黄色av网站| 久久人人爽人人爽人人片亚洲| 色爱av美腿丝袜综合粉嫩av| 亚洲视频自拍偷拍| 亚洲变态欧美另类捆绑| 夜夜狂射影院欧美极品| 久久久精品一区| 日本中文字幕成人| 成人国产精品一区| 国产精品福利在线观看| 欧美精品video| 国产国语刺激对白av不卡| 国产精品男人爽免费视频1| 国产精品成人免费电影| 欧美性生交大片免费| 国内伊人久久久久久网站视频| 91精品综合视频| 亚洲精品视频在线观看视频| 91系列在线观看| 国产欧美亚洲视频| 国产精品精品视频| 日本不卡视频在线播放| 精品偷拍一区二区三区在线看| 久久精品国产亚洲一区二区| 日韩一区二区在线视频| 777777777亚洲妇女| 亚洲成人av片在线观看| 欧美日韩加勒比精品一区| 欧美精品在线视频观看| 久久在线免费视频| 亚洲欧美成人一区二区在线电影| 91色琪琪电影亚洲精品久久| 中文字幕免费精品一区高清| 精品久久香蕉国产线看观看亚洲| 日韩av在线电影网| 亚洲四色影视在线观看| 国产精品福利片| 欧美洲成人男女午夜视频| 97在线看福利| 久久久精品国产亚洲| 国产精品视频1区| 亚洲色图欧美制服丝袜另类第一页| 成人夜晚看av| 亚洲最新视频在线| 国产精品视频中文字幕91| 亚洲九九九在线观看| 中文字幕视频一区二区在线有码| 日韩在线免费av| 2019中文字幕全在线观看| 色综合天天综合网国产成人网| 好吊成人免视频| 久久五月情影视| 91美女片黄在线观| 国产成人免费91av在线| 国内精品免费午夜毛片| 国产精品色婷婷视频| 国产情人节一区| 高清视频欧美一级| 91国偷自产一区二区三区的观看方式| 欧美成aaa人片在线观看蜜臀|