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