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

Side by Side Diff: pkg/analyzer/lib/src/summary/flat_buffers.dart

Issue 1564913004: Initial flat buffers implementation. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Rewrite using backward construction approach. Created 4 years, 11 months 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
OLDNEW
(Empty)
1 // Copyright (c) 2016, 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 library analyzer.src.summary.flat_buffers;
6
7 import 'dart:collection';
8 import 'dart:convert';
9 import 'dart:typed_data';
10
11 /**
12 * A pointer to some data.
13 */
14 class BufferPointer {
15 final ByteData _buffer;
16 final int _offset;
17
18 factory BufferPointer.fromBytes(List<int> byteList, [int offset = 0]) {
19 Uint8List uint8List = _asUint8List(byteList);
20 ByteData buf = new ByteData.view(uint8List.buffer);
21 return new BufferPointer._(buf, uint8List.offsetInBytes + offset);
22 }
23
24 BufferPointer._(this._buffer, this._offset);
25
26 BufferPointer derefObject() {
27 int uOffset = _getInt32();
Paul Berry 2016/01/07 22:44:54 Should be _getUint32().
scheglov 2016/01/07 23:21:08 Done.
28 return _advance(uOffset);
29 }
30
31 @override
32 String toString() => _offset.toString();
33
34 BufferPointer _advance(int delta) {
35 return new BufferPointer._(_buffer, _offset + delta);
36 }
37
38 int _getInt32([int delta = 0]) =>
39 _buffer.getInt32(_offset + delta, Endianness.LITTLE_ENDIAN);
40
41 int _getInt8([int delta = 0]) => _buffer.getInt8(_offset + delta);
42
43 int _getUint16([int delta = 0]) =>
44 _buffer.getUint16(_offset + delta, Endianness.LITTLE_ENDIAN);
45
46 int _getUint32([int delta = 0]) =>
47 _buffer.getUint32(_offset + delta, Endianness.LITTLE_ENDIAN);
48
49 /**
50 * If the [byteList] is already a [Uint8List] return it.
51 * Otherwise return a [Uint8List] copy of the [byteList].
52 */
53 static Uint8List _asUint8List(List<int> byteList) {
54 if (byteList is Uint8List) {
55 return byteList;
56 } else {
57 return new Uint8List.fromList(byteList);
58 }
59 }
60 }
61
62 /**
63 * Class that helps building flat buffers.
64 */
65 class Builder {
66 final int initialSize;
67
68 ByteData _buf;
69 int _maxAlign;
Paul Berry 2016/01/07 22:44:53 To help future maintainers, let's document what _m
scheglov 2016/01/07 23:21:08 Done.
70 int _tail;
71
72 int _currentTableEndTail;
73 _VTableBuilder _currentVTableBuilder;
74
75 Builder({this.initialSize: 1024}) {
76 reset();
77 }
78
79 /**
80 * Add the [field] with the given 32-bit signed integer [value]. The field is
81 * not added if the [value] is equal to [def].
82 */
83 void addInt32(int field, int value, [int def]) {
84 if (_currentVTableBuilder == null) {
85 throw new StateError('Start a table before adding values.');
86 }
87 if (value != def) {
88 int size = 4;
89 _prepare(size, 1);
90 _trackField(field);
91 _setInt32AtTail(_buf, _tail, value);
92 }
93 }
94
95 /**
96 * Add the [field] with the given 8-bit signed integer [value]. The field is
97 * not added if the [value] is equal to [def].
98 */
99 void addInt8(int field, int value, [int def]) {
100 if (_currentVTableBuilder == null) {
101 throw new StateError('Start a table before adding values.');
102 }
103 if (value != def) {
104 int size = 1;
105 _prepare(size, 1);
106 _trackField(field);
107 _buf.setInt8(_buf.lengthInBytes - _tail, value);
108 }
109 }
110
111 /**
112 * Add the [field] referencing an object with the given [offset].
113 */
114 void addOffset(int field, Offset offset) {
115 if (_currentVTableBuilder == null) {
116 throw new StateError('Start a table before adding values.');
117 }
118 if (offset != null) {
119 _prepare(4, 1);
120 _trackField(field);
121 _setUint32AtTail(_buf, _tail, _tail - offset._tail);
122 }
123 }
124
125 /**
126 * End the current table and return its offset.
127 */
128 Offset endTable() {
129 if (_currentVTableBuilder == null) {
130 throw new StateError('Start a table before ending it.');
131 }
132 // Prepare the size of the current table.
133 int tableSize = _tail - _currentTableEndTail;
134 // Prepare for writing the VTable.
135 _prepare(4, 1);
136 int tableTail = _tail;
137 // Write the VTable.
138 // TODO(scheglov) implement VTable(s) sharing
139 _prepare(2, _currentVTableBuilder.numOfUint16);
140 _currentVTableBuilder.output(
141 _buf, _buf.lengthInBytes - _tail, tableTail, tableSize);
142 // Set the VTable offset.
143 _setInt32AtTail(_buf, tableTail, _tail - tableTail);
144 // Done with this table.
145 _currentVTableBuilder = null;
146 return new Offset(tableTail);
147 }
148
149 /**
150 * Finish off the creation of the buffer. The given [offset] is used as the
151 * root object offset, and usually references directly or indirectly every
152 * written object.
153 */
154 Uint8List finish(Offset offset) {
155 _prepare(4, 1);
156 _setUint32AtTail(_buf, _tail, _tail - offset._tail);
157 return _buf.buffer.asUint8List(_buf.lengthInBytes - _tail);
158 }
159
160 /**
161 * Reset the builder and make it ready for filling a new buffer.
162 */
163 void reset() {
164 _buf = new ByteData(initialSize);
165 _maxAlign = 1;
166 _tail = 0;
167 _currentVTableBuilder = null;
168 }
169
170 /**
171 * Start a new table. Must be finished with [endTable] invocation.
172 */
173 void startTable() {
174 if (_currentVTableBuilder != null) {
175 throw new StateError('Inline tables are not supported.');
176 }
177 _currentVTableBuilder = new _VTableBuilder();
178 _currentTableEndTail = _tail;
179 }
180
181 /**
182 * Write the given list of [values].
183 */
184 Offset writeList(List<Offset> values) {
185 if (_currentVTableBuilder != null) {
186 throw new StateError(
187 'Cannot write a non-scalar value while writing a table.');
188 }
189 _prepare(4, 1 + values.length);
190 Offset result = new Offset(_tail);
191 int tail = _tail;
192 _setUint32AtTail(_buf, tail, values.length);
193 tail -= 4;
194 for (Offset value in values) {
195 _setUint32AtTail(_buf, tail, tail - value._tail);
196 tail -= 4;
197 }
198 return result;
199 }
200
201 /**
202 * Write the given string [value] and return its [Offset], or `null` if
203 * the [value] is equal to [def].
204 */
205 Offset<String> writeString(String value, [String def]) {
206 if (_currentVTableBuilder != null) {
207 throw new StateError(
208 'Cannot write a non-scalar value while writing a table.');
209 }
210 if (value != def) {
211 List<int> bytes = UTF8.encode(value);
212 int length = bytes.length;
213 _prepare(4, 1, additionalBytes: length);
214 Offset<String> result = new Offset(_tail);
215 _setUint32AtTail(_buf, _tail, length);
216 int offset = _buf.lengthInBytes - _tail + 4;
217 for (int i = 0; i < length; i++) {
218 _buf.setInt8(offset++, bytes[i]);
219 }
220 return result;
221 }
222 return null;
223 }
224
225 /**
226 * Prepare for writing the given [count] of scalars of the given [size].
227 * Additionally allocate the specified [additionalBytes]. Update the current
228 * tail pointer to point at the allocated space.
229 */
230 void _prepare(int size, int count, {int additionalBytes: 0}) {
231 // Update the alignment.
232 if (_maxAlign < size) {
233 _maxAlign = size;
234 }
235 // Prepare amount of required space.
236 int dataSize = size * count + additionalBytes;
237 int alignDelta = (-(_tail + dataSize)) % size;
238 int bufSize = alignDelta + dataSize;
239 // Ensure that we have the required amount of space.
240 {
241 int oldCapacity = _buf.lengthInBytes;
242 if (_tail + bufSize > oldCapacity) {
243 int newCapacity = (oldCapacity + bufSize) * 2;
244 newCapacity += (-newCapacity) % _maxAlign;
Paul Berry 2016/01/07 22:44:53 There's a bug here. The important thing is *not*
scheglov 2016/01/07 23:21:08 Done. Thank you for catching this!
245 ByteData newBuf = new ByteData(newCapacity);
246 int deltaCapacity = newCapacity - oldCapacity;
247 newBuf.buffer
248 .asUint8List()
249 .setAll(deltaCapacity, _buf.buffer.asUint8List());
250 _buf = newBuf;
251 }
252 }
253 // Update the tail pointer.
254 _tail += bufSize;
255 }
256
257 /**
258 * Record the offset of the given [field].
259 */
260 void _trackField(int field) {
261 _currentVTableBuilder.addField(field, _tail);
262 }
263
264 static void _setInt32AtTail(ByteData _buf, int tail, int x) {
265 _buf.setInt32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
266 }
267
268 static void _setUint32AtTail(ByteData _buf, int tail, int x) {
269 _buf.setUint32(_buf.lengthInBytes - tail, x, Endianness.LITTLE_ENDIAN);
270 }
271 }
272
273 /**
274 * The reader of 32-bit signed integers.
275 */
276 class Int32Reader extends Reader<int> {
277 const Int32Reader() : super();
278
279 @override
280 int get size => 2;
281
282 @override
283 int read(BufferPointer bp) => bp._getInt32();
284 }
285
286 /**
287 * The reader of 8-bit signed integers.
288 */
289 class Int8Reader extends Reader<int> {
290 const Int8Reader() : super();
291
292 @override
293 int get size => 1;
294
295 @override
296 int read(BufferPointer bp) => bp._getInt8();
297 }
298
299 /**
300 * The reader of object.
301 *
302 * The returned unmodifiable lists lazily read objects on access.
303 */
304 class ListReader<E> extends Reader<List<E>> {
305 final Reader<E> _elementReader;
306
307 const ListReader(this._elementReader);
308
309 @override
310 int get size => 4;
311
312 @override
313 List<E> read(BufferPointer bp) =>
314 new _FbList<E>(_elementReader, bp.derefObject());
315 }
316
317 /**
318 * The offset from the end of the buffer to a serialized object of the type [T].
319 */
320 class Offset<T> {
321 final int _tail;
322
323 Offset(this._tail);
324 }
325
326 /**
327 * Object that can read a value at a [BufferPointer].
328 */
329 abstract class Reader<T> {
330 const Reader();
331
332 /**
333 * The size of the value in bytes.
334 */
335 int get size;
336
337 /**
338 * Read the value at the given pointer.
339 */
340 T read(BufferPointer bp);
341
342 /**
343 * Read the value of the given [field] in the given [object].
344 */
345 T vTableGet(BufferPointer object, int field, [T defaultValue]) {
346 int vTableSOffset = object._getInt32();
347 BufferPointer vTable = object._advance(-vTableSOffset);
348 int vTableSize = vTable._getUint16();
349 int vTableFieldOffset = (1 + 1 + field) * 2;
350 if (vTableFieldOffset < vTableSize) {
351 int fieldOffsetInObject = vTable._getUint16(vTableFieldOffset);
352 if (fieldOffsetInObject != 0) {
353 BufferPointer fieldPointer = object._advance(fieldOffsetInObject);
354 return read(fieldPointer);
355 }
356 }
357 return defaultValue;
358 }
359 }
360
361 /**
362 * The reader of string values.
363 */
364 class StringReader extends Reader<String> {
365 const StringReader() : super();
366
367 @override
368 int get size => 4;
369
370 @override
371 String read(BufferPointer ref) {
372 BufferPointer object = ref.derefObject();
373 int length = object._getUint32();
374 return UTF8
375 .decode(ref._buffer.buffer.asUint8List(object._offset + 4, length));
376 }
377 }
378
379 /**
380 * An abstract reader for tables.
381 */
382 abstract class TableReader<T extends TableReader<T>> extends Reader<T> {
383 const TableReader();
384
385 @override
386 int get size => 4;
387
388 /**
389 * Return the [Reader] for reading fields of the object at [bp].
390 */
391 T createReader(BufferPointer bp);
392
393 @override
394 T read(BufferPointer bp) {
395 bp = bp.derefObject();
396 return createReader(bp);
397 }
398 }
399
400 class _FbList<E> extends Object with ListMixin<E> implements List<E> {
401 final Reader<E> elementReader;
402 final BufferPointer bp;
403
404 _FbList(this.elementReader, this.bp);
405
406 @override
407 int get length => bp._getUint32();
408
409 @override
410 void set length(int i) =>
411 throw new StateError('Attempt to modify immutable list');
412
413 @override
414 E operator [](int i) {
415 BufferPointer ref = bp._advance(4 + elementReader.size * i);
416 return elementReader.read(ref);
417 }
418
419 @override
420 void operator []=(int i, E e) =>
421 throw new StateError('Attempt to modify immutable list');
422 }
423
424 /**
425 * Class for building VTable(s).
426 */
427 class _VTableBuilder {
428 final List<int> fieldTails = <int>[];
429
430 int get numOfUint16 => 1 + 1 + fieldTails.length;
431
432 void addField(int field, int offset) {
433 while (fieldTails.length <= field) {
434 fieldTails.add(null);
435 }
436 fieldTails[field] = offset;
437 }
438
439 /**
440 * Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
441 * and have at least [numOfUint16] 16-bit words available.
442 */
443 void output(ByteData buf, int bufOffset, int tableTail, int tableSize) {
444 // VTable size.
445 buf.setUint16(bufOffset, numOfUint16 * 2, Endianness.LITTLE_ENDIAN);
446 bufOffset += 2;
447 // Table size.
448 buf.setUint16(bufOffset, tableSize, Endianness.LITTLE_ENDIAN);
449 bufOffset += 2;
450 // Field offsets.
451 for (int fieldTail in fieldTails) {
452 int fieldOffset = fieldTail == null ? 0 : tableTail - fieldTail;
453 buf.setUint16(bufOffset, fieldOffset, Endianness.LITTLE_ENDIAN);
454 bufOffset += 2;
455 }
456 }
457 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698