-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbufreaderat.go
91 lines (75 loc) · 1.86 KB
/
bufreaderat.go
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
91
// Package bufreaderat implements buffered io.ReaderAt. It wraps io.ReaderAt, by creating a wrapper object
// that also implement io.Reader but provide buffering.
package bufreaderat
import (
"io"
)
const (
DEFAULT_BUFFER_SIZE = 1024
)
// BufReaderAt a wrapper for io.ReaderAt, to provide buffering.
type BufReaderAt struct {
readerAt io.ReaderAt
buf []byte
offset int64
len int64
err error
}
// Default retrusn a new BufReaderAt with the default buffer size.
func Default(r io.ReaderAt) *BufReaderAt {
return &BufReaderAt{
readerAt: r,
buf: make([]byte, DEFAULT_BUFFER_SIZE),
offset: 0,
len: 0,
}
}
// New returns a new BufReaderAt with buffer of specific size.
func New(r io.ReaderAt, size int) *BufReaderAt {
return &BufReaderAt{
readerAt: r,
buf: make([]byte, size),
offset: 0,
len: 0,
}
}
func (r *BufReaderAt) bufEnd() int64 {
return r.offset + r.len
}
// bufOffset returns the offset relative to r.offset (offset of the buffer from the start of the file)
func (r *BufReaderAt) bufOffset(offset int64) int64 {
return offset - r.offset
}
func (r *BufReaderAt) bufCap() int64 {
return int64(cap(r.buf))
}
// ReadAt implements buffered io.ReadAt
func (r *BufReaderAt) ReadAt(p []byte, offset int64) (n int, er error) {
pn := int64(len(p))
// read from buffer
if offset >= r.offset && pn <= r.len {
n = copy(p, r.buf[r.bufOffset(offset):r.len])
return n, r.err
}
// read directly into p
if pn > r.bufCap() {
n, r.err = r.readerAt.ReadAt(p, offset)
return n, r.err
}
n, r.err = r.readerAt.ReadAt(r.buf, offset)
var read int64
if n > 0 {
r.offset = offset
r.len = int64(n)
if pn > r.len {
read = r.len - r.bufOffset(offset)
} else {
read = pn
}
copy(p, r.buf[r.bufOffset(offset):r.len])
}
if r.err == io.EOF && offset+pn < r.bufEnd() {
r.err = nil
}
return int(read), r.err
}