Skip to content

Commit 0574d4a

Browse files
committed
Make the sliding window and output buffer blocks of 4096 bytes to avoid overhead of Lua rewriting the entire string when the sliding window shifts.
1 parent de9df00 commit 0574d4a

1 file changed

Lines changed: 56 additions & 30 deletions

File tree

arch/INFLATE.LUA

Lines changed: 56 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,25 @@ if not LIB then print("Please run unzip instead") os.exit(1) end
66
---@param z boolean Is this deflate64
77
function inflate(r, w, z)
88

9-
-- Z = size of sliding window
10-
-- b = buffer
11-
-- p = position
12-
-- bb = bit buffer
13-
-- bc = bit count
14-
local Z, b, p, bb, bc = z and 65536 or 32768, "", 1, 0, 0
9+
-- Z = size of sliding window
10+
-- b = buffer
11+
-- p = position
12+
-- bb = bit buffer
13+
-- bc = bit count
14+
-- op = output position
15+
-- kg = keep going (in a loop)
16+
-- o = list of 4096-byte strings that make up the output and sliding window
17+
-- oc = current string being built
18+
-- os = total size of all strings in 'o'
19+
-- lex = length base & extra bits (pairs of bytes)
20+
-- dix = distance extra bits (1 byte per entry)
21+
-- dib = distance base (packed 32-bit LE)
22+
local Z, b, p, bb, bc, op, kg, o, oc, os, lex, dix, dib = z and 65536 or 32768, "", 1, 0, 0, 0, 1, {}, "", 0,
23+
-- lex, dix, dib packed strings
24+
25+
"\3\0\4\0\5\0\6\0\7\0\8\0\9\0\10\0\11\1\13\1\15\1\17\1\19\2\23\2\27\2\31\2\35\3\43\3\51\3\59\3\67\4\83\4\99\4\115\4\131\5\163\5\195\5\227\5\2\0",
26+
"\0\0\0\0\1\1\2\2\3\3\4\4\5\5\6\6\7\7\8\8\9\9\10\10\11\11\12\12\13\13\14\14\15\15\16\16\17\17\18\18\19\19\20\20\21\21\22\22\23\23\24\24\25\25\26\26\27\27\28\28\29\29\30\30",
27+
"\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\7\0\0\0\9\0\0\0\13\0\0\0\17\0\0\0\25\0\0\0\33\0\0\0\49\0\0\0\65\0\0\0\97\0\0\0\129\0\0\0\193\0\0\0\1\1\0\0\129\1\0\0\1\2\0\0\1\3\0\0\1\4\0\0\1\6\0\0\1\8\0\0\1\12\0\0\1\16\0\0\1\24\0\0\1\32\0\0\1\48\0\0\1\64\0\0\1\96\0\0\1\128\0\0\1\192\0\0\1\0\1\0\1\128\1\0\1\0\2\0\1\128\2\0\1\0\4\0\1\128\4\0\1\0\8\0\1\128\8\0\1\0\16\0\1\128\16\0\1\0\32\0\1\128\32\0\1\0\64\0\1\128\64\0\1\0\128\0\1\128\128\0\1\0\0\1\1\128\0\1\1\0\0\2\1\128\0\2\1\0\0\4\1\128\0\4\1\0\0\8\1\128\0\8\1\0\0\16\1\128\0\16\1\0\0\32\1\128\0\32\1\0\0\64\1\128\0\64\1\0\0\128\1\128\0\128\1\0\0\0\192"
1528

1629
---Internal buffer refill function.
1730
---@return number Zero on error, otherwise the buffer has been filled.
@@ -50,22 +63,25 @@ function inflate(r, w, z)
5063
return v
5164
end
5265

