OLD | NEW |
---|---|
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 part of dart.io; | 5 part of dart.io; |
6 | 6 |
7 /** | 7 /** |
8 * Builds a list of bytes, allowing bytes and lists of bytes to be added at the | 8 * Builds a list of bytes, allowing bytes and lists of bytes to be added at the |
9 * end. | 9 * end. |
10 * | 10 * |
11 * Used to efficiently collect bytes and lists of bytes, using an internal | 11 * Used to efficiently collect bytes and lists of bytes, using an internal |
12 * buffer. Note that it's optimized for IO, using an initial buffer of 1K bytes. | 12 * buffer. Note that it's optimized for IO, using an initial buffer of 1K bytes. |
Søren Gjesse
2014/04/01 08:58:40
I am not sure the "optimized of IO" is actually tr
Anders Johnsen
2014/04/01 09:29:07
Removed.
| |
13 */ | 13 */ |
14 class BytesBuilder { | 14 abstract class BytesBuilder { |
15 // Start with 1024 bytes. | |
16 static const int _INIT_SIZE = 1024; | |
17 | |
18 int _length = 0; | |
19 Uint8List _buffer; | |
20 | |
21 /** | 15 /** |
22 * Construct a new empty [BytesBuilder]. | 16 * Construct a new empty [BytesBuilder]. |
17 * | |
18 * If [copy] is true, the data is copied when added to the list. Default is | |
19 * `true`. | |
Søren Gjesse
2014/04/01 08:58:40
I think some more documentation on what happens if
Anders Johnsen
2014/04/01 09:29:07
Done.
| |
23 */ | 20 */ |
24 BytesBuilder(); | 21 factory BytesBuilder({bool copy: true}) { |
Søren Gjesse
2014/04/01 08:58:40
The argument name 'copy' is not totally correct. I
Anders Johnsen
2014/04/01 09:29:07
I think cacheBuffers and ownBuffers is confusing.
| |
22 if (copy) { | |
23 return new _CopyingBytesBuilder(); | |
24 } else { | |
25 return new _NonCopyingBytesBuilder(); | |
26 } | |
27 } | |
25 | 28 |
26 /** | 29 /** |
27 * Appends [bytes] to the current contents of the builder. | 30 * Appends [bytes] to the current contents of the builder. |
28 * | 31 * |
29 * Each value of [bytes] will be bit-representation truncated to the range | 32 * Each value of [bytes] will be bit-representation truncated to the range |
30 * 0 .. 255. | 33 * 0 .. 255. |
31 */ | 34 */ |
35 void add(List<int> bytes); | |
36 | |
37 /** | |
38 * Append [byte] to the current contents of the builder. | |
39 * | |
40 * The [byte] will be bit-representation truncated to the range 0 .. 255. | |
41 */ | |
42 void addByte(int byte); | |
43 | |
44 /** | |
45 * Returns the contents of `this` and clears `this`. | |
46 * | |
47 * The list returned is a view of the the internal buffer, limited to the | |
48 * [length]. | |
49 */ | |
50 List<int> takeBytes(); | |
51 | |
52 /** | |
53 * Returns a copy of the current contents of the builder. | |
54 * | |
55 * Leaves the contents of the builder intact. | |
56 */ | |
57 List<int> toBytes(); | |
58 | |
59 /** | |
60 * The number of bytes in the builder. | |
61 */ | |
62 int get length; | |
63 | |
64 /** | |
65 * Returns `true` if the buffer is empty. | |
66 */ | |
67 bool get isEmpty; | |
68 | |
69 /** | |
70 * Returns `true` if the buffer is not empty. | |
71 */ | |
72 bool get isNotEmpty; | |
73 | |
74 /** | |
75 * Clear the contents of the builder. | |
76 */ | |
77 void clear(); | |
78 } | |
79 | |
80 | |
81 class _CopyingBytesBuilder implements BytesBuilder { | |
82 // Start with 1024 bytes. | |
83 static const int _INIT_SIZE = 1024; | |
84 | |
85 int _length = 0; | |
86 Uint8List _buffer; | |
87 | |
32 void add(List<int> bytes) { | 88 void add(List<int> bytes) { |
33 int bytesLength = bytes.length; | 89 int bytesLength = bytes.length; |
34 if (bytesLength == 0) return; | 90 if (bytesLength == 0) return; |
35 int required = _length + bytesLength; | 91 int required = _length + bytesLength; |
36 if (_buffer == null) { | 92 if (_buffer == null) { |
37 int size = _pow2roundup(required); | 93 int size = _pow2roundup(required); |
38 size = max(size, _INIT_SIZE); | 94 size = max(size, _INIT_SIZE); |
39 _buffer = new Uint8List(size); | 95 _buffer = new Uint8List(size); |
40 } else if (_buffer.length < required) { | 96 } else if (_buffer.length < required) { |
41 // We will create a list in the range of 2-4 times larger than | 97 // We will create a list in the range of 2-4 times larger than |
42 // required. | 98 // required. |
43 int size = _pow2roundup(required) * 2; | 99 int size = _pow2roundup(required) * 2; |
44 var newBuffer = new Uint8List(size); | 100 var newBuffer = new Uint8List(size); |
45 newBuffer.setRange(0, _buffer.length, _buffer); | 101 newBuffer.setRange(0, _buffer.length, _buffer); |
46 _buffer = newBuffer; | 102 _buffer = newBuffer; |
47 } | 103 } |
48 assert(_buffer.length >= required); | 104 assert(_buffer.length >= required); |
49 if (bytes is Uint8List) { | 105 if (bytes is Uint8List) { |
50 _buffer.setRange(_length, required, bytes); | 106 _buffer.setRange(_length, required, bytes); |
51 } else { | 107 } else { |
52 for (int i = 0; i < bytesLength; i++) { | 108 for (int i = 0; i < bytesLength; i++) { |
53 _buffer[_length + i] = bytes[i]; | 109 _buffer[_length + i] = bytes[i]; |
54 } | 110 } |
55 } | 111 } |
56 _length = required; | 112 _length = required; |
57 } | 113 } |
58 | 114 |
59 /** | |
60 * Append [byte] to the current contents of the builder. | |
61 * | |
62 * The [byte] will be bit-representation truncated to the range 0 .. 255. | |
63 */ | |
64 void addByte(int byte) => add([byte]); | 115 void addByte(int byte) => add([byte]); |
65 | 116 |
66 /** | |
67 * Returns the contents of `this` and clears `this`. | |
68 * | |
69 * The list returned is a view of the the internal buffer, limited to the | |
70 * [length]. | |
71 */ | |
72 List<int> takeBytes() { | 117 List<int> takeBytes() { |
73 if (_buffer == null) return new Uint8List(0); | 118 if (_buffer == null) return new Uint8List(0); |
74 var buffer = new Uint8List.view(_buffer.buffer, 0, _length); | 119 var buffer = new Uint8List.view(_buffer.buffer, 0, _length); |
75 clear(); | 120 clear(); |
76 return buffer; | 121 return buffer; |
77 } | 122 } |
78 | 123 |
79 /** | |
80 * Returns a copy of the current contents of the builder. | |
81 * | |
82 * Leaves the contents of the builder intact. | |
83 */ | |
84 List<int> toBytes() { | 124 List<int> toBytes() { |
85 if (_buffer == null) return new Uint8List(0); | 125 if (_buffer == null) return new Uint8List(0); |
86 return new Uint8List.fromList( | 126 return new Uint8List.fromList( |
87 new Uint8List.view(_buffer.buffer, 0, _length)); | 127 new Uint8List.view(_buffer.buffer, 0, _length)); |
88 } | 128 } |
89 | 129 |
90 /** | |
91 * The number of bytes in the builder. | |
92 */ | |
93 int get length => _length; | 130 int get length => _length; |
94 | 131 |
95 /** | |
96 * Returns `true` if the buffer is empty. | |
97 */ | |
98 bool get isEmpty => _length == 0; | 132 bool get isEmpty => _length == 0; |
99 | 133 |
100 /** | |
101 * Returns `true` if the buffer is not empty. | |
102 */ | |
103 bool get isNotEmpty => _length != 0; | 134 bool get isNotEmpty => _length != 0; |
104 | 135 |
105 /** | |
106 * Clear the contents of the builder. | |
107 */ | |
108 void clear() { | 136 void clear() { |
109 _length = 0; | 137 _length = 0; |
110 _buffer = null; | 138 _buffer = null; |
111 } | 139 } |
112 | 140 |
113 int _pow2roundup(int x) { | 141 int _pow2roundup(int x) { |
114 --x; | 142 --x; |
115 x |= x >> 1; | 143 x |= x >> 1; |
116 x |= x >> 2; | 144 x |= x >> 2; |
117 x |= x >> 4; | 145 x |= x >> 4; |
118 x |= x >> 8; | 146 x |= x >> 8; |
119 x |= x >> 16; | 147 x |= x >> 16; |
120 return x + 1; | 148 return x + 1; |
121 } | 149 } |
122 } | 150 } |
151 | |
152 | |
153 class _NonCopyingBytesBuilder implements BytesBuilder { | |
154 int _length = 0; | |
155 final List _chunks = []; | |
156 | |
157 void add(List<int> bytes) { | |
158 if (bytes is! Uint8List) { | |
Søren Gjesse
2014/04/01 08:58:40
This might be surprising, as for the non-copying w
Anders Johnsen
2014/04/01 09:29:07
We do say that there is an internal list and promi
| |
159 bytes = new Uint8List.fromList(bytes); | |
160 } | |
161 _chunks.add(bytes); | |
162 _length += bytes.length; | |
163 } | |
164 | |
165 void addByte(int byte) => add([byte]); | |
166 | |
167 List<int> takeBytes() { | |
168 if (_chunks.length == 0) return new Uint8List(0); | |
169 if (_chunks.length == 1) { | |
170 var buffer = _chunks.single; | |
171 clear(); | |
172 return buffer; | |
173 } | |
174 var buffer = new Uint8List(_length); | |
175 int offset = 0; | |
176 for (var chunk in _chunks) { | |
177 buffer.setRange(offset, offset + chunk.length, chunk); | |
178 offset += chunk.length; | |
179 } | |
180 clear(); | |
181 return buffer; | |
182 } | |
183 | |
184 List<int> toBytes() { | |
185 if (_chunks.length == 0) return new Uint8List(0); | |
186 var buffer = new Uint8List(_length); | |
187 int offset = 0; | |
188 for (var chunk in _chunks) { | |
189 buffer.setRange(offset, offset + chunk.length, chunk); | |
190 offset += chunk.length; | |
191 } | |
192 return buffer; | |
193 } | |
194 | |
195 int get length => _length; | |
196 | |
197 bool get isEmpty => _length == 0; | |
198 | |
199 bool get isNotEmpty => _length != 0; | |
200 | |
201 void clear() { | |
202 _length = 0; | |
203 _chunks.clear(); | |
204 } | |
205 } | |
OLD | NEW |