Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Side by Side Diff: common/chunkstream/buffer.go

Issue 1413923013: Add `chunk` segmented data library. (Closed) Base URL: https://github.com/luci/luci-go@logdog-review-streamserver
Patch Set: Code review comments. Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | common/chunkstream/buffer_test.go » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 package chunkstream
6
7 // Buffer is a collection of ordered Chunks that can cheaply read and shifted
8 // as if it were a continuous byte stream.
9 //
10 // A Buffer is not goroutine-safe.
11 //
12 // The primary means of interacting with a Buffer is to construct a View and
13 // then use it to access the Buffer's contents. Views can be used concurrently,
14 // and View operations are goroutine-safe.
15 type Buffer struct {
16 // First is a pointer to the first Chunk node in the buffer.
17 first *chunkNode
18 // Last is a pointer to the last Chunk node in the buffer.
19 last *chunkNode
20
21 // size is the total number of bytes in the Buffer.
22 size int64
23
24 // fidx is the current byte offset in first.
25 fidx int
26 }
27
28 // Append adds additional Chunks to the buffer.
29 //
30 // After completion, the Chunk is now owned by the Buffer and should not be used
31 // anymore externally.
32 func (b *Buffer) Append(c ...Chunk) {
33 for _, chunk := range c {
34 b.appendChunk(chunk)
iannucci 2015/11/18 23:51:42 maybe allocate a mini-list of chunks and then appe
dnj (Google) 2015/11/19 00:19:55 Yeah it's not a bad idea, save some pointer updati
35 }
36 }
37
38 func (b *Buffer) appendChunk(c Chunk) {
39 // Ignore/discard zero-length data.
40 if len(c.Bytes()) == 0 {
41 c.Release()
42 return
43 }
44
45 cn := newChunkNode(c)
46 cn.next = nil
47 if b.last == nil {
48 // First node.
49 b.first = cn
50 } else {
51 b.last.next = cn
52 }
53 b.last = cn
54 b.size += int64(cn.length())
55 }
56
57 // Bytes constructs a byte slice containing the contents of the Buffer.
58 //
59 // This is a potentially expensive operation, and should generally be used only
60 // for debugging and tests, as it defeats most of the purpose of this package.
61 func (b *Buffer) Bytes() []byte {
62 if b.Len() == 0 {
63 return nil
64 }
65
66 m := make([]byte, 0, b.Len())
67 idx := b.fidx
68 for cur := b.first; cur != nil; cur = cur.next {
69 m = append(m, cur.Bytes()[idx:]...)
70 idx = 0
71 }
72 return m
73 }
74
75 // Len returns the total amount of data in the buffer.
76 func (b *Buffer) Len() int64 {
77 return b.size
78 }
79
80 // FirstChunk returns the first Chunk in the Buffer, or nil if the Buffer has
81 // no Chunks.
82 func (b *Buffer) FirstChunk() Chunk {
83 if b.first == nil {
84 return nil
85 }
86 return b.first.Chunk
87 }
88
89 // View returns a View instance bound to this Buffer and spanning all data
90 // currently in the Buffer.
91 //
92 // The View is no longer valid after Consume is called on the Buffer.
93 func (b *Buffer) View() *View {
94 return b.ViewLimit(b.size)
95 }
96
97 // ViewLimit constructs a View instance, but artifically constrains it to
98 // read at most the specified number of bytes.
99 //
100 // This is useful when reading a subset of the data into a Buffer, as ReadFrom
101 // does not allow a size to be specified.
102 func (b *Buffer) ViewLimit(limit int64) *View {
103 if limit > b.size {
104 limit = b.size
105 }
106
107 return &View{
108 cur: b.first,
109 cidx: b.fidx,
110 size: limit,
111
112 b: b,
113 }
114 }
115
116 // Consume removes the specified number of bytes from the beginning of the
117 // Buffer. If Consume skips past all of the data in a Chunk is no longer needed,
118 // it is Release()d.
119 func (b *Buffer) Consume(c int64) {
120 if c == 0 {
121 return
122 }
123
124 if c > b.size {
125 panic("consuming more data than available")
iannucci 2015/11/18 23:51:43 should we panic with errors? or is raw strings OK?
dnj (Google) 2015/11/19 00:19:55 TBH I'm not sure. I don't think an error would add
126 }
127 b.size -= c
128
129 for c > 0 {
130 // Do we consume the entire chunk?
131 if int64(b.first.length()-b.fidx) > c {
132 // No. Advance our chunk index and terminate.
133 b.fidx += int(c)
134 break
135 }
136
137 n := b.first
138 c -= int64(n.length() - b.fidx)
139 b.first = n.next
140 b.fidx = 0
141 if b.first == nil {
142 b.last = nil
143 }
144
145 // Release our node. We must not reference it after this.
146 n.release()
147 }
148 }
OLDNEW
« no previous file with comments | « no previous file | common/chunkstream/buffer_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698