aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/go/_std_1.22/src/internal/zstd/window.go
blob: f9c5f04c3ae221b37580f708386367fe5e0fd340 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
// 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) {
	w.data = w.data[:0]
	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]...)
	}
}