Lua设计与实现--读书笔记
lua简介
C++底层核心模块,暴露核心接口给lua脚本层,网络的收发都在c++层完成,本书简述lua解释器的实现原理,工业级脚本语言
特性:简洁高效可移植可嵌入可扩展
纯C编写
Lua的数据结构、Lua虚拟机、Lua的其他内容
我缺少的知识:词法分析、语法分析、递归下降分析、BNF规则
Lua代码是解释成lua虚拟机能识别的字节码而运行的
- 翻译成字节码
- 字节码装载到虚拟机执行
Lua是有宿主系统的
Lua采用一种通用的数据类型来表示所有的类型,Lua只有字符串和表两种基本的数据结构
一种通用的数据类型:lua_TValue
- 一个字段存储数据类型
- 存储不同的数据类型的数据(联合体)
commonHeader+union,lua还要标出处理GC的对象
配图:


字符串
每当创建字符串时,会先查找内存中是否有一份相同的字符串数据,如果存在就直接复用,将引用直接指向字符串数据,否则就重新创建一份数据,这样在进行字符串数据比较和查找时性能会提升不少,系统内部维护了一个全局的字符串的表用来存放字符串(LUA虚拟机使用一个散列桶来管理,global_state的strt),比较时可以直接比较字符串散列值,这样也是有空间优化,相同字符串只有一份数据
应当尽量少的使用字符串连接符,每次使用都会创建一个新的字符串,大量重复的相同字符连接可以用一个table缓冲区一个字符一个字符的缓存起来,然后再调用table.concat将其全部连接

Table



