标签:
转载出处:http://my.oschina.net/xhan/blog/308325
hash.c 代码分析
Lua 中最重要的一个数据结构及相关操作。
主要看下几个对外的接口。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /*** Create a new hash. Return the hash pointer or NULL on error.*/Hash *lua_hashcreate (unsigned intnhash){ Hash *t = new(Hash); if(t == NULL) {  lua_error ("not enough memory");  returnNULL; } nhash(t) = nhash; markarray(t) = 0; nodelist(t) = newvector (nhash, Node*); if(nodelist(t) == NULL) {  lua_error ("not enough memory");  returnNULL; } returnt;} | 
新建一个关联数组,入参是关联数组的大小。
新建一个关联数组。
设置大小。
打标记。
新建指针数组。
void lua_hashdelete (Hash *h);
释放关联数组。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | /*** If the hash node is present, return its pointer, otherwise create a new** node for the given reference and also return its pointer.** On error, return NULL.*/Object *lua_hashdefine (Hash *t, Object *ref){ inth; Node *n; h = head (t, ref); if(h < 0) returnNULL; n = present(t, ref, h); if(n == NULL) {  n = new(Node);  if(n == NULL)  {   lua_error ("not enough memory");   returnNULL;  }  n->ref= *ref;  tag(&n->val) = T_NIL;  n->next = list(t,h); /* link node to head of list */  list(t,h) = n; } return(&n->val);} | 
在关联数组中查看指定项是否存在,如果存在,返回它的指针。
如果不存在,新建一个结点,也同样返回它的指针。
返回关联引用在关联数组中的头。
跟据关联数组的头,查看引用在关联数组中是否存在:
如果不存在,新建一个结点,设置其引用为传入的参数,同时设置其值为空,把新建的结点插入到表头。
如果存在,直接返回它的值。
来看看 head 和 present 的实现:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | staticinthead (Hash *t, Object *ref) /* hash function */{ if(tag(ref) == T_NUMBER) return(((int)nvalue(ref))%nhash(t)); elseif(tag(ref) == T_STRING) {  inth;  char*name = svalue(ref);  for(h=0; *name!=0; name++) /* interpret name as binary number */  {   h <<= 8;   h += (unsigned char) *name; /* avoid sign extension */   h %= nhash(t); /* make it a valid index */  }  returnh; } else {  lua_reportbug ("unexpected type to index table");  return-1; }} | 
关联数组分为两个部分,数值部分和引用部分。
数值部分的下标是通过数值的大小和关联数组的大小取余得到的。
而引用部分目前只支持字符串类型。
字符串部分是通过一个算法得到它的散列值的。
具体算法是把字符串的 ASCII 码左移 8 位后相加之和与关联数组的大小取余。
再看 present 的实现
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | staticNode *present(Hash *t, Object *ref, inth){ Node *n=NULL, *p; if(tag(ref) == T_NUMBER) {  for(p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next)   if(ref_tag(n) == T_NUMBER && nvalue(ref) == ref_nvalue(n)) break; } elseif(tag(ref) == T_STRING) {  for(p=NULL,n=list(t,h); n!=NULL; p=n, n=n->next)   if(ref_tag(n) == T_STRING && streq(svalue(ref),ref_svalue(n))) break; } if(n==NULL) /* name not present */  returnNULL;#if 0 if(p!=NULL) /* name present but not first */ {  p->next=n->next; /* move-to-front self-organization */  n->next=list(t,h);  list(t,h)=n; }#endif returnn;} | 
通过数组和下标找到相应的链表,在链表中查找是否有指定的值。如果有,返回结点,如果没有,返回空。
void lua_hashmark (Hash *h) 
标记关联数组中所有的结点。
再看看 lua_next 的实现
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | voidlua_next (void){ Hash *a; Object *o = lua_getparam (1); Object *r = lua_getparam (2); if(o == NULL || r == NULL) { lua_error ("too few arguments to function `next‘"); return; } if(lua_getparam (3) != NULL) { lua_error ("too many arguments to function `next‘"); return; } if(tag(o) != T_ARRAY) { lua_error ("first argument of function `next‘ is not a table"); return; } a = avalue(o); if(tag(r) == T_NIL) {  firstnode (a, 0);  return; } else {  inth = head (a, r);  if(h >= 0)  {   Node *n = list(a,h);   while(n)   {    if(memcmp(&n->ref,r,sizeof(Object)) == 0)    {     if(n->next == NULL)     {      firstnode (a, h+1);      return;     }     elseif(tag(&n->next->val) != T_NIL)     {      lua_pushobject (&n->next->ref);      lua_pushobject (&n->next->val);      return;     }     else     {      Node *next = n->next->next;      while(next != NULL && tag(&next->val) == T_NIL) next = next->next;      if(next == NULL)      {       firstnode (a, h+1);       return;      }      else      {       lua_pushobject (&next->ref);       lua_pushobject (&next->val);      }      return;     }    }    n = n->next;   }   if(n == NULL)    lua_error ("error in function ‘next‘: reference not found");  } }} | 
在 Lua 脚本中调用 next 时调用的就是它。作用是数组遍历。
给定一个数组和引用,返回数组中给定引用的下一个结点。
如果给的是一个空值,返回数组的头一个结点。
否则返回数组中该值的下一个非空结点。
这里返回了两个值到 Lua 的脚本中。
看下自带的一个用到它的测试程序(array.lua):
a = @()
i=0
while i<10 do
 a[i] = i*i
 i=i+1
end
r,v = next(a,nil)
while r ~= nil do
 print ("array["..r.."] = "..v)
 r,v = next(a,r)
end
这个程序会打印出以下:
array[0] = 0
array[1] = 1
array[2] = 4
array[3] = 9
array[4] = 16
array[5] = 25
array[6] = 36
array[7] = 49
array[8] = 64
array[9] = 81
标签:
原文地址:http://www.cnblogs.com/vd01/p/4935035.html