Lua学习笔记:浅谈table的实现

news2024/12/29 8:37:30
前言
本篇在讲什么

Lua中的table的实现
本篇适合什么

适合初学Lua的小白
本篇需要什么

Lua语法有简单认知
依赖Sublime Text编辑器

本篇的特色

具有全流程的图文教学
重实践,轻理论,快速上手
提供全流程的源码内容


★提高阅读体验★

👉 ♠ 一级标题 👈

👉 ♥ 二级标题 👈

👉 ♣ 三级标题 👈

👉 ♦ 四级标题 👈


目录

  • ♠ table的定义
  • ♠ table的创建
  • ♠ table的销毁
  • ♠ table的操作
    • ♥ 读
  • ♠ 写
  • ♠ 获取长度
  • ♠ 总结一下
  • ♠ 推送
  • ♠ 结语


♠ table的定义

摘自Lua5.1源码文件lobject.h

/*
** Tables
*/

typedef union TKey {
  struct {
    TValuefields;
    struct Node *next;  /* for chaining */
  } nk;
  TValue tvk;
} TKey;


typedef struct Node {
  TValue i_val;
  TKey i_key;
} Node;


typedef struct Table {
  CommonHeader;
  lu_byte flags;  /* 1<<p means tagmethod(p) is not present */ 
  lu_byte lsizenode;  /* log2 of size of `node' array */
  struct Table *metatable;
  TValue *array;  /* array part */
  Node *node;
  Node *lastfree;  /* any free position is before this position */
  GCObject *gclist;
  int sizearray;  /* size of `array' array */
} Table;

  • flags:元方法的标记,用于查询table是否包含某个类别的元方法
  • lsizenode:表示table的hash部分大小,2的幂数
  • metatable:该表的元表
  • array:table的数组部分
  • node:hash表的起始位置指针
  • lastfree:hash表最后位置的指针
  • gclist:gc相关链表
  • sizearray:数组的大小,不一定是2的幂数

每个table,最多会由三块连续内存构成

  • 一个 table 结构
  • 一块存放了连续整数索引的数组
  • 和一块大小为 2 的整数次幂的哈希表

♠ table的创建

在之前C/C++操作Lua的表中就了解过,创建Lua的表可以通过通过函数lua_createtable,源码如下所示

LUA_API void lua_createtable (lua_State *L, int narray, int nrec) {
  lua_lock(L);
  luaC_checkGC(L);
  sethvalue(L, L->top, luaH_new(L, narray, nrec));
  api_incr_top(L);
  lua_unlock(L);
}

在这里插入图片描述

其中创建函数调用的事luaH_new函数,其定义在ltabel.c脚本内

Table *luaH_new (lua_State *L, int narray, int nhash) {
  Table *t = luaM_new(L, Table);
  luaC_link(L, obj2gco(t), LUA_TTABLE);
  t->metatable = NULL;
  t->flags = cast_byte(~0);
  /* temporary values (kept only if some malloc fails) */
  t->array = NULL;
  t->sizearray = 0;
  t->lsizenode = 0;
  t->node = cast(Node *, dummynode);
  setarrayvector(L, t, narray);
  setnodevector(L, t, nhash);
  return t;
}

可根据传入的narray和nhash,初始化数组和hash表的大小


♠ table的销毁

void luaH_free (lua_State *L, Table *t) {
  if (t->node != dummynode)
    luaM_freearray(L, t->node, sizenode(t), Node);
  luaM_freearray(L, t->array, t->sizearray, TValue);
  luaM_free(L, t);
}
  • 释放数组
  • 释放hash表
  • 释放table结构

♠ table的操作

针对table有多种这里我们挑一些看看源码,了解一下大致原理


♥ 读

源码摘自ltable.c,主要的查询入口是luaH_get函数

/*
** main search function
*/
const TValue *luaH_get (Table *t, const TValue *key) {
  switch (ttype(key)) {
    case LUA_TNIL: return luaO_nilobject;
    case LUA_TSTRING: return luaH_getstr(t, rawtsvalue(key));
    case LUA_TNUMBER: {
      int k;
      lua_Number n = nvalue(key);
      lua_number2int(k, n);
      if (luai_numeq(cast_num(k), nvalue(key))) /* index is int? */
        return luaH_getnum(t, k);  /* use specialized version */
      /* else go through */
    }
    default: {
      Node *n = mainposition(t, key);
      do {  /* check whether `key' is somewhere in the chain */
        if (luaO_rawequalObj(key2tval(n), key))
          return gval(n);  /* that's it */
        else n = gnext(n);
      } while (n);
      return luaO_nilobject;
    }
  }
}

会根据传入的key的类型,去调用对应类型的查询方法
如果key的类型是nil,则直接返回nil,table的key不能为nil
整数会根据大小,如果不超过数组长度,优先从数组内去查询
超过数组长度的key或者其他类型的key,直接从hash表内查询对应的值


♠ 写

同样的在之前操作表的学习中我们知道了可以通过以下几个函数来修改或添加表的键值

  • lua_settable
  • lua_setfield
  • lua_rawset
  • lua_rawseti

