From c82fd96c95f3540f57410909fcafec7d267896b1 Mon Sep 17 00:00:00 2001 From: Ryan Oldenburg Date: Sat, 14 Nov 2020 13:43:14 -0600 Subject: [PATCH] 0.3.4, inflate faster --- README.md | 8 +++---- src/zippy/inflate.nim | 52 ++++++++++++++++++++++++++++--------------- zippy.nimble | 2 +- 3 files changed, 39 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 933523c..6aa4a78 100644 --- a/README.md +++ b/README.md @@ -133,12 +133,12 @@ Each file is uncompressed 1000 times: **https://github.com/guzba/zippy** results: File | Time --- | ---: -alice29.txt | 0.9395s -urls.10K | 3.9862s -rfctest3.gold | 0.2052s +alice29.txt | 0.7797s +urls.10K | 3.5913s +rfctest3.gold | 0.1774s randtest3.gold | 0.0373s paper-100k.pdf | 0.6453s -geo.protodata | 0.2535s +geo.protodata | 0.2516s https://github.com/nim-lang/zip results: (Requires zlib1.dll) File | Time diff --git a/src/zippy/inflate.nim b/src/zippy/inflate.nim index 235428e..c839ef7 100644 --- a/src/zippy/inflate.nim +++ b/src/zippy/inflate.nim @@ -186,14 +186,14 @@ func inflateBlock(b: var BitStream, dst: var seq[uint8], fixedCodes: bool) = literalHuffman = initHuffman(unpacked[0 ..< hlit], maxLitLenCodes) distanceHuffman = initHuffman(unpacked[hlit ..< unpacked.len], maxDistCodes) - var pos = dst.len + var op = dst.len while true: let symbol = decodeSymbol(b, literalHuffman) if symbol <= 255: - if pos >= dst.len: - dst.setLen((pos + 1) * 2) - dst[pos] = symbol.uint8 - inc pos + if op >= dst.len: + dst.setLen((op + 1) * 2) + dst[op] = symbol.uint8 + inc op elif symbol == 256: break else: @@ -218,22 +218,38 @@ func inflateBlock(b: var BitStream, dst: var seq[uint8], fixedCodes: bool) = b.readBits(baseDistanceExtraBits[distIndex]) ).int - if totalDist > pos: + if totalDist > op: failUncompress() - if pos + totalLength > dst.len: - dst.setLen((pos + totalLength) * 2) - - var remaining = totalLength - while totalDist >= 8 and remaining >= 8: - copy64(dst, dst, pos, pos - totalDist) - inc(pos, 8) - dec(remaining, 8) - for i in 0 ..< remaining: - dst[pos + i] = dst[pos - totalDist + i] - inc(pos, remaining) + # Min match is 3 so leave room to overwrite by 13 + if op + totalLength + 13 > dst.len: + dst.setLen((op + totalLength) * 2 + 10) + + if totalLength <= 16 and totalDist >= 8 and dst.len > op + 16: + copy64(dst, dst, op, op - totalDist) + copy64(dst, dst, op + 8, op - totalDist + 8) + inc(op, totalLength) + elif dst.len - op >= totalLength + 10: + var + src = op - totalDist + pos = op + remaining = totalLength + while pos - src < 8: + copy64(dst, dst, pos, src) + dec(remaining, pos - src) + inc(pos, pos - src) + while remaining > 0: + copy64(dst, dst, pos, src) + inc(src, 8) + inc(pos, 8) + dec(remaining, 8) + inc(op, totalLength) + else: + for i in op ..< op + totalLength: + dst[op] = dst[op - totalDist] + inc op - dst.setLen(pos) + dst.setLen(op) func inflateNoCompression(b: var BitStream, dst: var seq[uint8]) = b.skipRemainingBitsInCurrentByte() diff --git a/zippy.nimble b/zippy.nimble index 002c74a..122215b 100644 --- a/zippy.nimble +++ b/zippy.nimble @@ -1,5 +1,5 @@ packageName = "zippy" -version = "0.3.3" +version = "0.3.4" author = "Ryan Oldenburg" description = "In-progress pure Nim implementation of deflate and zlib." license = "MIT"