• 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

  • 相关阅读:
    jzoj 6278. 2019.8.5【NOIP提高组A】跳房子
    2019.08.05【NOIP提高组】模拟 A 组 总结
    HTML笔记
    html中的锚点设置
    前端HTML
    数据库设计(第一范式,第二范式,第三范式)
    MySQL之锁、事务、优化、OLAP、OLTP
    MySQL数据备份与还原(mysqldump)
    MySQl创建用户和授权
    MySQL之索引原理与慢查询优化
  • 原文地址:https://www.cnblogs.com/vd01/p/4935035.html
Copyright © 2020-2023  润新知