1
1
const std = @import ("std" );
2
- const Allocator = std .mem .Allocator ;
3
2
const RingBuffer = std .RingBuffer ;
4
3
5
4
const types = @import ("zstandard/types.zig" );
@@ -10,7 +9,9 @@ pub const decompress = @import("zstandard/decompress.zig");
10
9
11
10
pub const DecompressStreamOptions = struct {
12
11
verify_checksum : bool = true ,
13
- window_size_max : usize = 1 << 23 , // 8MiB default maximum window size
12
+ window_size_max : usize = default_window_size_max ,
13
+
14
+ pub const default_window_size_max = 1 << 23 ; // 8MiB default maximum window size
14
15
};
15
16
16
17
pub fn DecompressStream (
@@ -20,20 +21,29 @@ pub fn DecompressStream(
20
21
return struct {
21
22
const Self = @This ();
22
23
23
- allocator : Allocator ,
24
+ pub const window_size_max = options .window_size_max ;
25
+
26
+ const table_size_max = types .compressed_block .table_size_max ;
27
+
24
28
source : std .io .CountingReader (ReaderType ),
25
29
state : enum { NewFrame , InFrame , LastBlock },
26
30
decode_state : decompress.block.DecodeState ,
27
31
frame_context : decompress.FrameContext ,
28
- buffer : RingBuffer ,
29
- literal_fse_buffer : []types.compressed_block.Table.Fse ,
30
- match_fse_buffer : []types.compressed_block.Table.Fse ,
31
- offset_fse_buffer : []types.compressed_block.Table.Fse ,
32
- literals_buffer : []u8 ,
33
- sequence_buffer : []u8 ,
32
+ buffer : WindowBuffer ,
33
+ literal_fse_buffer : [table_size_max . literal ]types.compressed_block.Table.Fse ,
34
+ match_fse_buffer : [table_size_max . match ]types.compressed_block.Table.Fse ,
35
+ offset_fse_buffer : [table_size_max . offset ]types.compressed_block.Table.Fse ,
36
+ literals_buffer : [types . block_size_max ]u8 ,
37
+ sequence_buffer : [types . block_size_max ]u8 ,
34
38
checksum : if (options .verify_checksum ) ? u32 else void ,
35
39
current_frame_decompressed_size : usize ,
36
40
41
+ const WindowBuffer = struct {
42
+ data : * [options .window_size_max ]u8 = undefined ,
43
+ read_index : usize = 0 ,
44
+ write_index : usize = 0 ,
45
+ };
46
+
37
47
pub const Error = ReaderType .Error || error {
38
48
ChecksumFailure ,
39
49
DictionaryIdFlagUnsupported ,
@@ -44,14 +54,13 @@ pub fn DecompressStream(
44
54
45
55
pub const Reader = std .io .Reader (* Self , Error , read );
46
56
47
- pub fn init (allocator : Allocator , source : ReaderType ) Self {
57
+ pub fn init (source : ReaderType , window_buffer : * [ options . window_size_max ] u8 ) Self {
48
58
return Self {
49
- .allocator = allocator ,
50
59
.source = std .io .countingReader (source ),
51
60
.state = .NewFrame ,
52
61
.decode_state = undefined ,
53
62
.frame_context = undefined ,
54
- .buffer = undefined ,
63
+ .buffer = .{ . data = window_buffer } ,
55
64
.literal_fse_buffer = undefined ,
56
65
.match_fse_buffer = undefined ,
57
66
.offset_fse_buffer = undefined ,
@@ -76,44 +85,11 @@ pub fn DecompressStream(
76
85
options .verify_checksum ,
77
86
);
78
87
79
- const literal_fse_buffer = try self .allocator .alloc (
80
- types .compressed_block .Table .Fse ,
81
- types .compressed_block .table_size_max .literal ,
82
- );
83
- errdefer self .allocator .free (literal_fse_buffer );
84
-
85
- const match_fse_buffer = try self .allocator .alloc (
86
- types .compressed_block .Table .Fse ,
87
- types .compressed_block .table_size_max .match ,
88
- );
89
- errdefer self .allocator .free (match_fse_buffer );
90
-
91
- const offset_fse_buffer = try self .allocator .alloc (
92
- types .compressed_block .Table .Fse ,
93
- types .compressed_block .table_size_max .offset ,
94
- );
95
- errdefer self .allocator .free (offset_fse_buffer );
96
-
97
88
const decode_state = decompress .block .DecodeState .init (
98
- literal_fse_buffer ,
99
- match_fse_buffer ,
100
- offset_fse_buffer ,
89
+ & self . literal_fse_buffer ,
90
+ & self . match_fse_buffer ,
91
+ & self . offset_fse_buffer ,
101
92
);
102
- const buffer = try RingBuffer .init (self .allocator , frame_context .window_size );
103
-
104
- const literals_data = try self .allocator .alloc (u8 , frame_context .block_size_max );
105
- errdefer self .allocator .free (literals_data );
106
-
107
- const sequence_data = try self .allocator .alloc (u8 , frame_context .block_size_max );
108
- errdefer self .allocator .free (sequence_data );
109
-
110
- self .literal_fse_buffer = literal_fse_buffer ;
111
- self .match_fse_buffer = match_fse_buffer ;
112
- self .offset_fse_buffer = offset_fse_buffer ;
113
- self .literals_buffer = literals_data ;
114
- self .sequence_buffer = sequence_data ;
115
-
116
- self .buffer = buffer ;
117
93
118
94
self .decode_state = decode_state ;
119
95
self .frame_context = frame_context ;
@@ -126,16 +102,6 @@ pub fn DecompressStream(
126
102
}
127
103
}
128
104
129
- pub fn deinit (self : * Self ) void {
130
- if (self .state == .NewFrame ) return ;
131
- self .allocator .free (self .decode_state .literal_fse_buffer );
132
- self .allocator .free (self .decode_state .match_fse_buffer );
133
- self .allocator .free (self .decode_state .offset_fse_buffer );
134
- self .allocator .free (self .literals_buffer );
135
- self .allocator .free (self .sequence_buffer );
136
- self .buffer .deinit (self .allocator );
137
- }
138
-
139
105
pub fn reader (self : * Self ) Reader {
140
106
return .{ .context = self };
141
107
}
@@ -153,7 +119,6 @@ pub fn DecompressStream(
153
119
0
154
120
else
155
121
error .MalformedFrame ,
156
- error .OutOfMemory = > return error .OutOfMemory ,
157
122
else = > return error .MalformedFrame ,
158
123
};
159
124
}
@@ -165,33 +130,43 @@ pub fn DecompressStream(
165
130
fn readInner (self : * Self , buffer : []u8 ) Error ! usize {
166
131
std .debug .assert (self .state != .NewFrame );
167
132
133
+ var ring_buffer = RingBuffer {
134
+ .data = self .buffer .data ,
135
+ .read_index = self .buffer .read_index ,
136
+ .write_index = self .buffer .write_index ,
137
+ };
138
+ defer {
139
+ self .buffer .read_index = ring_buffer .read_index ;
140
+ self .buffer .write_index = ring_buffer .write_index ;
141
+ }
142
+
168
143
const source_reader = self .source .reader ();
169
- while (self . buffer .isEmpty () and self .state != .LastBlock ) {
144
+ while (ring_buffer .isEmpty () and self .state != .LastBlock ) {
170
145
const header_bytes = source_reader .readBytesNoEof (3 ) catch
171
146
return error .MalformedFrame ;
172
147
const block_header = decompress .block .decodeBlockHeader (& header_bytes );
173
148
174
149
decompress .block .decodeBlockReader (
175
- & self . buffer ,
150
+ & ring_buffer ,
176
151
source_reader ,
177
152
block_header ,
178
153
& self .decode_state ,
179
154
self .frame_context .block_size_max ,
180
- self .literals_buffer ,
181
- self .sequence_buffer ,
155
+ & self .literals_buffer ,
156
+ & self .sequence_buffer ,
182
157
) catch
183
158
return error .MalformedBlock ;
184
159
185
160
if (self .frame_context .content_size ) | size | {
186
161
if (self .current_frame_decompressed_size > size ) return error .MalformedFrame ;
187
162
}
188
163
189
- const size = self . buffer .len ();
164
+ const size = ring_buffer .len ();
190
165
self .current_frame_decompressed_size += size ;
191
166
192
167
if (self .frame_context .hasher_opt ) | * hasher | {
193
168
if (size > 0 ) {
194
- const written_slice = self . buffer .sliceLast (size );
169
+ const written_slice = ring_buffer .sliceLast (size );
195
170
hasher .update (written_slice .first );
196
171
hasher .update (written_slice .second );
197
172
}
@@ -216,43 +191,37 @@ pub fn DecompressStream(
216
191
}
217
192
}
218
193
219
- const size = @min (self . buffer .len (), buffer .len );
194
+ const size = @min (ring_buffer .len (), buffer .len );
220
195
if (size > 0 ) {
221
- self . buffer .readFirstAssumeLength (buffer , size );
196
+ ring_buffer .readFirstAssumeLength (buffer , size );
222
197
}
223
- if (self .state == .LastBlock and self . buffer .len () == 0 ) {
198
+ if (self .state == .LastBlock and ring_buffer .len () == 0 ) {
224
199
self .state = .NewFrame ;
225
- self .allocator .free (self .literal_fse_buffer );
226
- self .allocator .free (self .match_fse_buffer );
227
- self .allocator .free (self .offset_fse_buffer );
228
- self .allocator .free (self .literals_buffer );
229
- self .allocator .free (self .sequence_buffer );
230
- self .buffer .deinit (self .allocator );
231
200
}
232
201
return size ;
233
202
}
234
203
};
235
204
}
236
205
237
206
pub fn decompressStreamOptions (
238
- allocator : Allocator ,
239
207
reader : anytype ,
240
208
comptime options : DecompressStreamOptions ,
209
+ window_buffer : * [options .window_size_max ]u8 ,
241
210
) DecompressStream (@TypeOf (reader ), options ) {
242
- return DecompressStream (@TypeOf (reader ), options ).init (allocator , reader );
211
+ return DecompressStream (@TypeOf (reader ), options ).init (reader , window_buffer );
243
212
}
244
213
245
214
pub fn decompressStream (
246
- allocator : Allocator ,
247
215
reader : anytype ,
216
+ window_buffer : * [DecompressStreamOptions .default_window_size_max ]u8 ,
248
217
) DecompressStream (@TypeOf (reader ), .{}) {
249
- return DecompressStream (@TypeOf (reader ), .{}).init (allocator , reader );
218
+ return DecompressStream (@TypeOf (reader ), .{}).init (reader , window_buffer );
250
219
}
251
220
252
221
fn testDecompress (data : []const u8 ) ! []u8 {
222
+ var window_buffer : [DecompressStreamOptions .default_window_size_max ]u8 = undefined ;
253
223
var in_stream = std .io .fixedBufferStream (data );
254
- var zstd_stream = decompressStream (std .testing .allocator , in_stream .reader ());
255
- defer zstd_stream .deinit ();
224
+ var zstd_stream = decompressStream (in_stream .reader (), & window_buffer );
256
225
const result = zstd_stream .reader ().readAllAlloc (std .testing .allocator , std .math .maxInt (usize ));
257
226
return result ;
258
227
}
@@ -301,9 +270,9 @@ fn expectEqualDecoded(expected: []const u8, input: []const u8) !void {
301
270
}
302
271
303
272
{
273
+ var window_buffer : [DecompressStreamOptions .default_window_size_max ]u8 = undefined ;
304
274
var in_stream = std .io .fixedBufferStream (input );
305
- var stream = decompressStream (allocator , in_stream .reader ());
306
- defer stream .deinit ();
275
+ var stream = decompressStream (in_stream .reader (), & window_buffer );
307
276
308
277
const result = try stream .reader ().readAllAlloc (allocator , std .math .maxInt (usize ));
309
278
defer allocator .free (result );
0 commit comments