lstring
lstring实现了Lua对于字符串的管理.
字符串对象的结构体声明在lobject中. Lua中的字符串可以是C语言的'\0'
结尾的连续字符数组, 也可以单纯是一块连续内存的内容, 包含任何字节内容.
#define LUA_TSTRING 4
/* Variant tags for strings */
#define LUA_TSHRSTR (LUA_TSTRING | (0 << 4)) /* short strings */
#define LUA_TLNGSTR (LUA_TSTRING | (1 << 4)) /* long strings */
在Lua中, 字符串根据长度LUAI_MAXSHORTLEN
( 默认40) 区分长短字符串, 分为LUA_TLNGSTR
和LUA_TSHRSTR
. 对短字符串进行hash后, 保存起来, 进行复用.
数据结构
/*
** Header for string value; string bytes follow the end of this structure
** (aligned according to 'UTString'; see next).
*/
typedef struct TString {
CommonHeader;
lu_byte extra; /* reserved words for short strings; "has hash" for longs */
lu_byte shrlen; /* length for short strings */
unsigned int hash;
union {
size_t lnglen; /* length for long strings */
struct TString *hnext; /* linked list for hash table */
} u;
} TString;
- CommonHeader
- extra: luaX_init中使用到这个, 用来表示是关键字类别.
- shrlen: 短字符串的长度
- hash: hash值
- u.lnglen: 长字符串的长度
- u.hnext: 如果出现hash碰撞, 则将碰撞内容链接到链表内
/*
** Ensures that address after this type is always fully aligned.
*/
typedef union UTString {
L_Umaxalign dummy; /* ensures maximum alignment for strings */
TString tsv;
} UTString;
将TString
进行内存对齐. L_Umaxalign
默认是一个union, 内容和部分union Value一致.
lua_State
和global_State
在lua_State
的l_G中引用了这个lua_State
所属的global_State
. 在global_State
中有几个被用到的域
TString *strcache[STRCACHE_SIZE][1]; /* cache for strings in API */
strcache
是长字符串的hash表, 默认长字符串使用地址对strcache的大小取余来获取存取地址. 可以通过luaS_clearcache
来清空.都是以
'\0'
结尾的字符串.
TString *memerrmsg; /* memory-error message */
memerrmsg
是在luaS_init
的时候没设置成MEMERRMSG
("not enough memory"
). 在luaS_init
中调用了luaC_fix
将这个字符串强制标记为不可被GC回收. 也是所有短字符串的默认值. rehash后
stringtable strt; /* hash table for strings */
strt
保存hash过的短字符串. 用luaS_remove
从中删除字符串对象,
API
luaS_eqlngstr
比较长字符串, assert同类型, 先看是否指向同一对象, 在比较长度是否相等, 最后利用字符串长度, 用memcmp
比较内存内容.luaS_hash
计算字符串的hash值. 对于长度小于2^LUAI_HASHLIMIT
的字符串, 每字节都参加计算hash(LUAI_HASHLIMIT
默认为5). 长度大于32的字符串, 从末尾开始, 每(l >> LUAI_HASHLIMIT) + 1
参加计算hash值.-
如果长度一样, 但是参加计算的字符也是一样的, 就会增加hash碰撞
luaS_resize
拓展L->l_G->strt
并将拓展部分置NULL
. 如果newsize
小于strt
的长度, 那么就会截取.-
所以必须保证, 截取的时候, 截取位置之后没有hash.
luaS_clearcache
: 如果g->strcache[i][0]
为white
, 则将里面的指向g->memerrmsg
-
为什么不置为
NULL
, 而要置为一个不可回收的字符串呢? luaS_init
利用luaS_resize
初始化L->l_G->strt
为MINSTRTABSIZE
(128)个元素. 将g->memerrmsg
置为MEMERRMSG
("not enough memory"
) , 并使其不可被GC回收. 初始化g->strcache
的每个元素指向g->memerrmsg
.createstrobj
创建字符串对象. 调用到了luaC_newobj
, 等看到GC的时候再返回看这个函数.luaS_remove
将TString
从L->l_G->strt
中移除, 这个TString
需要已经计算出hash值.internshrstr
检查短字符串是否在strt
内, 如果存在, 则复用, 否则检查是否需要rehash, 最后, 创建新的短字符串对象, 并放入strt
中.luaS_newlstr
创建字符串对象. 对短字符串进行internshrstr
, 对长字符串, 字节创建对象. 长字符串对象的hash是他的长度, 末尾会添加'\0'
luaS_new
创建或复用'\0'
结尾的字符串, 首先在L->l_G->strcache
内用地址作为hash键值查找, 看是否有内容相同的'\0'
结尾的字符串. 有则复用, 没有则利用luaS_newlstr
创建长字符串对象.luaS_newudata
和创建userdata
相关