53-
-- op = output position
54-
-- kg = keep going (in a loop)
55-
-- o = output buffer that also acts like a sliding window
56-
local op, kg, o = 0, 1, ""
57-
5866
---Appends a decoded byte to the output buffer and updates the sliding window history.
5967
---@param by number The byte value (0-255) to append.
6068
function ab(by)
6169
op = op + 1
62-
o = o .. string.char(by)
63-
if #o > Z + 4096 then -- Flush what has exceeded the sliding window
70+
oc = oc .. string.char(by)
71+
72+
if #oc >= 4096 then
73+
o[#o + 1] = oc
74+
os = os + #oc
75+
oc = ""
76+
77+
-- If window exceeds limit, write and discard the oldest chunk
78+
if os > Z then
6479

65-
-- c = cut
66-
local c = #o - Z
67-
w(o:sub(1, c))
68-
o = o:sub(c + 1)
80+
-- ot = old table of 4096 bytes that have shifted out of the sliding window
81+
local ot = table.remove(o, 1)
82+
os = os - #ot
83+
w(ot)
84+
end
6985
end
7086
end
7187

@@ -144,15 +160,6 @@ function inflate(r, w, z)
144160
error("!Huffman", 0)
145161
end
146162

147-
-- lex = length base & extra bits (pairs of bytes)
148-
-- dix = distance extra bits (1 byte per entry)
149-
-- dib = distance base (packed 32-bit LE)
150-
local lex, dix, dib =
151-
152-
"\3\0\4\0\5\0\6\0\7\0\8\0\9\0\10\0\11\1\13\1\15\1\17\1\19\2\23\2\27\2\31\2\35\3\43\3\51\3\59\3\67\4\83\4\99\4\115\4\131\5\163\5\195\5\227\5\2\0",
153-
"\0\0\0\0\1\1\2\2\3\3\4\4\5\5\6\6\7\7\8\8\9\9\10\10\11\11\12\12\13\13\14\14\15\15\16\16\17\17\18\18\19\19\20\20\21\21\22\22\23\23\24\24\25\25\26\26\27\27\28\28\29\29\30\30",
154-
"\1\0\0\0\2\0\0\0\3\0\0\0\4\0\0\0\5\0\0\0\7\0\0\0\9\0\0\0\13\0\0\0\17\0\0\0\25\0\0\0\33\0\0\0\49\0\0\0\65\0\0\0\97\0\0\0\129\0\0\0\193\0\0\0\1\1\0\0\129\1\0\0\1\2\0\0\1\3\0\0\1\4\0\0\1\6\0\0\1\8\0\0\1\12\0\0\1\16\0\0\1\24\0\0\1\32\0\0\1\48\0\0\1\64\0\0\1\96\0\0\1\128\0\0\1\192\0\0\1\0\1\0\1\128\1\0\1\0\2\0\1\128\2\0\1\0\4\0\1\128\4\0\1\0\8\0\1\128\8\0\1\0\16\0\1\128\16\0\1\0\32\0\1\128\32\0\1\0\64\0\1\128\64\0\1\0\128\0\1\128\128\0\1\0\0\1\1\128\0\1\1\0\0\2\1\128\0\2\1\0\0\4\1\128\0\4\1\0\0\8\1\128\0\8\1\0\0\16\1\128\0\16\1\0\0\32\1\128\0\32\1\0\0\64\1\128\0\64\1\0\0\128\1\128\0\128\1\0\0\0\192"
155-
156163
while kg > 0 do
157164

158165
-- f = final
@@ -274,7 +281,26 @@ function inflate(r, w, z)
274281
for _ = 1, l do
275282

276283
-- c = character
277-
local c = o:sub(#o - dv + 1, #o - dv + 1)
284+
local c
285+
286+
if dv <= #oc then -- Target is in the currently building chunk
287+
c = oc:sub(#oc - dv + 1, #oc - dv + 1)
288+
else -- Target is in one of the completed chunks
289+
290+
-- of = offset
291+
-- co = coff
292+
local of, co = os - (dv - #oc), 0
293+
for i = 1, #o do
294+
if of < co + #o[i] then
295+
296+
-- n = position
297+
local n = of - co + 1
298+
c = o[i]:sub(n, n)
299+
break
300+
end
301+
co = co + #o[i]
302+
end
303+
end
278304
ab(c:byte())
279305
end
280306
end
@@ -287,7 +313,7 @@ function inflate(r, w, z)
287313
if f == 1 then kg = 0 end
288314
end
289315

290-
if #o > 0 then -- End of file, flush remaining output to disk
291-
w(o) o = ""
292-
end
316+
-- Flush remaining data
317+
for i = 1, #o do w(o[i]) end
318+
if #oc > 0 then w(oc) end
293319
end

0 commit comments

Comments
 (0)