Skip to content

Commit acab4f7

Browse files
authored
Fix LZSS length base (#3291)
1 parent ea592e3 commit acab4f7

File tree

8 files changed

+41
-25
lines changed

8 files changed

+41
-25
lines changed

cmd/decode/src/main.scm

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@
6262
(decompressor-push! decompressor y)
6363
y)
6464
(begin
65-
(decompressor-set-length! decompressor y)
65+
(decompressor-set-length! decompressor (+ y 1))
6666
(decompressor-set-offset! decompressor (read-u8))
6767
(decompressor-read decompressor)))))
6868
(else

cmd/minimal/Cargo.lock

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compile.scm

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,7 +1695,7 @@
16951695

16961696
(define window-size 256)
16971697
(define minimum-match 2) ; exclusive
1698-
(define maximum-match 127) ; inclusive
1698+
(define maximum-match 128) ; inclusive
16991699

17001700
;; Compressor
17011701

@@ -1758,7 +1758,7 @@
17581758
(n (cdr match)))
17591759
(if (> n minimum-match)
17601760
(begin
1761-
(write-u8 (+ 1 (* 2 n)))
1761+
(write-u8 (+ 1 (* 2 (- n 1))))
17621762
(write-u8 (- back (car match) 1))
17631763
(compressor-pop! compressor n))
17641764
(write-u8 (* 2 (compressor-pop! compressor 1)))))))

lzss/src/compress.rs

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
1-
use crate::ring_buffer::RingBuffer;
1+
use crate::{MAX_LENGTH, ring_buffer::RingBuffer};
22

33
const MIN_LENGTH: usize = 2;
4-
/// The maximum match length.
5-
pub const MAX_LENGTH: usize = (u8::MAX / 2) as _;
64

75
/// LZSS compression iterator.
86
pub struct LzssCompressionIterator<const B: usize, I: Iterator<Item = u8>> {
@@ -83,7 +81,7 @@ impl<const B: usize, I: Iterator<Item = u8>> Iterator for LzssCompressionIterato
8381
self.ahead -= m;
8482
self.next = Some(n as _);
8583

86-
(m as u8) << 1 | 1
84+
((m - 1) << 1) as u8 | 1
8785
} else {
8886
self.next()? << 1
8987
}
@@ -180,7 +178,7 @@ mod tests {
180178
assert_eq!(
181179
LzssCompressionIterator::<BUFFER_SIZE, _>::new([42, 42, 42, 42].into_iter())
182180
.collect::<Vec<_>>(),
183-
[84, 7, 0]
181+
[84, 5, 0]
184182
);
185183
}
186184

@@ -191,7 +189,7 @@ mod tests {
191189
[42, 42, 42, 42, 7, 7, 7, 127, 127, 127, 127, 127].into_iter()
192190
)
193191
.collect::<Vec<_>>(),
194-
[84, 7, 0, 14, 14, 14, 254, 9, 0]
192+
[84, 5, 0, 14, 14, 14, 254, 7, 0]
195193
);
196194
}
197195

@@ -200,7 +198,7 @@ mod tests {
200198
assert_eq!(
201199
LzssCompressionIterator::<BUFFER_SIZE, _>::new([0, 0, 0].into_iter())
202200
.collect::<Vec<_>>(),
203-
[7, 0]
201+
[5, 0]
204202
);
205203
}
206204

@@ -233,8 +231,7 @@ mod tests {
233231
.chain(&chunk)
234232
.copied()
235233
.map(|x| x << 1)
236-
// TODO Set the length base to 0.
237-
.chain([u8::MAX, u8::MAX, 0])
234+
.chain([u8::MAX, u8::MAX])
238235
.collect::<Vec<_>>()
239236
);
240237
}

