| // Copyright 2023 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package zstd |
| |
| // window stores up to size bytes of data. |
| // It is implemented as a circular buffer: |
| // sequential save calls append to the data slice until |
| // its length reaches configured size and after that, |
| // save calls overwrite previously saved data at off |
| // and update off such that it always points at |
| // the byte stored before others. |
| type window struct { |
| size int |
| data []byte |
| off int |
| } |
| |
| // reset clears stored data and configures window size. |
| func (w *window) reset(size int) { |
| b := w.data[:0] |
| if cap(b) < size { |
| b = make([]byte, 0, size) |
| } |
| w.data = b |
| w.off = 0 |
| w.size = size |
| } |
| |
| // len returns the number of stored bytes. |
| func (w *window) len() uint32 { |
| return uint32(len(w.data)) |
| } |
| |
| // save stores up to size last bytes from the buf. |
| func (w *window) save(buf []byte) { |
| if w.size == 0 { |
| return |
| } |
| if len(buf) == 0 { |
| return |
| } |
| |
| if len(buf) >= w.size { |
| from := len(buf) - w.size |
| w.data = append(w.data[:0], buf[from:]...) |
| w.off = 0 |
| return |
| } |
| |
| // Update off to point to the oldest remaining byte. |
| free := w.size - len(w.data) |
| if free == 0 { |
| n := copy(w.data[w.off:], buf) |
| if n == len(buf) { |
| w.off += n |
| } else { |
| w.off = copy(w.data, buf[n:]) |
| } |
| } else { |
| if free >= len(buf) { |
| w.data = append(w.data, buf...) |
| } else { |
| w.data = append(w.data, buf[:free]...) |
| w.off = copy(w.data, buf[free:]) |
| } |
| } |
| } |
| |
| // appendTo appends stored bytes between from and to indices to the buf. |
| // Index from must be less or equal to index to and to must be less or equal to w.len(). |
| func (w *window) appendTo(buf []byte, from, to uint32) []byte { |
| dataLen := uint32(len(w.data)) |
| from += uint32(w.off) |
| to += uint32(w.off) |
| |
| wrap := false |
| if from > dataLen { |
| from -= dataLen |
| wrap = !wrap |
| } |
| if to > dataLen { |
| to -= dataLen |
| wrap = !wrap |
| } |
| |
| if wrap { |
| buf = append(buf, w.data[from:]...) |
| return append(buf, w.data[:to]...) |
| } else { |
| return append(buf, w.data[from:to]...) |
| } |
| } |