Skip to content

Commit

Permalink
a little better
Browse files Browse the repository at this point in the history
  • Loading branch information
guzba committed Nov 11, 2020
1 parent 18a9fdd commit eed792b
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 32 deletions.
5 changes: 1 addition & 4 deletions src/zippy/bitstreams.nim
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,7 @@ func addBits*(b: var BitStream, value: uint16, bits: int) =
bitsLeftInByte = 8 - b.bitPos
bitsAdded = min(bitsLeftInByte, bitsRemaining) # Can be 0 which is fine
bitsToAdd = (value shr (bits - bitsRemaining)) shl b.bitPos
when nimvm:
b.data[b.bytePos] = b.data[b.bytePos] or (bitsToAdd and 255).uint8
else:
b.data[b.bytePos] = b.data[b.bytePos] or bitsToAdd.uint8
b.data[b.bytePos] = b.data[b.bytePos] or (bitsToAdd and 255).uint8
dec(bitsRemaining, bitsAdded)
b.movePos(bitsAdded)

Expand Down
4 changes: 2 additions & 2 deletions src/zippy/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -96,9 +96,9 @@ const
var
table: array[256, uint32]
c: uint32
for i in 0.uint8 .. high(uint8):
for i in 0.uint32 ..< table.len.uint32:
c = i
for j in 0.uint8 ..< 8.uint8:
for j in 0 ..< 8:
if (c and 1) > 0:
c = 0xedb88320.uint32 xor (c shr 1)
else:
Expand Down
37 changes: 21 additions & 16 deletions src/zippy/deflate.nim
Original file line number Diff line number Diff line change
Expand Up @@ -275,29 +275,34 @@ func lz77Encode(src: seq[uint8]): (seq[uint16], seq[int], seq[int], int) =

prevOffset = offset

var matchLen: int
when nimvm:
for i in 0 ..< stop - pos:
if src[pos - offset + i] != src[pos + i]:
break
inc matchLen
else:
var i: int
while i < stop - pos:
let
bytesToCheck = min(8, stop - pos - i)
v = read64(src[pos - offset + i].unsafeAddr) xor
var
matchLen: int
i: int
while i < stop - pos:
var useFastPath: bool
when nimvm:
useFastPath = false
else:
# Can we look at the next 8 bytes?
useFastPath = stop - pos - i > 8
if useFastPath:
let v = read64(src[pos - offset + i].unsafeAddr) xor
read64(src[pos + i].unsafeAddr)
if v == 0:
inc(matchLen, bytesToCheck)
inc(matchLen, 8)
else:
let
zeroBits = countTrailingZeroBits(v)
matchingBytes = min(zeroBits shr 3, bytesToCheck)
matchingBytes = min(zeroBits shr 3, 8)
inc(matchLen, matchingBytes)
if matchingBytes < bytesToCheck:
if matchingBytes < 8:
break
inc(i, bytesToCheck)
inc(i, 8)
else:
if src[pos - offset + i] != src[pos + i]:
break
inc matchLen
inc i

if matchLen > longestMatchLen:
longestMatchLen = matchLen
Expand Down
12 changes: 7 additions & 5 deletions src/zippy/inflate.nim
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,12 @@ const
huffmanNumChunks = 1 shl huffmanChunkBits
huffmanCountMask = 15
huffmanValueShift = 4
huffmanMaxLinks = 1 shl (maxCodeLength - huffmanChunkBits)

type
Huffman = object
minCodeLength, maxCodeLength: uint8
chunks: array[huffmanNumChunks, uint16]
links: array[huffmanMaxLinks, array[huffmanMaxLinks, uint16]]
links: seq[seq[uint16]]
linkMask: uint16

when defined(release):
Expand Down Expand Up @@ -62,6 +61,7 @@ func initHuffman(lengths: seq[uint8], maxCodes: int): Huffman =
result.linkMask = numLinks - 1

let link = nextCode[huffmanChunkBits + 1] shr 1
result.links.setLen(huffmanNumChunks - link)
for i in link ..< huffmanNumChunks:
let
reverse = reverseUint16(i.uint16, huffmanChunkBits)
Expand All @@ -72,6 +72,7 @@ func initHuffman(lengths: seq[uint8], maxCodes: int): Huffman =
result.chunks[reverse] = (
(offset shl huffmanValueShift) or huffmanChunkBits + 1
).uint16
result.links[offset].setLen(numLinks)

for i, n in lengths:
if n == 0:
Expand Down Expand Up @@ -125,19 +126,20 @@ func decodeSymbol(b: var BitStream, h: Huffman): uint16 {.inline.} =
b.checkBytePos()

var
n = h.minCodeLength.int
bits = b.data[b.bytePos].uint16 shr b.bitPos
numBits = 8 - b.bitPos
bytePos = b.bytePos + 1
chunk = h.chunks[bits and (huffmanNumChunks - 1)]
n = (chunk and huffmanCountMask).int
while true:
if numBits < n:
if bytePos >= b.data.len:
failEndOfBuffer()
bits = bits or (b.data[bytePos].uint16 shl numBits)
inc bytePos
numBits += 8
var chunk = h.chunks[bits and (huffmanNumChunks - 1)]
n = (chunk and huffmanCountMask).int
chunk = h.chunks[bits and (huffmanNumChunks - 1)]
n = (chunk and huffmanCountMask).int
if n > huffmanChunkBits:
chunk = h.links[chunk shr huffmanValueShift][(bits shr huffmanChunkBits) and h.linkMask]
n = (chunk and huffmanCountMask).int
Expand Down
11 changes: 6 additions & 5 deletions tests/random_compress.nim
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import random, zippy

randomize()
import random, zippy, times

# Generate random blobs of data containing runs of random lengths. Ensure
# we can always compress this blob and that uncompressing the compressed
# data matches the original blob.

let seed = epochTime().int
var r = initRand(seed)

for i in 0 ..< 10000:
echo i
echo "Test ", i, " (seed ", seed, ")"

var
data: seq[uint8]
length = rand(100000)
length = r.rand(100000)
i: int
data.setLen(length)
while i < length:
Expand Down

0 comments on commit eed792b

Please sign in to comment.