查看源码,这几个接口最终都是调用了函数luaH_set,代码如下所示

TValue *luaH_set (lua_State *L, Table *t, const TValue *key) {
  const TValue *p = luaH_get(t, key);
  t->flags = 0;
  if (p != luaO_nilobject)
    return cast(TValue *, p);
  else {
    if (ttisnil(key)) luaG_runerror(L, "table index is nil");
    else if (ttisnumber(key) && luai_numisnan(nvalue(key)))
      luaG_runerror(L, "table index is NaN");
    return newkey(L, t, key);
  }
}

♠ 获取长度

获取table的长度通过函数luaH_getn,源码如下,这里需要注意,如果表不是从1开始的连续整数为key,长度获取可能会错乱

/*
** Try to find a boundary in table `t'. A `boundary' is an integer index
** such that t[i] is non-nil and t[i+1] is nil (and 0 if t[1] is nil).
*/
int luaH_getn (Table *t) {
  unsigned int j = t->sizearray;
  if (j > 0 && ttisnil(&t->array[j - 1])) {
    /* there is a boundary in the array part: (binary) search for it */
    unsigned int i = 0;
    while (j - i > 1) {
      unsigned int m = (i+j)/2;
      if (ttisnil(&t->array[m - 1])) j = m;
      else i = m;
    }
    return i;
  }
  /* else must find a boundary in hash part */
  else if (t->node == dummynode)  /* hash part is empty? */
    return j;  /* that is easy... */
  else return unbound_search(t, j);
}

♠ 总结一下

table的实现就是通过一个固定长度的数组和一个hash表构成的


♠ 推送

  • Github
https://github.com/KingSun5

♠ 结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。

👉 本文属于原创文章,转载请评论留言,并在转载文章头部著名作者出处👈

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/723255.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CIO40---22亿灯塔工厂建设规划之工业4.0

1-灯塔工厂规划&#xff1a; 行业趋势 在人工智能、物联网和5G技术的深度渗透下&#xff0c;3C既能作为交互的入口又能是交互的出口&#xff0c;3C产业已成为场景最丰富的产业领域&#xff0c;柔性化生产、个性化定制才能给用户提供更好的体验。市场需求要求企业进行数字化升级…

UE4 如何设置玩家Character的两个位置和角度之间的切换

问题&#xff1a;玩家Character的角度不能直接去设置其中的Camera角度&#xff0c;因为Camera的角度是由鼠标X/Y移动增量决定的&#xff0c;同时把Camera的角度传给PlayController中的PlayCameraManneger&#xff0c;PlayCameraManneger是所有Pawn类型的Camera视口总管&#xf…

Netty的事件驱动模型nio,epoll,oio各个使用场景和支持的网络通讯协议

1.首先说一下nio和epoll有什么区别 在Netty中&#xff0c;Epoll和NIO是两种不同的事件驱动模型&#xff0c;用于实现网络通信。它们在底层的实现和性能特征上有一些区别。 1. NIO&#xff08;Non-blocking I/O&#xff09;&#xff1a;NIO是Java原生的非阻塞I/O模型&#xff…

【NX】NX二次开发中判断曲线是否重合

在NX二次开发中&#xff0c;并没有直接的函数判断两条曲线是否重合&#xff0c;那么我们自己有没有办法判断两条曲线是否重合呢&#xff0c;自然是有的&#xff0c;那么首先我们得定义一下什么叫做重合&#xff0c;几乎重合的曲线算重合吗&#xff0c;这里就涉及到一个容忍度的…

如何控制滚轮横向滑动(原生JS实现方法)

控制滚轮横向滑动 提示&#xff1a;这个是以前讨论的时候遇到的情况 ; 回头想了一下应用场景确实挺多的,.所以今天趁周末大致的记录一下如何通过js去实现【横向滚动】 文章目录 控制滚轮横向滑动解决思路如下1.如何在页面中展示横向滚动条2.如何获取鼠标的【滚动轮】3.通过什么…

AI for Science 交流会来了!科学计算前沿邀您共同探讨

随着深度学习不断驱动技术创新&#xff0c;人工智能科学计算迈向高质量发展道路。百度飞桨作为科学计算的坚定支持者&#xff0c;计划于7月13日举办飞桨科学计算线下交流会。本次交流会以百度飞桨深度学习框架为基座&#xff0c;广泛联动人工智能科学计算领域头部专家学者、高等…

数据宝董事长汤寒林应邀将在2023世界人工智能大会发言

摘要&#xff1a;2023世界人工智能大会即将在上海举行&#xff0c;数据宝董事长、华东江苏大数据交易中心总经理汤寒林应邀将出席产业区块链生态论坛&#xff0c;并将围绕“数据要素流通与交易”话题展开讨论。 由国家发展和改革委员会、科学技术部、工业和信息化部、国家互联…

【Linux】如何将自定义源文件打包并生成动态库

在这之前我们已经讲述了如何将自定义源文件打包并生成静态库&#xff0c;本文来带你了解如何打包成为动态库并使用 动态库打包动态库使用1.增加环境变量方法2.配置.conf文件3.创建一个软连接在当前目录4.创建一个软连接在系统库目录 静态库的加载动态库的加载 关于源文件的书写…

