我们这里打算实现两个方法
1.对一个字符串做hash并对其hash值取摸,在lua中我们可以这样调用该方法:
local value = demo.mod("abcdefe",8);
其中demo是我们写好的c库;
mod方法的第一个参数是要进行取摸的字符串;
第二个参数是摸;
2.由于lua中的时间函数无法精确到毫秒级,我们这里实现一个可以获取系统毫秒的时间:
local time = demo.time();
具体实现
首先引入lua的c api头文件和我们用到的时间头文件
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <sys/time.h>
实现一个murmurhash算法,用来hash我们的字符串
typedef unsigned long long uint64_t;
typedef long long int64_t;
typedef long int int32_t;
static uint64_t murmurhash64A(const void *key,size_t len,int32_t seed){
int64_t m = 0xc6a4a7935bd1e995LL;
int r = 47;
uint64_t h = seed ^ (len * m);
const uint64_t * data = (const uint64_t *)key;
const uint64_t * end = data + (len >> 3);
while(data != end){
uint64_t k = *data++;
k *= m;
k ^= k >> r;
k *= m;
h ^= k;
h *= m;
}
const unsigned char * data2 = (const unsigned char *)data;
switch(len & 7){
case 7: h ^= (uint64_t)data2[6] << 48;
case 6: h ^= (uint64_t)data2[5] << 40;
case 5: h ^= (uint64_t)data2[4] << 32;
case 4: h ^= (uint64_t)data2[3] << 24;
case 3: h ^= (uint64_t)data2[2] << 16;
case 2: h ^= (uint64_t)data2[1] << 8;
case 1: h ^= (uint64_t)data2[0];
h *= m;
};
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
}
我们看到上面这个方法是一个纯c函数,lua如何于c传递数据呢?我们看下面这个方法
// 时间上lua和c交换数据使用的是一个lua_State栈结构
// 当我们在lua中调用demo.mod("a",8);这个方法时,该方法的两个参数会被顺序的压入到栈顶
// 这个时候栈底是字符串"a",栈顶是数字8
static int mod(lua_State *L){
//checks whether the key is a string
size_t len;
// 这个方法用来检查第一个参数是不是一个字符串或数字,如果不是那么lua在调用时就会报错
// len这个变量保存的是字符串的长度,这个值是调用该方法后被回填的值。
// 还有一个需要说明的是,在lua的栈中序号1代表栈底,序号2代表栈底的上一个元素
// 所以这里我们向luaL_checklstring方法的第二个参数传入1
const void *key = luaL_checklstring(L,1,&len);
//checks if the num is a number
int num = luaL_checknumber(L,2);
uint64_t seed=0x1234ABCD;
uint64_t h = murmurhash64A(key,len,seed);
int index = h%num;
// 将计算出的摸值压入栈顶
lua_pushnumber(L,index); //the first return value
// 返回值代表demo.mod()这个方法返回的参数个数
// lua会根据返回数字的个数,从栈中逐个取出作为lua方法的返回值
return 1;
}
下面这个是我们从5.2中拿过来的代码
static void setfuncs (lua_State *l, const luaL_Reg *reg, int nup){
int i;
luaL_checkstack(l, nup, "too many upvalues");
for (; reg->name != NULL; reg++) { /* fill the table with given functions */
for (i = 0; i < nup; i++) /* copy upvalues to the top */
lua_pushvalue(l, -nup);
lua_pushcclosure(l, reg->func, nup); /* closure with those upvalues */
lua_setfield(l, -(nup + 2), reg->name);
}
lua_pop(l, nup); /* remove upvalues */
}