Lua1.0 代码分析 hash.c

转载出处: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 int nhash)

{

 Hash *t = new (Hash);

 if (t == NULL)

 {

  lua_error ("not enough memory");

  return NULL;

 }

 nhash(t) = nhash;

 markarray(t) = 0;

 nodelist(t) = newvector (nhash, Node*);

 if (nodelist(t) == NULL)

 {

  lua_error ("not enough memory");

  return NULL;

 }

 return t;

}

新建一个关联数组,入参是关联数组的大小。

新建一个关联数组。

设置大小。

打标记。

新建指针数组。

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)

{

 int h;

 Node *n;

 h = head (t, ref);

 if (h < 0) return NULL;

 n = present(t, ref, h);

 if (n == NULL)

 {

  n = new(Node);

  if (n == NULL)

  {

   lua_error ("not enough memory");

   return NULL;

  }

  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

static int head (Hash *t, Object *ref/* hash function */

{

 if (tag(ref) == T_NUMBER) return (((int)nvalue(ref))%nhash(t));

 else if (tag(ref) == T_STRING)

 {

  int h;

  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 */

  }

  return h;

 }

 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

static Node *present(Hash *t, Object *refint h)

{

 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;

 }

 else if (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 */

  return NULL;

#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

 return n;

}

通过数组和下标找到相应的链表,在链表中查找是否有指定的值。如果有,返回结点,如果没有,返回空。
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

void lua_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

 {

  int h = 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;

     }

     else if (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

时间: 2024-11-15 09:27:20

Lua1.0 代码分析 hash.c的相关文章

Lua1.0 代码分析 库

Lua1.0 代码分析 库库的代码相对比较简单.这里以数学库为例进行说明.比如看下这个取绝对值的数学函数 static void math_abs (void) {  double d;  lua_Object o = lua_getparam (1);  if (o == NULL)  { lua_error ("too few arguments to function `abs'"); return; }  if (!lua_isnumber(o))  { lua_error (

Lua1.0 代码分析 table.c

转载出处:http://my.oschina.net/xhan/blog/307961 table.c 代码分析 全局符号,常量,字符串,关联数组,文件列表的定义. 全局符号: 初始有 5 个基本的符号,Lua 预设的函数和库函数都注册在里面. 常量: 初始的几个常量是 Lua 中 type 的名字. 字符串表,关联数组表,文件列表 所有的这些在 table.c 中定义的这些数组可以认为是 Lua 的全局注册表空间,Lua 的环境. 函数分析 ? 1 2 3 4 5 6 7 8 9 10 11

Lua1.0 代码分析 inout.c

inout.c 代码分析 主要看下对于文件的处理 /* ** Function to open a file to be input unit. ** Return 0 on success or 1 on error. */ int lua_openfile (char *fn) {  lua_linenumber = 1;  lua_setinput (fileinput);  lua_setunput (fileunput);  fp = fopen (fn, "r");  if

linphone3.4.0代码分析

主要类型定义: 1.LinphoneCoreVTable /** * This structure holds all callbacks that the application should implement. * None is mandatory. **/ typedef struct _LinphoneVTable{ LinphoneGlobalStateCb global_state_changed; /**<Notifies globlal state changes*/ Lin

OAuth2.0学习(4-1)Spring Security OAuth2.0 - 代码分析

1.org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter              org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter              org.springframework.security.oauth2.client.fil

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载

Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 2012-09-07 11:19 8152人阅读 评论(12) 收藏 举报 代码分析android相册优化工作 Android4.0图库Gallery2代码分析(二) 数据管理和数据加载 一 图库数据管理 Gallery2的数据管理 DataManager(职责:管理数据源)- MediaSource(职责:管理数据集) - MediaSet(职责:管理数据项).DataManager中初始化所有的数据源(LocalSo

SDL2.0例子代码分析-----CheckKeys Project

SDL简介 SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成.SDL提供了数种控制图像.声音.输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux.Windows.Mac OS X等)的应用软件.目前SDL多用于开发游戏.模拟器.媒体播放器等多媒体应用领域. SDL1.2和SDL2的差别 SDK1.2和SDL2.1系列的API接口变动的不小,当然功能也大大增强,支持多线程窗口. 具体的change 请看 h

(原创)cocos2d-x 3.0 示例代码分析1:AppDelegate

星月最近在用3.0做类似刀塔游戏,第一次用3.0,之前一直只是查查资料,最近发现做一些特定行为需要对3.0一些新的特性了解.所以趁这个机会,把3.0的测试代码过一遍,同时增加注释,希望能对大家有帮助~ 因为项目原因,所以不定期更新~~(小白:借口,继续找借口!) 星月倾心贡献~~~ // AppDelegate.cpp /**************************************************************************** Copyright (

阅读代码分析工具Understand 2.0试用

Understand 2.0是一款源码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实能够大大提高代码阅读效率. 因为Understand功能十分强大,本文不可能详尽地介绍它的全部功能,所以仅仅列举本人觉得比較重要或有特色的功能,以做抛砖引玉之举. Understand 2.0能够从http://www.scitools.com/下载到,安装后能够试用15天. 使用Understand阅读代码前.要先创建一个Project,然后把全部的源码文件增加到这个Project里.这里我创建了