Lua中table的实现-《Lua设计与实现》

摘要:
本文来自“Lua设计与实现”的阅读笔记。建议Lua学习者可以购买一个,并简单地解释Lua的设计和实现原则。非常好。哈哈,Lua中的表设计基于数组和哈希表。与其他语言不同,数组的下标从1开始。对于哈希表,只要其键值填充为nil,就可以将其存储在其中。
本文来自《Lua设计与实现》的阅读笔记,推荐Lua学习者可以购买一本,深入浅出讲解lua的设计和实现原理,很赞,哈哈
 
Lua中对于表的设计,是基于数组和散列表,和其他语言不同,对于数组的下标是从1开始的,对于散列表而言,只要其键值补位nil,都可以存储在其中。
 
一、table的基本类型定义
首先看看table的数据定义,参考源码lobject.h
Lua中table的实现-《Lua设计与实现》第1张
 
CommonHeader, 参看专栏前面的文章;
flags 这是一个lua的byte类型的数据,用于表示表中提供了哪些元方法,比如是否提供了元方法_index,该数据最开始设置为1,如果进行查找一次,比如_index,如果存在,这该元方法对应的flag bit设置为0,在下一次查找的时候,只需要比较这个bit即可,对应的元方法在ltm.h中
Lua中table的实现-《Lua设计与实现》第2张
lsizenode,为散列表的大小,必定为2的幂对应的数字;
metatable,该table的元表;
array,该table的数组的指针
node, 该table的散列表的起始位置的指针;
lastfree, 该散列表的最后位置的指针
gclist, gc相关的链表
sizearray, 数组的大小,不一定为2的幂对应的数字
对于node数据,类似于其他语言中的字典设计hash设计,就是一个键值对集合,其定义为:
Lua中table的实现-《Lua设计与实现》第3张
需要提一下的是对于key的设计采用的是union,也就是说Lua的散列表的key,可以为nk对应的struct,也可以是TValue类型
 
二、table相关的操作的实现原理
1、查找算法的实现原理
借用原文的伪代码:
if 输入的key为整数 && key >= 0 && key <= 数组的大小
尝试在数组部分查找
else 在散列表部分查找
计算出该key的散列值,据其查找对应的node所在散列表中的位置,然后遍历其对应的链表,查找是否有该key对应的元素
举例:
local t = {}
t[1] = 0
t[100] = 0
那么1是在数组中查找,100就是在散列表中去查找了(100大于数组的len)
 
2、新增元素的实现原理
给lua中添加新元素的时候,会有可能触发重新分配table中的数组和散列表,其本质来自于散列表的rehash(由于lua对于下标超过数组的大小的数字,都会存储在散列表部分去,所以数组部分的插值不会触发rehash)
散列表的组织,就是多个mainposition,每个单独的mainposition会对应一个数据链表,当插入一个key的时候,会调用luaHsetluaH_setnumluaH_setstr,来获得该key对应的TValue指针,如果没有,则调用内部的newkey函数来分配一个新的key:
Lua中table的实现-《Lua设计与实现》第4张
基本的实现过程看源代码写的比较详细,这儿说一下rehash部分的操作,在ltable.c中:
Lua中table的实现-《Lua设计与实现》第5张
1) nums中存放的是元素的数量
2)分表遍历数组(numusearray)和散列表(numusehash),统计更新nums中的数量大小
3) 重新计算数组和hash部分的大小,数组大小的计算规则:逐个遍历nums数组,获得其范围区间内所包含的整数数量大于50%的最大索引,作为rehash后的数组大小,这个索引值来自与computesizes函数:
Lua中table的实现-《Lua设计与实现》第6张
可能看了会有点迷糊,那我就用大白话说一下吧:
首先nums数组在统计后,每个下标对应的是处于当前2^(i -1) - 2^i中的元素的个数,然后不断的累加计算,求得满足 sum > 2^n/2的最大下标值(这个下标值是nums数组中的)
所以,在不同的rehash阶段,table中的同一个key可能会在数组部分和散列表部分交替出现,也是可能的。
由于rehash会带来较大的性能消耗,所以一般都尽量避免,比如在创建表的时候,就采用预填充的算法
 
3、取长度算法的原理
如果table中元表没有重载len方法,则调用的是luaH_getn方法,其基本的伪代码为:
if 表中存在数组部分:
初始化i = 0, j = sizearray
  while(j - i > 1){
    m = (j + i)/2
  if(array[m-1] == nil)
    j = m
  else
    i = m
  }
  return i
else
  查找表中散列表长度,算法同数组部分
对于表中只有散列表的时候,其实质就是对键值为正整数的部分进行长度操作,如果既有数组,又有散列表,则优先对数组部分进行长度操作

免责声明:文章转载自《Lua中table的实现-《Lua设计与实现》》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇使用jsPDF 和jspdf-autotable 导出中文表格页面深入探究Lua的GC算法(下)-《Lua设计与实现》下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Selenium Python FirefoxWebDriver处理打开保存对话框

 代码如下(网上示例): #profile =  webdriver.FirefoxProfile(r"C:UsersSkyyjAppDataRoamingMozillaFirefoxProfiles1rzh6139.default")profile = webdriver.FirefoxProfile()##设置成0代表下载到浏览器默认下载路径;设置成2...

黑马程序员——JAVA学习笔记八(集合)

1,    JAVA最初版本只为最常用的数据结构提供了很少的一组类:Vector、Stack、Hashtable、BitSet与Enumeration接口,从JAVA1.2版本开始推出了一组功能完善的的数据结构。 集合类的由来:  对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定。  就使用集合容器进行存储。 集合特点: 1,用于存储对象的容器...

MySQL(一) 数据表数据库的基本操作

      序言         这类文章,记录我看《MySQL5.6从零开始学》这本书的过程,将自己觉得重要的东西记录一下,并有可能帮助到你们,在写的博文前几篇度会非常基础,只要动手敲,跟着我写的例子全部实现一遍,基本上就搞定了,前期很难理解的东西基本没有,所以写博文的内容,就是以练题的形式来呈现的。             需要用的资料以链接的形式给需...

element UI 之table表格表头过长使用点点...显示,并添加鼠标移入悬浮显示

需求: 鼠标移入表头: 1、样式中添加 .el-table .cell {word-break: keep-all !important;white-space: nowrap !important;}2、在需要悬浮显示的表头文字过长处添加 :show-overflow-tooltip="true":render-header="renderHeade...

[转载]oracle删除数据后的恢复

原文地址:oracle删除数据后的恢复作者:無心傷害 今天一哥们把正式服务器上oracle数据表给delete了,我晕。吓我一身冷汗。赶紧google一下,终于找到正解。记录下来备忘。 要达到删除数据,有以下几种方式都可以:1、delete2、drop一个表3、truncate一个表重要的不是怎么删除一个表,而是误删除数据后怎么立即恢复(不考虑全库...

sysbench对自装MySQL数据库进行基准测试

一、 安装sysbench wget https://packagecloud.io/install/repositories/akopytov/sysbench/script.rpm.sh chmod +x script.rpm.sh ./script.rpm.sh yum install -y sysbench 二、准备测试表 sysbench //...