Line data Source code
1 : // Copyright (c) 2020, 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 : import 'dart:collection' show ListBase;
6 : import 'dart:typed_data';
7 :
8 : abstract class TypedDataBuffer<E> extends ListBase<E> {
9 : static const int _initialLength = 8;
10 :
11 : /// The underlying data buffer.
12 : ///
13 : /// This is always both a List<E> and a TypedData, which we don't have a type
14 : /// for here. For example, for a `Uint8Buffer`, this is a `Uint8List`.
15 : List<E> _buffer;
16 :
17 : /// Returns a view of [_buffer] as a [TypedData].
18 0 : TypedData get _typedBuffer => _buffer as TypedData;
19 :
20 : /// The length of the list being built.
21 : int _length;
22 :
23 0 : TypedDataBuffer(List<E> buffer)
24 : : _buffer = buffer,
25 0 : _length = buffer.length;
26 :
27 0 : @override
28 0 : int get length => _length;
29 :
30 0 : @override
31 : E operator [](int index) {
32 0 : if (index >= length) throw RangeError.index(index, this);
33 0 : return _buffer[index];
34 : }
35 :
36 0 : @override
37 : void operator []=(int index, E value) {
38 0 : if (index >= length) throw RangeError.index(index, this);
39 0 : _buffer[index] = value;
40 : }
41 :
42 0 : @override
43 : set length(int newLength) {
44 0 : if (newLength < _length) {
45 0 : var defaultValue = _defaultValue;
46 0 : for (var i = newLength; i < _length; i++) {
47 0 : _buffer[i] = defaultValue;
48 : }
49 0 : } else if (newLength > _buffer.length) {
50 : List<E> newBuffer;
51 0 : if (_buffer.isEmpty) {
52 0 : newBuffer = _createBuffer(newLength);
53 : } else {
54 0 : newBuffer = _createBiggerBuffer(newLength);
55 : }
56 0 : newBuffer.setRange(0, _length, _buffer);
57 0 : _buffer = newBuffer;
58 : }
59 0 : _length = newLength;
60 : }
61 :
62 0 : void _add(E value) {
63 0 : if (_length == _buffer.length) _grow(_length);
64 0 : _buffer[_length++] = value;
65 : }
66 :
67 : // We override the default implementation of `add` because it grows the list
68 : // by setting the length in increments of one. We want to grow by doubling
69 : // capacity in most cases.
70 0 : @override
71 : void add(E value) {
72 0 : _add(value);
73 : }
74 :
75 : /// Appends all objects of [values] to the end of this buffer.
76 : ///
77 : /// This adds values from [start] (inclusive) to [end] (exclusive) in
78 : /// [values]. If [end] is omitted, it defaults to adding all elements of
79 : /// [values] after [start].
80 : ///
81 : /// The [start] value must be non-negative. The [values] iterable must have at
82 : /// least [start] elements, and if [end] is specified, it must be greater than
83 : /// or equal to [start] and [values] must have at least [end] elements.
84 0 : @override
85 : void addAll(Iterable<E> values, [int start = 0, int? end]) {
86 0 : RangeError.checkNotNegative(start, 'start');
87 0 : if (end != null && start > end) {
88 0 : throw RangeError.range(end, start, null, 'end');
89 : }
90 :
91 0 : _addAll(values, start, end);
92 : }
93 :
94 : /// Inserts all objects of [values] at position [index] in this list.
95 : ///
96 : /// This adds values from [start] (inclusive) to [end] (exclusive) in
97 : /// [values]. If [end] is omitted, it defaults to adding all elements of
98 : /// [values] after [start].
99 : ///
100 : /// The [start] value must be non-negative. The [values] iterable must have at
101 : /// least [start] elements, and if [end] is specified, it must be greater than
102 : /// or equal to [start] and [values] must have at least [end] elements.
103 0 : @override
104 : void insertAll(int index, Iterable<E> values, [int start = 0, int? end]) {
105 0 : RangeError.checkValidIndex(index, this, 'index', _length + 1);
106 0 : RangeError.checkNotNegative(start, 'start');
107 : if (end != null) {
108 0 : if (start > end) {
109 0 : throw RangeError.range(end, start, null, 'end');
110 : }
111 0 : if (start == end) return;
112 : }
113 :
114 : // If we're adding to the end of the list anyway, use [_addAll]. This lets
115 : // us avoid converting [values] into a list even if [end] is null, since we
116 : // can add values iteratively to the end of the list. We can't do so in the
117 : // center because copying the trailing elements every time is non-linear.
118 0 : if (index == _length) {
119 0 : _addAll(values, start, end);
120 : return;
121 : }
122 :
123 0 : if (end == null && values is List) {
124 0 : end = values.length;
125 : }
126 : if (end != null) {
127 0 : _insertKnownLength(index, values, start, end);
128 : return;
129 : }
130 :
131 : // Add elements at end, growing as appropriate, then put them back at
132 : // position [index] using flip-by-double-reverse.
133 0 : var writeIndex = _length;
134 : var skipCount = start;
135 0 : for (var value in values) {
136 0 : if (skipCount > 0) {
137 0 : skipCount--;
138 : continue;
139 : }
140 0 : if (writeIndex == _buffer.length) {
141 0 : _grow(writeIndex);
142 : }
143 0 : _buffer[writeIndex++] = value;
144 : }
145 :
146 0 : if (skipCount > 0) {
147 0 : throw StateError('Too few elements');
148 : }
149 0 : if (end != null && writeIndex < end) {
150 0 : throw RangeError.range(end, start, writeIndex, 'end');
151 : }
152 :
153 : // Swap [index.._length) and [_length..writeIndex) by double-reversing.
154 0 : _reverse(_buffer, index, _length);
155 0 : _reverse(_buffer, _length, writeIndex);
156 0 : _reverse(_buffer, index, writeIndex);
157 0 : _length = writeIndex;
158 : return;
159 : }
160 :
161 : // Reverses the range [start..end) of buffer.
162 0 : static void _reverse(List buffer, int start, int end) {
163 0 : end--; // Point to last element, not after last element.
164 0 : while (start < end) {
165 0 : var first = buffer[start];
166 0 : var last = buffer[end];
167 0 : buffer[end] = first;
168 0 : buffer[start] = last;
169 0 : start++;
170 0 : end--;
171 : }
172 : }
173 :
174 : /// Does the same thing as [addAll].
175 : ///
176 : /// This allows [addAll] and [insertAll] to share implementation without a
177 : /// subclass unexpectedly overriding both when it intended to only override
178 : /// [addAll].
179 0 : void _addAll(Iterable<E> values, [int start = 0, int? end]) {
180 0 : if (values is List) end ??= values.length;
181 :
182 : // If we know the length of the segment to add, do so with [addRange]. This
183 : // way we know how much to grow the buffer in advance, and it may be even
184 : // more efficient for typed data input.
185 : if (end != null) {
186 0 : _insertKnownLength(_length, values, start, end);
187 : return;
188 : }
189 :
190 : // Otherwise, just add values one at a time.
191 : var i = 0;
192 0 : for (var value in values) {
193 0 : if (i >= start) add(value);
194 0 : i++;
195 : }
196 0 : if (i < start) throw StateError('Too few elements');
197 : }
198 :
199 : /// Like [insertAll], but with a guaranteed non-`null` [start] and [end].
200 0 : void _insertKnownLength(int index, Iterable<E> values, int start, int end) {
201 0 : if (values is List) {
202 0 : if (start > values.length || end > values.length) {
203 0 : throw StateError('Too few elements');
204 : }
205 : }
206 :
207 0 : var valuesLength = end - start;
208 0 : var newLength = _length + valuesLength;
209 0 : _ensureCapacity(newLength);
210 :
211 0 : _buffer.setRange(
212 0 : index + valuesLength, _length + valuesLength, _buffer, index);
213 0 : _buffer.setRange(index, index + valuesLength, values, start);
214 0 : _length = newLength;
215 : }
216 :
217 0 : @override
218 : void insert(int index, E element) {
219 0 : if (index < 0 || index > _length) {
220 0 : throw RangeError.range(index, 0, _length);
221 : }
222 0 : if (_length < _buffer.length) {
223 0 : _buffer.setRange(index + 1, _length + 1, _buffer, index);
224 0 : _buffer[index] = element;
225 0 : _length++;
226 : return;
227 : }
228 0 : var newBuffer = _createBiggerBuffer(null);
229 0 : newBuffer.setRange(0, index, _buffer);
230 0 : newBuffer.setRange(index + 1, _length + 1, _buffer, index);
231 0 : newBuffer[index] = element;
232 0 : _length++;
233 0 : _buffer = newBuffer;
234 : }
235 :
236 : /// Ensures that [_buffer] is at least [requiredCapacity] long,
237 : ///
238 : /// Grows the buffer if necessary, preserving existing data.
239 0 : void _ensureCapacity(int requiredCapacity) {
240 0 : if (requiredCapacity <= _buffer.length) return;
241 0 : var newBuffer = _createBiggerBuffer(requiredCapacity);
242 0 : newBuffer.setRange(0, _length, _buffer);
243 0 : _buffer = newBuffer;
244 : }
245 :
246 : /// Create a bigger buffer.
247 : ///
248 : /// This method determines how much bigger a bigger buffer should
249 : /// be. If [requiredCapacity] is not null, it will be at least that
250 : /// size. It will always have at least have double the capacity of
251 : /// the current buffer.
252 0 : List<E> _createBiggerBuffer(int? requiredCapacity) {
253 0 : var newLength = _buffer.length * 2;
254 0 : if (requiredCapacity != null && newLength < requiredCapacity) {
255 : newLength = requiredCapacity;
256 0 : } else if (newLength < _initialLength) {
257 : newLength = _initialLength;
258 : }
259 0 : return _createBuffer(newLength);
260 : }
261 :
262 : /// Grows the buffer.
263 : ///
264 : /// This copies the first [length] elements into the new buffer.
265 0 : void _grow(int length) {
266 0 : _buffer = _createBiggerBuffer(null)..setRange(0, length, _buffer);
267 : }
268 :
269 0 : @override
270 : void setRange(int start, int end, Iterable<E> source, [int skipCount = 0]) {
271 0 : if (end > _length) throw RangeError.range(end, 0, _length);
272 0 : _setRange(start, end, source, skipCount);
273 : }
274 :
275 : /// Like [setRange], but with no bounds checking.
276 0 : void _setRange(int start, int end, Iterable<E> source, int skipCount) {
277 0 : if (source is TypedDataBuffer<E>) {
278 0 : _buffer.setRange(start, end, source._buffer, skipCount);
279 : } else {
280 0 : _buffer.setRange(start, end, source, skipCount);
281 : }
282 : }
283 :
284 : // TypedData.
285 :
286 0 : int get elementSizeInBytes => _typedBuffer.elementSizeInBytes;
287 :
288 0 : int get lengthInBytes => _length * _typedBuffer.elementSizeInBytes;
289 :
290 0 : int get offsetInBytes => _typedBuffer.offsetInBytes;
291 :
292 : /// Returns the underlying [ByteBuffer].
293 : ///
294 : /// The returned buffer may be replaced by operations that change the [length]
295 : /// of this list.
296 : ///
297 : /// The buffer may be larger than [lengthInBytes] bytes, but never smaller.
298 0 : ByteBuffer get buffer => _typedBuffer.buffer;
299 :
300 : // Specialization for the specific type.
301 :
302 : // Return zero for integers, 0.0 for floats, etc.
303 : // Used to fill buffer when changing length.
304 : E get _defaultValue;
305 :
306 : // Create a new typed list to use as buffer.
307 : List<E> _createBuffer(int size);
308 : }
309 :
310 : abstract class _IntBuffer extends TypedDataBuffer<int> {
311 0 : _IntBuffer(List<int> buffer) : super(buffer);
312 :
313 0 : @override
314 : int get _defaultValue => 0;
315 : }
316 :
317 : abstract class _FloatBuffer extends TypedDataBuffer<double> {
318 0 : _FloatBuffer(List<double> buffer) : super(buffer);
319 :
320 0 : @override
321 : double get _defaultValue => 0.0;
322 : }
323 :
324 : class Uint8Buffer extends _IntBuffer {
325 0 : Uint8Buffer([int initialLength = 0]) : super(Uint8List(initialLength));
326 :
327 0 : @override
328 0 : Uint8List _createBuffer(int size) => Uint8List(size);
329 : }
330 :
331 : class Int8Buffer extends _IntBuffer {
332 0 : Int8Buffer([int initialLength = 0]) : super(Int8List(initialLength));
333 :
334 0 : @override
335 0 : Int8List _createBuffer(int size) => Int8List(size);
336 : }
337 :
338 : class Uint8ClampedBuffer extends _IntBuffer {
339 0 : Uint8ClampedBuffer([int initialLength = 0])
340 0 : : super(Uint8ClampedList(initialLength));
341 :
342 0 : @override
343 0 : Uint8ClampedList _createBuffer(int size) => Uint8ClampedList(size);
344 : }
345 :
346 : class Uint16Buffer extends _IntBuffer {
347 0 : Uint16Buffer([int initialLength = 0]) : super(Uint16List(initialLength));
348 :
349 0 : @override
350 0 : Uint16List _createBuffer(int size) => Uint16List(size);
351 : }
352 :
353 : class Int16Buffer extends _IntBuffer {
354 0 : Int16Buffer([int initialLength = 0]) : super(Int16List(initialLength));
355 :
356 0 : @override
357 0 : Int16List _createBuffer(int size) => Int16List(size);
358 : }
359 :
360 : class Uint32Buffer extends _IntBuffer {
361 0 : Uint32Buffer([int initialLength = 0]) : super(Uint32List(initialLength));
362 :
363 0 : @override
364 0 : Uint32List _createBuffer(int size) => Uint32List(size);
365 : }
366 :
367 : class Int32Buffer extends _IntBuffer {
368 0 : Int32Buffer([int initialLength = 0]) : super(Int32List(initialLength));
369 :
370 0 : @override
371 0 : Int32List _createBuffer(int size) => Int32List(size);
372 : }
373 :
374 : class Uint64Buffer extends _IntBuffer {
375 0 : Uint64Buffer([int initialLength = 0]) : super(Uint64List(initialLength));
376 :
377 0 : @override
378 0 : Uint64List _createBuffer(int size) => Uint64List(size);
379 : }
380 :
381 : class Int64Buffer extends _IntBuffer {
382 0 : Int64Buffer([int initialLength = 0]) : super(Int64List(initialLength));
383 :
384 0 : @override
385 0 : Int64List _createBuffer(int size) => Int64List(size);
386 : }
387 :
388 : class Float32Buffer extends _FloatBuffer {
389 0 : Float32Buffer([int initialLength = 0]) : super(Float32List(initialLength));
390 :
391 0 : @override
392 0 : Float32List _createBuffer(int size) => Float32List(size);
393 : }
394 :
395 : class Float64Buffer extends _FloatBuffer {
396 0 : Float64Buffer([int initialLength = 0]) : super(Float64List(initialLength));
397 :
398 0 : @override
399 0 : Float64List _createBuffer(int size) => Float64List(size);
400 : }
401 :
402 : class Int32x4Buffer extends TypedDataBuffer<Int32x4> {
403 0 : static final Int32x4 _zero = Int32x4(0, 0, 0, 0);
404 :
405 0 : Int32x4Buffer([int initialLength = 0]) : super(Int32x4List(initialLength));
406 :
407 0 : @override
408 0 : Int32x4 get _defaultValue => _zero;
409 :
410 0 : @override
411 0 : Int32x4List _createBuffer(int size) => Int32x4List(size);
412 : }
413 :
414 : class Float32x4Buffer extends TypedDataBuffer<Float32x4> {
415 0 : Float32x4Buffer([int initialLength = 0])
416 0 : : super(Float32x4List(initialLength));
417 :
418 0 : @override
419 0 : Float32x4 get _defaultValue => Float32x4.zero();
420 :
421 0 : @override
422 0 : Float32x4List _createBuffer(int size) => Float32x4List(size);
423 : }
|