pub const CircularBuffer = struct buf: ArrayList(u8)Circular buffer
dict_size: usizeLength of the buffer
mem_limit: usizeBuffer memory limit
cursor: usizeCurrent position
len: usizeTotal number of bytes sent through the buffer
pub fn init(dict_size: usize, mem_limit: usize) CircularBufferpub fn get(self: CircularBuffer, index: usize) u8pub fn set(self: *CircularBuffer, gpa: Allocator, index: usize, value: u8) !voidpub fn lastOr(self: CircularBuffer, lit: u8) u8Retrieve the last byte or return a default
pub fn lastN(self: CircularBuffer, dist: usize) !u8Retrieve the n-th last byte
pub fn appendLiteral(self: *CircularBuffer, gpa: Allocator, lit: u8, writer: *Writer) !voidAppend a literal
pub fn appendLz(self: *CircularBuffer, gpa: Allocator, len: usize, dist: usize, writer: *Writer) !voidFetch an LZ sequence (length, distance) from inside the buffer
pub fn finish(self: *CircularBuffer, writer: *Writer) !voidpub fn deinit(self: *CircularBuffer, gpa: Allocator) void338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446 pub const CircularBuffer = struct {
/// Circular buffer
buf: ArrayList(u8),
/// Length of the buffer
dict_size: usize,
/// Buffer memory limit
mem_limit: usize,
/// Current position
cursor: usize,
/// Total number of bytes sent through the buffer
len: usize,
pub fn init(dict_size: usize, mem_limit: usize) CircularBuffer {
return .{
.buf = .empty,
.dict_size = dict_size,
.mem_limit = mem_limit,
.cursor = 0,
.len = 0,
};
}
pub fn get(self: CircularBuffer, index: usize) u8 {
return if (0 <= index and index < self.buf.items.len) self.buf.items[index] else 0;
}
pub fn set(self: *CircularBuffer, gpa: Allocator, index: usize, value: u8) !void {
if (index >= self.mem_limit) {
return error.CorruptInput;
}
try self.buf.ensureTotalCapacity(gpa, index + 1);
while (self.buf.items.len < index) {
self.buf.appendAssumeCapacity(0);
}
self.buf.appendAssumeCapacity(value);
}
/// Retrieve the last byte or return a default
pub fn lastOr(self: CircularBuffer, lit: u8) u8 {
return if (self.len == 0)
lit
else
self.get((self.dict_size + self.cursor - 1) % self.dict_size);
}
/// Retrieve the n-th last byte
pub fn lastN(self: CircularBuffer, dist: usize) !u8 {
if (dist > self.dict_size or dist > self.len) {
return error.CorruptInput;
}
const offset = (self.dict_size + self.cursor - dist) % self.dict_size;
return self.get(offset);
}
/// Append a literal
pub fn appendLiteral(
self: *CircularBuffer,
gpa: Allocator,
lit: u8,
writer: *Writer,
) !void {
try self.set(gpa, self.cursor, lit);
self.cursor += 1;
self.len += 1;
// Flush the circular buffer to the output
if (self.cursor == self.dict_size) {
try writer.writeAll(self.buf.items);
self.cursor = 0;
}
}
/// Fetch an LZ sequence (length, distance) from inside the buffer
pub fn appendLz(
self: *CircularBuffer,
gpa: Allocator,
len: usize,
dist: usize,
writer: *Writer,
) !void {
if (dist > self.dict_size or dist > self.len) {
return error.CorruptInput;
}
var offset = (self.dict_size + self.cursor - dist) % self.dict_size;
var i: usize = 0;
while (i < len) : (i += 1) {
const x = self.get(offset);
try self.appendLiteral(gpa, x, writer);
offset += 1;
if (offset == self.dict_size) {
offset = 0;
}
}
}
pub fn finish(self: *CircularBuffer, writer: *Writer) !void {
if (self.cursor > 0) {
try writer.writeAll(self.buf.items[0..self.cursor]);
self.cursor = 0;
}
}
pub fn deinit(self: *CircularBuffer, gpa: Allocator) void {
self.buf.deinit(gpa);
self.* = undefined;
}
}
A circular buffer for LZ sequences