/* ** Header for a string value. */ typedefstructTString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ lu_byte shrlen; /* length for short strings */ unsignedint hash; union { size_t lnglen; /* length for long strings */ structTString *hnext; /* linked list for hash table */ } u; char contents[1]; } TString;
typedefstructTString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ lu_byte shrlen; /* length for short strings */ unsignedint hash; structTString *hnext; /* linked list for hash table */ char contents[1]; } TString;
而针对长字符串,TString 的结构为:
1 2 3 4 5 6 7
typedefstructTString { CommonHeader; lu_byte extra; /* reserved words for short strings; "has hash" for longs */ unsignedint hash; size_t lnglen; /* length for long strings */ char contents[1]; } TString;
/* ** test whether a string is a reserved word */ #define isreserved(s) ((s)->tt == LUA_VSHRSTR && (s)->extra > 0)
该宏用于判断一个字符串是否是系统的保留字符串。可以看出,如果一个字符串是短字符串且 extra 大于 0,则该字符串是系统的保留字符串。
关于长短字符串的界限,Lua 在 llimits.h 中定义了一个宏:
1 2 3 4 5 6 7 8 9
/* ** Maximum length for short strings, that is, strings that are ** internalized. (Cannot be smaller than reserved words or tags for ** metamethods, as these strings must be internalized; ** #("function") = 8, #("__newindex") = 10.) */ #if !defined(LUAI_MAXSHORTLEN) #define LUAI_MAXSHORTLEN 40 #endif
/* ** 'global state', shared by all threads of this state */ typedefstructglobal_State { // ... stringtable strt; /* hash table for strings */ // ... TString *strcache[STRCACHE_N][STRCACHE_M]; /* cache for strings in API */ // ... } global_State;
staticvoidtablerehash(TString **vect, int osize, int nsize){ int i; for (i = osize; i < nsize; i++) /* clear new elements */ vect[i] = NULL; for (i = 0; i < osize; i++) { /* rehash old part of the array */ TString *p = vect[i]; vect[i] = NULL; while (p) { /* for each string in the list */ TString *hnext = p->u.hnext; /* save next */ unsignedint h = lmod(p->hash, nsize); /* new position */ p->u.hnext = vect[h]; /* chain it into array */ vect[h] = p; p = hnext; } } }
/* ** Lua will use at most ~(2^LUAI_HASHLIMIT) bytes from a long string to ** compute its hash */ #if !defined(LUAI_HASHLIMIT) #define LUAI_HASHLIMIT 5 #endif
/* ** Create or reuse a zero-terminated string, first checking in the ** cache (using the string address as a key). The cache can contain ** only zero-terminated strings, so it is safe to use 'strcmp' to ** check hits. */ TString *luaS_new(lua_State *L, constchar *str){ unsignedint i = point2uint(str) % STRCACHE_N; /* hash */ int j; TString **p = G(L)->strcache[i]; for (j = 0; j < STRCACHE_M; j++) { if (strcmp(str, getstr(p[j])) == 0) /* hit? */ return p[j]; /* that is it */ } /* normal route */ for (j = STRCACHE_M - 1; j > 0; j--) p[j] = p[j - 1]; /* move out last element */ /* new element is first in the list */ p[0] = luaS_newlstr(L, str, strlen(str)); return p[0]; }
/* ** Size of cache for strings in the API. 'N' is the number of ** sets (better be a prime) and "M" is the size of each set (M == 1 ** makes a direct cache.) */ #if !defined(STRCACHE_N) #define STRCACHE_N 53 #define STRCACHE_M 2 #endif
/* ** open parts of the state that may cause memory-allocation errors. ** ('g->nilvalue' being a nil value flags that the state was completely ** build.) */ staticvoidf_luaopen(lua_State *L, void *ud){ global_State *g = G(L); UNUSED(ud); stack_init(L, L); /* init stack */ init_registry(L, g); luaS_init(L); luaT_init(L); luaX_init(L); g->gcrunning = 1; /* allow gc */ setnilvalue(&g->nilvalue); luai_userstateopen(L); }