使用Maven创建Java Web项目

环境 windows环境 jdk8 maven3.6 IDEA2022 步骤 1.新建maven工程 使用IDEA工具&#xff0c;File->New->Project->选择项目目录&#xff0c;填写项目名称&#xff0c;选择对应选项&#xff0c;其中Create Git repository可不勾选&#xff0c;如下图所示&#xff…

怎样将递归函数转为非递归函数

一道非常不错的面试题&#xff1a;不支持递归的程序语言如何实现递归程序&#xff1f; 之所以说这道题好&#xff0c;是因为&#xff1a; 首先&#xff0c;它不是纯粹考概念和死记硬背&#xff0c;求职者在回答问题之前需要进行一定的思考&#xff1b; 其次&#xff0c;这道题…

phar协议文件包含

实验目的 通过本实验&#xff0c;了解php封装伪协议&#xff0c;掌握phar协议文件包含的用法 实验环境 操作机&#xff1a;kali 靶机&#xff1a;Windows 2007 实验地址&#xff1a;http://靶机ip/exp/include2/phar/phar1/ 用户名&#xff1a;college 密码&#xff1a;360C…

Script file ‘D:\Anaconda365\Scripts\conda-script.py‘ is not present

运行anaconda&#xff0c;出现错误&#xff0c;找不到conda-script.py&#xff0c; 解决途径&#xff1a; 用everything查找电脑上的conda-script.py文件&#xff0c; 将查到的codna-script.py文件放入Script文件夹完美解决。 再从运行conda list&#xff0c;就不报错了。

监控系统Zabbix

zabbix概述 作为一个运维&#xff0c;需要会使用监控系统查看服务器状态以及网站流量指标&#xff0c;利用监控系统的数据去了解上线发布的结果&#xff0c;和网站的健康状态。 利用一个优秀的监控软件&#xff0c;我们可以&#xff1a; 通过一个友好的界面进行浏览整个网站…

前端Vue自定义精美上下滚动通告栏组件 常用于展示公告信息 上下滚动跑马灯 上下滚动广播

前端Vue自定义精美上下滚动通告栏组件 常用于展示公告信息 上下滚动跑马灯 上下滚动广播,下载完整代码请访问uni-app插件市场地址&#xff1a;https://ext.dcloud.net.cn/plugin?id13318 效果图如下: # cc-noticeBar #### 使用方法 使用方法 <!-- 默认颜色#333公告栏 -…

YoloV5/YoloV7改进---注意力机制:SRM,卷积神经网络再校准模块,性能优于SE、GE

目录 1.SRM介绍 ​编辑 2.SRM引入到yolov5 2.1 加入common.py中&#xff1a; 2.2 加入yolo.py中&#xff1a; 2.3 yolov5s_SRM.yaml 2.4 yolov5s_SRM1.yaml 3.YOLOv5/YOLOv7魔术师专栏介绍 1.SRM介绍 论文&#xff1a;https://openaccess.thecvf.com/content…

设计模式7:装饰者模式

目录 装饰者模式是要解决什么问题&#xff1f;装饰者模式在JDK中有哪些实际应用&#xff1f;装饰者模式在Android SDK中有哪些实际应用&#xff1f;装饰者模式和适配器模式的区别是什么&#xff1f;装饰者模式和代理模式的区别是什么&#xff1f; 装饰者模式是要解决什么问题&a…

基于matlab使用单类全卷积数据描述异常检测网络检测药丸图像上的缺陷(附源码)

一、前言 此示例演示如何使用单类全卷积数据描述 &#xff08;FCDD&#xff09; 异常检测网络检测药丸图像上的缺陷。 异常检测的一个关键目标是让人类观察者能够理解为什么经过训练的网络将图像分类为异常。FCDD支持e可解释的分类&#xff0c;它用证明神经网络如何达到其分类…

Python快速将多个文件夹内的文件移动至一个文件夹内

在日常办公中生活中&#xff0c;我们经常需要将多个文件夹内的文件如&#xff1a;(图片png,jpg,jpeg&#xff0c;word文档&#xff0c;Excel,PPT等等)&#xff0c;需要将这个文件夹内的文件移动至同一个文件夹内&#xff0c;如果我们复制粘贴的话&#xff0c;将会非常的繁琐以及…

Impala3.4源码阅读笔记(七)解析ScanNode(上)

前言 本文为笔者个人阅读Apache Impala源码时的笔记&#xff0c;仅代表我个人对代码的理解&#xff0c;个人水平有限&#xff0c;文章可能存在理解错误、遗漏或者过时之处。如果有任何错误或者有更好的见解&#xff0c;欢迎指正。 正文 我们知道Impala执行一条SQL的主要流程…

在vscode中配置git bash终端

将以下配置添加到vscode中的settings.json中 "terminal.integrated.profiles.windows": {"PowerShell": {"source": "PowerShell","icon": "terminal-powershell"},"Command Prompt": {"path"…