有数组和散列表部分,唯一的要求就键值不能为nil
数组从1开始索引,内涵散列桶数组起点和终点的指针还有元表,意思0和负数的索引都是哈希表里的内容,如果数字的很大,超过了数组长度则是在散列表里面存
存的数据有可能在数组或者在散列表部分
查找数据:使用key来查找。我们看这个key是否为正整数且他是否大于0且小于等于数组长度,在则在数组中查找,不在则跑到散列表去查
设置数据:set setnum setstr三个set数据的函数先找对应的key,找不到则内部是调用一个newkey函数分配一个新key,大小不够会重新散列
个人实践规律:取长度符号#
取长度,只对表的序列部分进行,序列指的是表的一个子集,
当既有数组部分又有散列表部分,优先取数组部分长度,
当只有数组部分时候取数组的长度
(#{1,2,3,nil,4,5,6,} == 6)
当散列表的key和数组的Index一致的时候,遇到[num] = nil的时候便停止计数
(#{[1] = 10,[2]=20,[3]=nil,[4]=60} ==2)
(#{[1] = 10,[2]=20,[3]=32,[5]=60} ==3) 缺少4
当只有散列表部分时,取key从1开始的最大正整数
(#{["asd"] = 10,["sd1"]=20,["aasd"]=nil,[45]=60} == 0)
(#{["asd"] = 10,["sd1"]=20,["aasd"]=nil,[1]=60,[2]=899} == 0)
一般要规避重新散列操作,一般通过只使用数组部分、预分配等方式来避免重新散列
尽量不要混用数组和散列表部分,一个table最好只放一类数据
lua实现一个队列
网上的版本,用起来,pushright存数据会往数组里的填很多东西,pushleft突破了0,会往哈希表里填东西,如果一直popleft多了则数组部分的头部会被回收吗?推测不会,数组部分的指针指向的数组整体,前面几个元素回收了头部会改变,如果是popright回收数组部分是可以理解的,如果pop的是哈希的部分应该是可以回收的
List = {}
function List.new ()
return {first = 0, last = -1}
end
function List.pushleft (list, value)
local first = list.first - 1
list.first = first
list[first] = value
end
function List.pushright (list, value)
local last = list.last + 1
list.last = last
list[last] = value
end
function List.popleft (list)
local first = list.first
if first > list.last then error("list is empty") end
local value = list[first]
list[first] = nil -- to allow garbage collection
list.first = first + 1
return value
end
function List.popright (list)
local last = list.last
if list.first > last then error("list is empty") end
local value = list[last]
list[last] = nil -- to allow garbage collection
list.last = last - 1
return value
end
插入、删除时间复杂度 O(1),空间复杂度可能会随着消息变大而变大,O(n)
使用Insert和Remove的版本,空间复杂度是O(1)的,时间复杂度是(n)
关于清空lua table
a = {1,2,3,4,5}
function upDate(t)
print("====")
print(t)
t = {}
print(t)
end
upDate(a)
print(a)
print(a[1])
这里设置t = {} 或者 t = nil都不会真的清空table对象 a
只是处理了变量和值之间的关系,t的地址是值传递的,尝试用一个新表的地址给它赋值会出现函数参数值传递,对地址t引用的实际值并不会有影响,但是通过t改动引用table里的实际值是会对a有影响的比如t[1]=999,这里就是通过地址改动到了实际值的区域
我的方法是使用——table套table,其实就是相当于指针的指针
local a = {1,2,3,4,5}
local b = {9,99,999,9999}
function upDate(t)
print("====")
print(t.a)
t.a = nil
--a = nil
print(t.a)
end
local ta ={}
ta.a = a
upDate(ta)
print(ta.a)
print(a)
这样子ta.a可以便可以正确的赋值为nil了
我实现的一份LuaQueue代码
local LuaQueue = {}
-- pure array table, if you want to iterate use lua "ipairs"
function LuaQueue.New()
return {_length = 0,_maxLength=10,_queue={}}
end
function LuaQueue.SetMaxLength(queue,length)
if(queue==nil) then
error("Queue is nil")
end
queue._maxLength = length
end
function LuaQueue.GetLength(queue)
if(queue==nil) then
error("Queue is nil")
end
return queue._length
end
--push in array last pos O(1)
function LuaQueue.Push(queue,val)
if(queue==nil) then
error("Queue is nil")
end
if(queue._length<queue._maxLength) then
table.insert(queue._queue,val)
queue._length = queue._length+1
else
error("Already reach last pos")
end
end
--O(n)
function LuaQueue.Pop(queue)
if(queue==nil) then
error("Queue is nil")
end
if(queue._length>0) then
table.remove(queue._queue,1)
queue._length = queue._length-1
else
error("Queue is Empty")
end
end
function LuaQueue.GetData(queue)
if(queue==nil) then
error("Queue is nil")
end
local data={}
if(queue._length>0) then
for _,v in ipairs(queue._queue) do
table.insert(data,v)
end
return data
else
print("Queue is Empty")
end
end
function LuaQueue.ClearData(queue)
if queue == nil then
error("Queue is nil")
end
queue._queue = {}
queue._length = 0
end
--[[Example:
local testQueue = LuaQueue.New()
LuaQueue.Push(testQueue,10)
LuaQueue.Push(testQueue,20)
LuaQueue.Push(testQueue,30)
LuaQueue.Push(testQueue,40)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
print("-------------------------------------")
LuaQueue.Pop(testQueue)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
print("-------------------------------------")
LuaQueue.Pop(testQueue)
LuaQueue.Push(testQueue,909)
local data = LuaQueue.GetData(testQueue)
for _,v in pairs(data) do
print(v)
end
LuaQueue.ClearData(testQueue)
--]]
Lua设计与实现--读书笔记的更多相关文章
- Linux内核设计与实现 读书笔记 转
Linux内核设计与实现 读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...
- 【2018.08.13 C与C++基础】C++语言的设计与演化读书笔记
先占坑 老实说看这本书的时候,有很多地方都很迷糊,但却说不清楚问题到底在哪里,只能和Effective C++联系起来,更深层次的东西就想不到了. 链接: https://blog.csdn.net/ ...
- Redis设计与实现读书笔记——简单动态字符串
前言 项目里用到了redis数据结构,不想只是简单的调用api,这里对我的读书笔记做一下记录.原文地址: http://www.redisbook.com/en/latest/internal-dat ...
- Redis设计与实现读书笔记(二) 链表
链表作为最基础的数据结构,在许多高级语言上已经有了很好的实现.由于redis采用C语言编写,需要自己实现链表,于是redis在adlist.h定义了链表类型.作者对于这部分没什么好说,源码比较简单,如 ...
- Redis设计与实现读书笔记(一) SDS
作为redis最基础的底层数据结构之一,SDS提供了许多C风格字符串所不具备的功能,为之后redis内存管理提供了许多方便.它们分别是: 二进制安全 减少字符串长度获取时间复杂度 杜绝字符串溢出 减少 ...
- Redis 设计与实现读书笔记一 Redis字符串
1 Redis 是C语言实现的 2 C字符串是 /0 结束的字符数组 3 Redis具体的动态字符串实现 /* * 保存字符串对象的结构 */ struct sdshdr { // buf 中已占用空 ...
- 《点石成金-访客至上的web和移动可用性设计秘籍》读书笔记
简介 作者Steve Krug,惯例先去了解一下本书的作者,发现书中介绍的并不多,百度一下后发现这本书比作者出名.好吧,百度就是这样子,作者自称web可用性咨询师,手上这本书是第三版再版,第一版2 ...
- Linux内核设计与实现 读书笔记
第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...
- 《About Face 3:交互设计精髓》读书笔记(一)
第一章 目标导向设计 当今数字产品的创造过程 市场营销人员对于产品设计过程的贡献,通常局限于需求列表这些需求同用户的实际需要与期望无关,主要在于追赶竞争对手,按照任务清单管理IT资源,以及基于市场调查 ...
随机推荐
- MySQL 索引结构
谈到 MYSQL 索引服务端的同学应该是熟悉的不能再熟悉,新建表的时候怎么着都知道先来个主键索引,对于经常查询的列也会加个索引加快查询速度.那么 MYSQL 索引都有哪些类型呢?索引结构是什么样的呢? ...
- virtualenv最佳实战
一 系统环境 windows 10 64-bit 安装python 2.7.18 和python 3.8两个版本 二 安装 默认会把virtualenv安装到系统默认python版本中 pip ins ...
- python练习 英文字符的鲁棒输入+数字的鲁棒输入
鲁棒 = Robust 健壮 英文字符的鲁棒输入 描述 获得用户的任何可能输入,将其中的英文字符进行打印输出,程序不出现错误. ...
- ract-native常用命令
1.新建项目:react-native init AwesomeProject 2.运动项目 cd AwesomeProject react-native run-ios 3.添加第三方插件: yar ...
- Python之根据四个坐标确定其位于左上下右上下
1.导入模块 import numpy as np 2.存储所需要确定位置的四个坐标点 # 所需要确定位置的四个坐标 coordinate = [[2570, 1948], [2391, 1919], ...
- HashMap源码解析、jdk7和8之后的区别、相关问题分析(多线程扩容带来的死循环)
一.概览 HashMap<String, Integer> map = new HashMap<>(); 这个语句执行起来,在 jdk1.8 之前,会创建一个长度是 16 的 ...
- Spring JPA 拓展
Spring JPA 拓展 翻译:Spring Data Extensions 本节记录了一组Spring数据扩展,它们支持在各种上下文中使用Spring数据.目前,大部分集成都是针对Spring M ...
- GET请求和POST请求的request和response的中文乱码问题
GET请求(request)中文乱码解决方案: 在Services的server.xml的配置文件的第一个Connector标签中添加属性URIEncoding="UTF-8" P ...
- stackoverflow的ret2syscall利用
ret2syscall 系统调用 ret2syscall,即控制程序执行系统调用,获取shell.Linux将内核功能接口制作为系统调用(system call),可在程序中直接调用.程序中存在int ...
- JS的全局变量无法给Ajax里的变量赋值
前阶段遇到这么一个问题,在JS定义一个全局变量,JS方法里的其他地方都能使用,偏偏ajax里无法赋值,也不是无法赋值,但赋值总是慢一拍,具体的解决方案如下图所示: