OLD | NEW |
| (Empty) |
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 | |
3 // BSD-style license that can be found in the LICENSE file. | |
4 | |
5 // This is a copy of "dart:io"'s BytesBuilder implementation, from | |
6 // sdk/lib/io/bytes_builder.dart. It's copied here to make it available to | |
7 // non-"dart:io" applications (issue 18348). | |
8 // | |
9 // Because it's copied directly, there are no modifications from the original. | |
10 library http_parser.bytes_builder; | |
11 | |
12 import 'dart:math'; | |
13 import 'dart:typed_data'; | |
14 | |
15 /** | |
16 * Builds a list of bytes, allowing bytes and lists of bytes to be added at the | |
17 * end. | |
18 * | |
19 * Used to efficiently collect bytes and lists of bytes. | |
20 */ | |
21 abstract class BytesBuilder { | |
22 /** | |
23 * Construct a new empty [BytesBuilder]. | |
24 * | |
25 * If [copy] is true, the data is always copied when added to the list. If | |
26 * it [copy] is false, the data is only copied if needed. That means that if | |
27 * the lists are changed after added to the [BytesBuilder], it may effect the | |
28 * output. Default is `true`. | |
29 */ | |
30 factory BytesBuilder({bool copy: true}) { | |
31 if (copy) { | |
32 return new _CopyingBytesBuilder(); | |
33 } else { | |
34 return new _BytesBuilder(); | |
35 } | |
36 } | |
37 | |
38 /** | |
39 * Appends [bytes] to the current contents of the builder. | |
40 * | |
41 * Each value of [bytes] will be bit-representation truncated to the range | |
42 * 0 .. 255. | |
43 */ | |
44 void add(List<int> bytes); | |
45 | |
46 /** | |
47 * Append [byte] to the current contents of the builder. | |
48 * | |
49 * The [byte] will be bit-representation truncated to the range 0 .. 255. | |
50 */ | |
51 void addByte(int byte); | |
52 | |
53 /** | |
54 * Returns the contents of `this` and clears `this`. | |
55 * | |
56 * The list returned is a view of the the internal buffer, limited to the | |
57 * [length]. | |
58 */ | |
59 List<int> takeBytes(); | |
60 | |
61 /** | |
62 * Returns a copy of the current contents of the builder. | |
63 * | |
64 * Leaves the contents of the builder intact. | |
65 */ | |
66 List<int> toBytes(); | |
67 | |
68 /** | |
69 * The number of bytes in the builder. | |
70 */ | |
71 int get length; | |
72 | |
73 /** | |
74 * Returns `true` if the buffer is empty. | |
75 */ | |
76 bool get isEmpty; | |
77 | |
78 /** | |
79 * Returns `true` if the buffer is not empty. | |
80 */ | |
81 bool get isNotEmpty; | |
82 | |
83 /** | |
84 * Clear the contents of the builder. | |
85 */ | |
86 void clear(); | |
87 } | |
88 | |
89 class _CopyingBytesBuilder implements BytesBuilder { | |
90 // Start with 1024 bytes. | |
91 static const int _INIT_SIZE = 1024; | |
92 | |
93 int _length = 0; | |
94 Uint8List _buffer; | |
95 | |
96 void add(List<int> bytes) { | |
97 int bytesLength = bytes.length; | |
98 if (bytesLength == 0) return; | |
99 int required = _length + bytesLength; | |
100 if (_buffer == null) { | |
101 int size = _pow2roundup(required); | |
102 size = max(size, _INIT_SIZE); | |
103 _buffer = new Uint8List(size); | |
104 } else if (_buffer.length < required) { | |
105 // We will create a list in the range of 2-4 times larger than | |
106 // required. | |
107 int size = _pow2roundup(required) * 2; | |
108 var newBuffer = new Uint8List(size); | |
109 newBuffer.setRange(0, _buffer.length, _buffer); | |
110 _buffer = newBuffer; | |
111 } | |
112 assert(_buffer.length >= required); | |
113 if (bytes is Uint8List) { | |
114 _buffer.setRange(_length, required, bytes); | |
115 } else { | |
116 for (int i = 0; i < bytesLength; i++) { | |
117 _buffer[_length + i] = bytes[i]; | |
118 } | |
119 } | |
120 _length = required; | |
121 } | |
122 | |
123 void addByte(int byte) => add([byte]); | |
124 | |
125 List<int> takeBytes() { | |
126 if (_buffer == null) return new Uint8List(0); | |
127 var buffer = new Uint8List.view(_buffer.buffer, 0, _length); | |
128 clear(); | |
129 return buffer; | |
130 } | |
131 | |
132 List<int> toBytes() { | |
133 if (_buffer == null) return new Uint8List(0); | |
134 return new Uint8List.fromList( | |
135 new Uint8List.view(_buffer.buffer, 0, _length)); | |
136 } | |
137 | |
138 int get length => _length; | |
139 | |
140 bool get isEmpty => _length == 0; | |
141 | |
142 bool get isNotEmpty => _length != 0; | |
143 | |
144 void clear() { | |
145 _length = 0; | |
146 _buffer = null; | |
147 } | |
148 | |
149 int _pow2roundup(int x) { | |
150 --x; | |
151 x |= x >> 1; | |
152 x |= x >> 2; | |
153 x |= x >> 4; | |
154 x |= x >> 8; | |
155 x |= x >> 16; | |
156 return x + 1; | |
157 } | |
158 } | |
159 | |
160 class _BytesBuilder implements BytesBuilder { | |
161 int _length = 0; | |
162 final List _chunks = []; | |
163 | |
164 void add(List<int> bytes) { | |
165 if (bytes is! Uint8List) { | |
166 bytes = new Uint8List.fromList(bytes); | |
167 } | |
168 _chunks.add(bytes); | |
169 _length += bytes.length; | |
170 } | |
171 | |
172 void addByte(int byte) => add([byte]); | |
173 | |
174 List<int> takeBytes() { | |
175 if (_chunks.length == 0) return new Uint8List(0); | |
176 if (_chunks.length == 1) { | |
177 var buffer = _chunks.single; | |
178 clear(); | |
179 return buffer; | |
180 } | |
181 var buffer = new Uint8List(_length); | |
182 int offset = 0; | |
183 for (var chunk in _chunks) { | |
184 buffer.setRange(offset, offset + chunk.length, chunk); | |
185 offset += chunk.length; | |
186 } | |
187 clear(); | |
188 return buffer; | |
189 } | |
190 | |
191 List<int> toBytes() { | |
192 if (_chunks.length == 0) return new Uint8List(0); | |
193 var buffer = new Uint8List(_length); | |
194 int offset = 0; | |
195 for (var chunk in _chunks) { | |
196 buffer.setRange(offset, offset + chunk.length, chunk); | |
197 offset += chunk.length; | |
198 } | |
199 return buffer; | |
200 } | |
201 | |
202 int get length => _length; | |
203 | |
204 bool get isEmpty => _length == 0; | |
205 | |
206 bool get isNotEmpty => _length != 0; | |
207 | |
208 void clear() { | |
209 _length = 0; | |
210 _chunks.clear(); | |
211 } | |
212 } | |
OLD | NEW |