Compression 本机Lua中的高效可变字节数组

Compression 本机Lua中的高效可变字节数组,compression,lua,Compression,Lua,我正在尝试在本机Lua中高效地实现LZ77解码器(即没有C库,也不依赖于非核心Lua库)-请参阅 对于加载和解析二进制文件,Lua字符串可以完美地工作,并且具有良好的性能(例如,使用s:byte(k)方法)。然而,对于创建解码的输出数据,字符串并不是非常理想的,因为它们是不可变的,并且当输出变大时,字符串串联往往会花费很多时间 解码器必须能够: 每次向输出追加一个字节(最多数百万次) 从输出缓冲区读取(或多或少的随机访问) 最好的选择是什么?输出数据的大小是事先知道的,因此可以预先分配。避免

我正在尝试在本机Lua中高效地实现LZ77解码器(即没有C库,也不依赖于非核心Lua库)-请参阅

对于加载和解析二进制文件,Lua字符串可以完美地工作,并且具有良好的性能(例如,使用s:byte(k)方法)。然而,对于创建解码的输出数据,字符串并不是非常理想的,因为它们是不可变的,并且当输出变大时,字符串串联往往会花费很多时间

解码器必须能够:

  • 每次向输出追加一个字节(最多数百万次)
  • 从输出缓冲区读取(或多或少的随机访问)

最好的选择是什么?输出数据的大小是事先知道的,因此可以预先分配。

避免字符串串联:将输出字符串保存到表中,并在末尾写入其中的所有字符串。如果您担心桌子太大,请定期冲洗。
参见听起来是
表格的完美工作。concat
您的输出只是一个字节表

当您需要复制时,您可以像通常那样复制表格。 例如:


最后处理完输出流后,将其转换为带有
str=table.concat(output)

的字符串。不幸的是,这并不能解决对缓冲区进行随机访问的问题。必须支持的一个操作是(例如):“从输出缓冲区的5个字节开始选取9个字节,然后将其附加到输出缓冲区中”(是的,副本可以重叠!)。@marcus256在这种情况下,@lhf建议的方法仍然有效。您只需要对一些函数进行修改,以在字符串表上抽象这些操作。也许您应该在每次需要发生重叠读/写时将表“刷新”为单个字符串,或者这会再次降低性能吗?我想这会降低性能(这是经常发生的)。我目前正在考虑@daurnimator建议的字符串表和字节表的混合:使用一个“顶部”字节表,直到它填满,比如说1024字节,然后将其转换为字符串并附加到字符串表,其中每个字符串正好是1024字节,便于索引。出于好奇,为什么不能使用C库?这是一个教育性的练习还是在沙盒Lua环境中需要的?它更像是一个教育性的练习(我想看看性能,以及低级编译语言和托管脚本环境之间的技术差异)。另外,我认为拥有一个纯Lua实现将使部署更加容易。这是一个完美的问题。顺便说一句,我不是唯一一个有相同想法的人。大桌子的性能损失是什么?我想它实际上是一个数字表(即双倍),因此值的大小应该是8:1,然后是表索引开销。-我将测试它。另外,预分配输出表(因为大小已知)会给我带来什么好处吗?出于好奇:table.concat的效率有多高?比如说,我有1000000个表元素-进行某种递归连接(1+1、1+1、1+1、.100+100、100+100等)有什么意义,这样你就不会最终进行99997+119999 8+1等了?很有效!(速度:3Mb/s,而C版本为300Mb/s,OK)我还通过在一个单独的变量中跟踪输出长度,而不是执行#输出(这对于表来说是一个代价高昂的操作),获得了速度提升。不确定内存消耗,但我认为:问题解决。表。它实际上是在lua中可以实现的最有效的连接。将#输出保存在另一个变量中也是一种很好的做法(尽管这可能会使事情稍微不可读)
for i=#output-5,9 do output[#output+1]=output[i] end