lzss/src/decompress.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ impl<const W: usize, I: Iterator<Item = u8>> Iterator for LzssDecompressionItera
3838
self.buffer.push(y);
3939
Some(y)
4040
} else {
41-
self.length = y;
41+
self.length = y + 1;
4242
self.offset = self.iterator.next()?;
4343

4444
self.next()
@@ -58,7 +58,7 @@ mod tests {
5858
#[test]
5959
fn repetition() {
6060
assert_eq!(
61-
LzssDecompressionIterator::<8, _>::new([2, 4, 6, 8, 11, 3].into_iter())
61+
LzssDecompressionIterator::<8, _>::new([2, 4, 6, 8, 9, 3].into_iter())
6262
.collect::<Vec<_>>(),
6363
[1, 2, 3, 4, 1, 2, 3, 4, 1]
6464
);
@@ -67,7 +67,7 @@ mod tests {
6767
#[test]
6868
fn repetitions() {
6969
assert_eq!(
70-
LzssDecompressionIterator::<8, _>::new([2, 4, 6, 8, 11, 3, 10, 12, 7, 1].into_iter())
70+
LzssDecompressionIterator::<8, _>::new([2, 4, 6, 8, 9, 3, 10, 12, 5, 1].into_iter())
7171
.collect::<Vec<_>>(),
7272
[1, 2, 3, 4, 1, 2, 3, 4, 1, 5, 6, 5, 6, 5]
7373
);
@@ -77,7 +77,7 @@ mod tests {
7777
fn max_length() {
7878
assert_eq!(
7979
LzssDecompressionIterator::<1, _>::new(
80-
[84, (MAX_LENGTH as u8) << 1 | 1, 0].into_iter()
80+
[84, (MAX_LENGTH - 1 << 1) as u8 | 1, 0].into_iter()
8181
)
8282
.collect::<Vec<_>>(),
8383
repeat(42).take(MAX_LENGTH + 1).collect::<Vec<_>>()

lzss/src/lib.rs

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,14 @@ mod compress;
1111
mod decompress;
1212
mod ring_buffer;
1313

14-
pub use self::compress::MAX_LENGTH;
1514
use self::{compress::LzssCompressionIterator, decompress::LzssDecompressionIterator};
1615

1716
/// The maximum window size.
1817
pub const MAX_WINDOW_SIZE: usize = 1 << 8;
1918

19+
/// The maximum match length.
20+
pub const MAX_LENGTH: usize = 1 << 7;
21+
2022
/// LZSS compression for 7-bit bytes.
2123
pub trait Lzss {
2224
/// Compresses bytes.
@@ -27,8 +29,8 @@ pub trait Lzss {
2729
}
2830

2931
impl<I: IntoIterator<Item = u8>> Lzss for I {
30-
fn compress<const W: usize>(self) -> impl Iterator<Item = u8> {
31-
LzssCompressionIterator::<W, _>::new(self.into_iter())
32+
fn compress<const B: usize>(self) -> impl Iterator<Item = u8> {
33+
LzssCompressionIterator::<B, _>::new(self.into_iter())
3234
}
3335

3436
fn decompress<const W: usize>(self) -> impl Iterator<Item = u8> {
@@ -134,7 +136,7 @@ mod tests {
134136
#[test]
135137
fn max_length() {
136138
const WINDOW_SIZE: usize = 1;
137-
let data = repeat(42).take(256).collect::<Vec<_>>();
139+
let data = repeat(42).take(MAX_LENGTH + 1).collect::<Vec<_>>();
138140

139141
assert_eq!(
140142
data.iter()
@@ -149,7 +151,7 @@ mod tests {
149151
#[test]
150152
fn max_offset() {
151153
const WINDOW_SIZE: usize = 128;
152-
let data = (0..128).chain(0..128).collect::<Vec<_>>();
154+
let data = repeat(0..128).take(2).flatten().collect::<Vec<_>>();
153155

154156
assert_eq!(
155157
data.iter()
@@ -172,4 +174,16 @@ mod tests {
172174
.collect::<Vec<_>>()
173175
== data
174176
}
177+
178+
#[quickcheck]
179+
fn random_max(data: Vec<u8>) -> bool {
180+
let data = data.into_iter().map(|x| x >> 1).collect::<Vec<_>>();
181+
182+
data.iter()
183+
.copied()
184+
.compress::<{ MAX_WINDOW_SIZE + MAX_LENGTH }>()
185+
.decompress::<MAX_WINDOW_SIZE>()
186+
.collect::<Vec<_>>()
187+
== data
188+
}
175189
}

snapshots/cmd/decode/src/main.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2293,6 +2293,8 @@
22932293
- get 0
22942294
- get 2
22952295
- get 1
2296+
- constant 1
2297+
- call 2 #f ||
22962298
- call 2 #f ||
22972299
- set 0
22982300
- get 2

snapshots/compile.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19183,7 +19183,7 @@
1918319183
- list
1918419184
- define
1918519185
- maximum-match
19186-
- 127
19186+
- 128
1918719187
- list
1918819188
- define-record-type
1918919189
- compressor
@@ -19474,7 +19474,10 @@
1947419474
- list
1947519475
- -
1947619476
- 2
19477-
- n
19477+
- list
19478+
- -
19479+
- n
19480+
- 1
1947819481
- list
1947919482
- write-u8
1948019483
- list

0 commit comments

Comments
 (0)