This repository has been archived by the owner on Jul 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathchunked_writer.go
127 lines (113 loc) · 2.82 KB
/
chunked_writer.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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// Copyright 2012, Google Inc. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// Package bytes2 provides alternate implementations of functionality similar
// to go's bytes package.
package bson
import (
"fmt"
"io"
"unicode/utf8"
)
// ChunkedWriter has the same interface as bytes.Buffer's write functions.
// It additionally provides a Reserve function that returns a []byte that
// the caller can directly change.
type ChunkedWriter struct {
bufs [][]byte
}
func NewChunkedWriter(chunkSize int) *ChunkedWriter {
cw := &ChunkedWriter{make([][]byte, 1)}
cw.bufs[0] = make([]byte, 0, chunkSize)
return cw
}
// Bytes This function can get expensive for large buffers.
func (cw *ChunkedWriter) Bytes() (b []byte) {
if len(cw.bufs) == 1 {
return cw.bufs[0]
}
b = make([]byte, 0, cw.Len())
for _, buf := range cw.bufs {
b = append(b, buf...)
}
return b
}
func (cw *ChunkedWriter) Len() int {
l := 0
for _, buf := range cw.bufs {
l += len(buf)
}
return l
}
func (cw *ChunkedWriter) Reset() {
b := cw.bufs[0][:0]
cw.bufs = make([][]byte, 1)
cw.bufs[0] = b
}
func (cw *ChunkedWriter) Truncate(n int) {
for i, buf := range cw.bufs {
if n > len(buf) {
n -= len(buf)
continue
}
cw.bufs[i] = buf[:n]
cw.bufs = cw.bufs[:i+1]
return
}
panic("bytes.ChunkedBuffer: truncation out of range")
}
func (cw *ChunkedWriter) Write(p []byte) (n int, err error) {
return cw.WriteString(StringFn(p))
}
func (cw *ChunkedWriter) WriteString(p string) (n int, err error) {
n = len(p)
lastbuf := cw.bufs[len(cw.bufs)-1]
for {
available := cap(lastbuf) - len(lastbuf)
required := len(p)
if available >= required {
cw.bufs[len(cw.bufs)-1] = append(lastbuf, p...)
return
}
cw.bufs[len(cw.bufs)-1] = append(lastbuf, p[:available]...)
p = p[available:]
lastbuf = make([]byte, 0, cap(cw.bufs[0]))
cw.bufs = append(cw.bufs, lastbuf)
}
}
func (cw *ChunkedWriter) Reserve(n int) (b []byte) {
if n > cap(cw.bufs[0]) {
panic(fmt.Sprintf("bytes.ChunkedBuffer: Reserve request too high: %d > %d", n, cap(cw.bufs[0])))
}
lastbuf := cw.bufs[len(cw.bufs)-1]
if n > cap(lastbuf)-len(lastbuf) {
b = make([]byte, n, cap(cw.bufs[0]))
cw.bufs = append(cw.bufs, b)
return b
}
l := len(lastbuf)
b = lastbuf[l : n+l]
cw.bufs[len(cw.bufs)-1] = lastbuf[:n+l]
return b
}
func (cw *ChunkedWriter) WriteByte(c byte) error {
cw.Reserve(1)[0] = c
return nil
}
func (cw *ChunkedWriter) WriteRune(r rune) (n int, err error) {
n = utf8.EncodeRune(cw.Reserve(utf8.RuneLen(r)), r)
return n, nil
}
func (cw *ChunkedWriter) WriteTo(w io.Writer) (n int64, err error) {
for _, buf := range cw.bufs {
m, err := w.Write(buf)
n += int64(m)
if err != nil {
return n, err
}
if m != len(buf) {
return n, io.ErrShortWrite
}
}
cw.Reset()
return n, nil
}