1 // Copyright 2023 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package zstd
6 7 // window stores up to size bytes of data.
8 // It is implemented as a circular buffer:
9 // sequential save calls append to the data slice until
10 // its length reaches configured size and after that,
11 // save calls overwrite previously saved data at off
12 // and update off such that it always points at
13 // the byte stored before others.
14 type window struct {
15 size int
16 data []byte
17 off int
18 }
19 20 // reset clears stored data and configures window size.
21 func (w *window) reset(size int) {
22 b := w.data[:0]
23 if cap(b) < size {
24 b = []byte{:0:size}
25 }
26 w.data = b
27 w.off = 0
28 w.size = size
29 }
30 31 // len returns the number of stored bytes.
32 func (w *window) len() uint32 {
33 return uint32(len(w.data))
34 }
35 36 // save stores up to size last bytes from the buf.
37 func (w *window) save(buf []byte) {
38 if w.size == 0 {
39 return
40 }
41 if len(buf) == 0 {
42 return
43 }
44 45 if len(buf) >= w.size {
46 from := len(buf) - w.size
47 w.data = append(w.data[:0], buf[from:]...)
48 w.off = 0
49 return
50 }
51 52 // Update off to point to the oldest remaining byte.
53 free := w.size - len(w.data)
54 if free == 0 {
55 n := copy(w.data[w.off:], buf)
56 if n == len(buf) {
57 w.off += n
58 } else {
59 w.off = copy(w.data, buf[n:])
60 }
61 } else {
62 if free >= len(buf) {
63 w.data = append(w.data, buf...)
64 } else {
65 w.data = append(w.data, buf[:free]...)
66 w.off = copy(w.data, buf[free:])
67 }
68 }
69 }
70 71 // appendTo appends stored bytes between from and to indices to the buf.
72 // Index from must be less or equal to index to and to must be less or equal to w.len().
73 func (w *window) appendTo(buf []byte, from, to uint32) []byte {
74 dataLen := uint32(len(w.data))
75 from += uint32(w.off)
76 to += uint32(w.off)
77 78 wrap := false
79 if from > dataLen {
80 from -= dataLen
81 wrap = !wrap
82 }
83 if to > dataLen {
84 to -= dataLen
85 wrap = !wrap
86 }
87 88 if wrap {
89 buf = append(buf, w.data[from:]...)
90 return append(buf, w.data[:to]...)
91 } else {
92 return append(buf, w.data[from:to]...)
93 }
94 }
95