Lua内置库的实现(一)_string模块

Lua内置库的实现(一)_string模块
         Lua的string库相较其它许多动态语言的string库来说,可谓短小精悍。不到千行C代码就实现了一个简单使用的字符串模式匹配模块。虽然功能上比正则表达式有所欠缺,但考虑到代码体积和功能比,这应该是一个相当漂亮的平衡(C 语言社区中常用的正则表达式库PCRE的个头整体比lua的实现还要大好几倍)。若需要更强大的字符串处理功能,Lua的作者之一Roberto给出了一个比正则表达式更强大的选择LPEG 6。有这一轻一重两大利器,在Lua社区中,很少有人再用正则表达式了。string模块实现在lstrlib.c中。
       我们先看看string模块的注册部分,它和上节所讲的math模块稍有不同,准确说是略微复杂一点。
LUAMOD_API int luaopen_string(lua_State *L){
	luaL_newlib(L, strlib);
	createmetatable(L);
	return l;
}

       这里多了一处createmetatable的调用,下面列出细节:

static void createmetatable (lua_State *L){
	lua_createtable(L, 0, 1);	/*table to be metatable for strings*/
	lua_pushliteral(L, "");		/*dummy string*/
	lua_pushvalue(L, -2); 		/*copy table*/
	lua_setmetatable(L, -2);	/*set table as metatable for strings*/
	lua_pop(L, 1);				/*pop dummy string */
	lua_pushvalue(L, -2);		/* get string library*/
	lua_setfield(L, -2, "__index");/*metatable.__index = string*/
	lua_pop(L, 1)				/* pop metatable */
}

        第一次看Lua的API使用流程,容易被Lua Stack弄晕。Lua和C的交互就是通过这一系列的API操作Lua栈来完成的。如果你看不太明白,可以用笔在纸上画出Lua栈上数据的情况。进入这个函数时,栈顶有一个table、即所有的string API存在的那张表。然后,余下的几行API创建了一个metatable,使用这张表做索引表。这张元表最终被设置入dummy字符串中。
        给字符串类型设置元表,它并非给特定的字符串值赋予元方法,而是针对整个字符串类型。这个特性几乎不会给Lua的运行效率带来损失,但极大的丰富了Lua的表达能力。当然,处于语言上的严谨考虑,Lua的API setmetatable禁止修改这个元表。
        下面返回源文件开头,uchar这个宏定义很能体现Lua源码风格:
/* macro to ‘unsign’ a character */
#define uchar(c)	((unsigned char)(c))

         C语言中,对 char类型中保存数字是否有符号并无严格定义 (C语言的char类型是 singed还是依赖于实现。我们常用的C编译器如 gccchar类型是有符号的,也有一些C编译器如 Watcom C的char类型默认则是无符号的。 )所以有统一把字符数字转换为无符号来处理的需求。Lua的源码中,所有类型强制转换都很严谨的使用了宏以显式标示出来。因为仅在这一个源文件中需要处理字符这个类型,所以uchar这个宏被定义在.c文件中,而不存在于别的.h里。
         Lua在处理偏移量时,习惯用负数表示从尾部倒数。Lua API设计中,对Lua栈的索引就是如此;处理字符串时,字符串索引也遵循同一规则。这里定义了一个内部函数 posrelat方便转换这个索引值。
static size_t posrelat (ptrdiff_t pos, size_t len){
	if(pos >= 0) return (size_t) pos;
	else if(0u - (size_t)pos > len) return 0;
	else return len - ((size_t) - pos) + 1;
}
         lstrlib.c中间的数百行代码大体分为三个部分。

         第一部分,是一些简单的API实现,如string.len,  string.reverse,string.lower,  string.upper等等,实现的中规中矩,乏善可陈。str_byte函数的实现中,有一行luaL_checkstack调用值得初学Lua的C binding、编写人员注意。Lua的栈不像C语言的栈那样,不大考虑栈溢出的情况。Lua栈给C函数留的默认空间很小,默认情况下只有20(LUA_MINSTACK定义在lua.h中,默认值为20)。当你要在Lua的栈上留下大量值时,务必用luaL_checkstack扩展堆栈。因为处于性能考虑,Lua和栈有关的API都是不检查栈溢出的情况的。

if (posi + n <= pose) /* (size_t->int) overflow */
	return luaL_error(L, "string_slice_too_long");
	luaL_checkstack(L, n, "string_slice_too_long");
	for (i = 0; i<n; i++)
		lua_pushinteger(L, uchar(s[posi + i - 1]));





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值