Source
pub fn update(self: *XxHash3, input: anytype) void {
self.total_len += input.len;
std.debug.assert(self.buffered <= self.buffer.len);
// Copy the input into the buffer if we haven't filled it up yet.
const remaining = self.buffer.len - self.buffered;
if (input.len <= remaining) {
@memcpy(self.buffer[self.buffered..][0..input.len], input);
self.buffered += input.len;
return;
}
// Input will overflow the buffer. Fill up the buffer with some input and consume it.
var consumable: []const u8 = input;
if (self.buffered > 0) {
@memcpy(self.buffer[self.buffered..], consumable[0..remaining]);
consumable = consumable[remaining..];
self.accumulator.consume(std.mem.bytesAsSlice(Block, &self.buffer));
self.buffered = 0;
}
// The input isn't small enough to fit in the buffer. Consume it directly.
if (consumable.len > self.buffer.len) {
const block_count = ((consumable.len - 1) / @sizeOf(Block)) * @sizeOf(Block);
self.accumulator.consume(std.mem.bytesAsSlice(Block, consumable[0..block_count]));
consumable = consumable[block_count..];
// In case we consume all remaining input, write the last block to end of the buffer
// to populate the last_block_copy in final() similar to hashLong()'s last_block.
@memcpy(
self.buffer[self.buffer.len - @sizeOf(Block) .. self.buffer.len],
(consumable.ptr - @sizeOf(Block))[0..@sizeOf(Block)],
);
}
// Copy in any remaining input into the buffer.
std.debug.assert(consumable.len <= self.buffer.len);
@memcpy(self.buffer[0..consumable.len], consumable);
self.buffered = consumable.len;
}