1*890232f2SAndroid Build Coastguard Workerimport 'dart:convert'; 2*890232f2SAndroid Build Coastguard Workerimport 'dart:typed_data'; 3*890232f2SAndroid Build Coastguard Worker 4*890232f2SAndroid Build Coastguard Workerimport 'types.dart'; 5*890232f2SAndroid Build Coastguard Worker 6*890232f2SAndroid Build Coastguard Worker/// The main builder class for creation of a FlexBuffer. 7*890232f2SAndroid Build Coastguard Workerclass Builder { 8*890232f2SAndroid Build Coastguard Worker final ByteData _buffer; 9*890232f2SAndroid Build Coastguard Worker List<_StackValue> _stack = []; 10*890232f2SAndroid Build Coastguard Worker List<_StackPointer> _stackPointers = []; 11*890232f2SAndroid Build Coastguard Worker int _offset = 0; 12*890232f2SAndroid Build Coastguard Worker bool _finished = false; 13*890232f2SAndroid Build Coastguard Worker final Map<String, _StackValue> _stringCache = {}; 14*890232f2SAndroid Build Coastguard Worker final Map<String, _StackValue> _keyCache = {}; 15*890232f2SAndroid Build Coastguard Worker final Map<_KeysHash, _StackValue> _keyVectorCache = {}; 16*890232f2SAndroid Build Coastguard Worker final Map<int, _StackValue> _indirectIntCache = {}; 17*890232f2SAndroid Build Coastguard Worker final Map<double, _StackValue> _indirectDoubleCache = {}; 18*890232f2SAndroid Build Coastguard Worker 19*890232f2SAndroid Build Coastguard Worker /// Instantiate the builder if you intent to gradually build up the buffer by calling 20*890232f2SAndroid Build Coastguard Worker /// add... methods and calling [finish] to receive the the resulting byte array. 21*890232f2SAndroid Build Coastguard Worker /// 22*890232f2SAndroid Build Coastguard Worker /// The default size of internal buffer is set to 2048. Provide a different value in order to avoid buffer copies. 23*890232f2SAndroid Build Coastguard Worker Builder({int size = 2048}) : _buffer = ByteData(size); 24*890232f2SAndroid Build Coastguard Worker 25*890232f2SAndroid Build Coastguard Worker /// Use this method in order to turn an object into a FlexBuffer directly. 26*890232f2SAndroid Build Coastguard Worker /// 27*890232f2SAndroid Build Coastguard Worker /// Use the manual instantiation of the [Builder] and gradual addition of values, if performance is more important than convenience. 28*890232f2SAndroid Build Coastguard Worker static ByteBuffer buildFromObject(Object? value) { 29*890232f2SAndroid Build Coastguard Worker final builder = Builder(); 30*890232f2SAndroid Build Coastguard Worker builder._add(value); 31*890232f2SAndroid Build Coastguard Worker final buffer = builder.finish(); 32*890232f2SAndroid Build Coastguard Worker final byteData = ByteData(buffer.lengthInBytes); 33*890232f2SAndroid Build Coastguard Worker byteData.buffer.asUint8List().setAll(0, buffer); 34*890232f2SAndroid Build Coastguard Worker return byteData.buffer; 35*890232f2SAndroid Build Coastguard Worker } 36*890232f2SAndroid Build Coastguard Worker 37*890232f2SAndroid Build Coastguard Worker void _add(Object? value) { 38*890232f2SAndroid Build Coastguard Worker if (value == null) { 39*890232f2SAndroid Build Coastguard Worker addNull(); 40*890232f2SAndroid Build Coastguard Worker } else if (value is bool) { 41*890232f2SAndroid Build Coastguard Worker addBool(value); 42*890232f2SAndroid Build Coastguard Worker } else if (value is int) { 43*890232f2SAndroid Build Coastguard Worker addInt(value); 44*890232f2SAndroid Build Coastguard Worker } else if (value is double) { 45*890232f2SAndroid Build Coastguard Worker addDouble(value); 46*890232f2SAndroid Build Coastguard Worker } else if (value is ByteBuffer) { 47*890232f2SAndroid Build Coastguard Worker addBlob(value); 48*890232f2SAndroid Build Coastguard Worker } else if (value is String) { 49*890232f2SAndroid Build Coastguard Worker addString(value); 50*890232f2SAndroid Build Coastguard Worker } else if (value is List<dynamic>) { 51*890232f2SAndroid Build Coastguard Worker startVector(); 52*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < value.length; i++) { 53*890232f2SAndroid Build Coastguard Worker _add(value[i]); 54*890232f2SAndroid Build Coastguard Worker } 55*890232f2SAndroid Build Coastguard Worker end(); 56*890232f2SAndroid Build Coastguard Worker } else if (value is Map<String, dynamic>) { 57*890232f2SAndroid Build Coastguard Worker startMap(); 58*890232f2SAndroid Build Coastguard Worker value.forEach((key, value) { 59*890232f2SAndroid Build Coastguard Worker addKey(key); 60*890232f2SAndroid Build Coastguard Worker _add(value); 61*890232f2SAndroid Build Coastguard Worker }); 62*890232f2SAndroid Build Coastguard Worker end(); 63*890232f2SAndroid Build Coastguard Worker } else { 64*890232f2SAndroid Build Coastguard Worker throw UnsupportedError('Value of unexpected type: $value'); 65*890232f2SAndroid Build Coastguard Worker } 66*890232f2SAndroid Build Coastguard Worker } 67*890232f2SAndroid Build Coastguard Worker 68*890232f2SAndroid Build Coastguard Worker /// Use this method if you want to store a null value. 69*890232f2SAndroid Build Coastguard Worker /// 70*890232f2SAndroid Build Coastguard Worker /// Specifically useful when building up a vector where values can be null. 71*890232f2SAndroid Build Coastguard Worker void addNull() { 72*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 73*890232f2SAndroid Build Coastguard Worker _stack.add(_StackValue.withNull()); 74*890232f2SAndroid Build Coastguard Worker } 75*890232f2SAndroid Build Coastguard Worker 76*890232f2SAndroid Build Coastguard Worker /// Adds a string value. 77*890232f2SAndroid Build Coastguard Worker void addInt(int value) { 78*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 79*890232f2SAndroid Build Coastguard Worker _stack.add(_StackValue.withInt(value)); 80*890232f2SAndroid Build Coastguard Worker } 81*890232f2SAndroid Build Coastguard Worker 82*890232f2SAndroid Build Coastguard Worker /// Adds a bool value. 83*890232f2SAndroid Build Coastguard Worker void addBool(bool value) { 84*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 85*890232f2SAndroid Build Coastguard Worker _stack.add(_StackValue.withBool(value)); 86*890232f2SAndroid Build Coastguard Worker } 87*890232f2SAndroid Build Coastguard Worker 88*890232f2SAndroid Build Coastguard Worker /// Adds a double value. 89*890232f2SAndroid Build Coastguard Worker void addDouble(double value) { 90*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 91*890232f2SAndroid Build Coastguard Worker _stack.add(_StackValue.withDouble(value)); 92*890232f2SAndroid Build Coastguard Worker } 93*890232f2SAndroid Build Coastguard Worker 94*890232f2SAndroid Build Coastguard Worker /// Adds a string value. 95*890232f2SAndroid Build Coastguard Worker void addString(String value) { 96*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 97*890232f2SAndroid Build Coastguard Worker if (_stringCache.containsKey(value)) { 98*890232f2SAndroid Build Coastguard Worker _stack.add(_stringCache[value]!); 99*890232f2SAndroid Build Coastguard Worker return; 100*890232f2SAndroid Build Coastguard Worker } 101*890232f2SAndroid Build Coastguard Worker final utf8String = utf8.encode(value); 102*890232f2SAndroid Build Coastguard Worker final length = utf8String.length; 103*890232f2SAndroid Build Coastguard Worker final bitWidth = BitWidthUtil.uwidth(length); 104*890232f2SAndroid Build Coastguard Worker final byteWidth = _align(bitWidth); 105*890232f2SAndroid Build Coastguard Worker _writeUInt(length, byteWidth); 106*890232f2SAndroid Build Coastguard Worker final stringOffset = _offset; 107*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(length + 1); 108*890232f2SAndroid Build Coastguard Worker _pushBuffer(utf8String); 109*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 110*890232f2SAndroid Build Coastguard Worker final stackValue = 111*890232f2SAndroid Build Coastguard Worker _StackValue.withOffset(stringOffset, ValueType.String, bitWidth); 112*890232f2SAndroid Build Coastguard Worker _stack.add(stackValue); 113*890232f2SAndroid Build Coastguard Worker _stringCache[value] = stackValue; 114*890232f2SAndroid Build Coastguard Worker } 115*890232f2SAndroid Build Coastguard Worker 116*890232f2SAndroid Build Coastguard Worker /// This methods adds a key to a map and should be followed by an add... value call. 117*890232f2SAndroid Build Coastguard Worker /// 118*890232f2SAndroid Build Coastguard Worker /// It also implies that you call this method only after you called [startMap]. 119*890232f2SAndroid Build Coastguard Worker void addKey(String value) { 120*890232f2SAndroid Build Coastguard Worker _integrityCheckOnKeyAddition(); 121*890232f2SAndroid Build Coastguard Worker if (_keyCache.containsKey(value)) { 122*890232f2SAndroid Build Coastguard Worker _stack.add(_keyCache[value]!); 123*890232f2SAndroid Build Coastguard Worker return; 124*890232f2SAndroid Build Coastguard Worker } 125*890232f2SAndroid Build Coastguard Worker final utf8String = utf8.encode(value); 126*890232f2SAndroid Build Coastguard Worker final length = utf8String.length; 127*890232f2SAndroid Build Coastguard Worker final keyOffset = _offset; 128*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(length + 1); 129*890232f2SAndroid Build Coastguard Worker _pushBuffer(utf8String); 130*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 131*890232f2SAndroid Build Coastguard Worker final stackValue = 132*890232f2SAndroid Build Coastguard Worker _StackValue.withOffset(keyOffset, ValueType.Key, BitWidth.width8); 133*890232f2SAndroid Build Coastguard Worker _stack.add(stackValue); 134*890232f2SAndroid Build Coastguard Worker _keyCache[value] = stackValue; 135*890232f2SAndroid Build Coastguard Worker } 136*890232f2SAndroid Build Coastguard Worker 137*890232f2SAndroid Build Coastguard Worker /// Adds a byte array. 138*890232f2SAndroid Build Coastguard Worker /// 139*890232f2SAndroid Build Coastguard Worker /// This method can be used to store any generic BLOB. 140*890232f2SAndroid Build Coastguard Worker void addBlob(ByteBuffer value) { 141*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 142*890232f2SAndroid Build Coastguard Worker final length = value.lengthInBytes; 143*890232f2SAndroid Build Coastguard Worker final bitWidth = BitWidthUtil.uwidth(length); 144*890232f2SAndroid Build Coastguard Worker final byteWidth = _align(bitWidth); 145*890232f2SAndroid Build Coastguard Worker _writeUInt(length, byteWidth); 146*890232f2SAndroid Build Coastguard Worker final blobOffset = _offset; 147*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(length); 148*890232f2SAndroid Build Coastguard Worker _pushBuffer(value.asUint8List()); 149*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 150*890232f2SAndroid Build Coastguard Worker final stackValue = 151*890232f2SAndroid Build Coastguard Worker _StackValue.withOffset(blobOffset, ValueType.Blob, bitWidth); 152*890232f2SAndroid Build Coastguard Worker _stack.add(stackValue); 153*890232f2SAndroid Build Coastguard Worker } 154*890232f2SAndroid Build Coastguard Worker 155*890232f2SAndroid Build Coastguard Worker /// Stores int value indirectly in the buffer. 156*890232f2SAndroid Build Coastguard Worker /// 157*890232f2SAndroid Build Coastguard Worker /// Adding large integer values indirectly might be beneficial if those values suppose to be store in a vector together with small integer values. 158*890232f2SAndroid Build Coastguard Worker /// This is due to the fact that FlexBuffers will add padding to small integer values, if they are stored together with large integer values. 159*890232f2SAndroid Build Coastguard Worker /// When we add integer indirectly the vector of ints will contain not the value itself, but only the relative offset to the value. 160*890232f2SAndroid Build Coastguard Worker /// By setting the [cache] parameter to true, you make sure that the builder tracks added int value and performs deduplication. 161*890232f2SAndroid Build Coastguard Worker void addIntIndirectly(int value, {bool cache = false}) { 162*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 163*890232f2SAndroid Build Coastguard Worker if (_indirectIntCache.containsKey(value)) { 164*890232f2SAndroid Build Coastguard Worker _stack.add(_indirectIntCache[value]!); 165*890232f2SAndroid Build Coastguard Worker return; 166*890232f2SAndroid Build Coastguard Worker } 167*890232f2SAndroid Build Coastguard Worker final stackValue = _StackValue.withInt(value); 168*890232f2SAndroid Build Coastguard Worker final byteWidth = _align(stackValue.width); 169*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(byteWidth); 170*890232f2SAndroid Build Coastguard Worker final valueOffset = _offset; 171*890232f2SAndroid Build Coastguard Worker _pushBuffer(stackValue.asU8List(stackValue.width)); 172*890232f2SAndroid Build Coastguard Worker final stackOffset = _StackValue.withOffset( 173*890232f2SAndroid Build Coastguard Worker valueOffset, ValueType.IndirectInt, stackValue.width); 174*890232f2SAndroid Build Coastguard Worker _stack.add(stackOffset); 175*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 176*890232f2SAndroid Build Coastguard Worker if (cache) { 177*890232f2SAndroid Build Coastguard Worker _indirectIntCache[value] = stackOffset; 178*890232f2SAndroid Build Coastguard Worker } 179*890232f2SAndroid Build Coastguard Worker } 180*890232f2SAndroid Build Coastguard Worker 181*890232f2SAndroid Build Coastguard Worker /// Stores double value indirectly in the buffer. 182*890232f2SAndroid Build Coastguard Worker /// 183*890232f2SAndroid Build Coastguard Worker /// Double are stored as 8 or 4 byte values in FlexBuffers. If they are stored in a mixed vector, values which are smaller than 4 / 8 bytes will be padded. 184*890232f2SAndroid Build Coastguard Worker /// When we add double indirectly, the vector will contain not the value itself, but only the relative offset to the value. Which could occupy only 1 or 2 bytes, reducing the odds for unnecessary padding. 185*890232f2SAndroid Build Coastguard Worker /// By setting the [cache] parameter to true, you make sure that the builder tracks already added double value and performs deduplication. 186*890232f2SAndroid Build Coastguard Worker void addDoubleIndirectly(double value, {bool cache = false}) { 187*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 188*890232f2SAndroid Build Coastguard Worker if (cache && _indirectDoubleCache.containsKey(value)) { 189*890232f2SAndroid Build Coastguard Worker _stack.add(_indirectDoubleCache[value]!); 190*890232f2SAndroid Build Coastguard Worker return; 191*890232f2SAndroid Build Coastguard Worker } 192*890232f2SAndroid Build Coastguard Worker final stackValue = _StackValue.withDouble(value); 193*890232f2SAndroid Build Coastguard Worker final byteWidth = _align(stackValue.width); 194*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(byteWidth); 195*890232f2SAndroid Build Coastguard Worker final valueOffset = _offset; 196*890232f2SAndroid Build Coastguard Worker _pushBuffer(stackValue.asU8List(stackValue.width)); 197*890232f2SAndroid Build Coastguard Worker final stackOffset = _StackValue.withOffset( 198*890232f2SAndroid Build Coastguard Worker valueOffset, ValueType.IndirectFloat, stackValue.width); 199*890232f2SAndroid Build Coastguard Worker _stack.add(stackOffset); 200*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 201*890232f2SAndroid Build Coastguard Worker if (cache) { 202*890232f2SAndroid Build Coastguard Worker _indirectDoubleCache[value] = stackOffset; 203*890232f2SAndroid Build Coastguard Worker } 204*890232f2SAndroid Build Coastguard Worker } 205*890232f2SAndroid Build Coastguard Worker 206*890232f2SAndroid Build Coastguard Worker /// This method starts a vector definition and needs to be followed by 0 to n add... value calls. 207*890232f2SAndroid Build Coastguard Worker /// 208*890232f2SAndroid Build Coastguard Worker /// The vector definition needs to be finished with an [end] call. 209*890232f2SAndroid Build Coastguard Worker /// It is also possible to add nested vector or map by calling [startVector] / [startMap]. 210*890232f2SAndroid Build Coastguard Worker void startVector() { 211*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 212*890232f2SAndroid Build Coastguard Worker _stackPointers.add(_StackPointer(_stack.length, true)); 213*890232f2SAndroid Build Coastguard Worker } 214*890232f2SAndroid Build Coastguard Worker 215*890232f2SAndroid Build Coastguard Worker /// This method starts a map definition. 216*890232f2SAndroid Build Coastguard Worker /// 217*890232f2SAndroid Build Coastguard Worker /// This method call needs to be followed by 0 to n [addKey] + add... value calls. 218*890232f2SAndroid Build Coastguard Worker /// The map definition needs to be finished with an [end] call. 219*890232f2SAndroid Build Coastguard Worker /// It is also possible to add nested vector or map by calling [startVector] / [startMap] after calling [addKey]. 220*890232f2SAndroid Build Coastguard Worker void startMap() { 221*890232f2SAndroid Build Coastguard Worker _integrityCheckOnValueAddition(); 222*890232f2SAndroid Build Coastguard Worker _stackPointers.add(_StackPointer(_stack.length, false)); 223*890232f2SAndroid Build Coastguard Worker } 224*890232f2SAndroid Build Coastguard Worker 225*890232f2SAndroid Build Coastguard Worker /// Marks that the addition of values to the last vector, or map have ended. 226*890232f2SAndroid Build Coastguard Worker void end() { 227*890232f2SAndroid Build Coastguard Worker final pointer = _stackPointers.removeLast(); 228*890232f2SAndroid Build Coastguard Worker if (pointer.isVector) { 229*890232f2SAndroid Build Coastguard Worker _endVector(pointer); 230*890232f2SAndroid Build Coastguard Worker } else { 231*890232f2SAndroid Build Coastguard Worker _sortKeysAndEndMap(pointer); 232*890232f2SAndroid Build Coastguard Worker } 233*890232f2SAndroid Build Coastguard Worker } 234*890232f2SAndroid Build Coastguard Worker 235*890232f2SAndroid Build Coastguard Worker /// Finish building the FlatBuffer and return array of bytes. 236*890232f2SAndroid Build Coastguard Worker /// 237*890232f2SAndroid Build Coastguard Worker /// Can be called multiple times, to get the array of bytes. 238*890232f2SAndroid Build Coastguard Worker /// After the first call, adding values, or starting vectors / maps will result in an exception. 239*890232f2SAndroid Build Coastguard Worker Uint8List finish() { 240*890232f2SAndroid Build Coastguard Worker if (_finished == false) { 241*890232f2SAndroid Build Coastguard Worker _finish(); 242*890232f2SAndroid Build Coastguard Worker } 243*890232f2SAndroid Build Coastguard Worker return _buffer.buffer.asUint8List(0, _offset); 244*890232f2SAndroid Build Coastguard Worker } 245*890232f2SAndroid Build Coastguard Worker 246*890232f2SAndroid Build Coastguard Worker /// Builds a FlatBuffer with current state without finishing the builder. 247*890232f2SAndroid Build Coastguard Worker /// 248*890232f2SAndroid Build Coastguard Worker /// Creates an internal temporary copy of current builder and finishes the copy. 249*890232f2SAndroid Build Coastguard Worker /// Use this method, when the state of a long lasting builder need to be persisted periodically. 250*890232f2SAndroid Build Coastguard Worker ByteBuffer snapshot() { 251*890232f2SAndroid Build Coastguard Worker final tmp = Builder(size: _offset + 200); 252*890232f2SAndroid Build Coastguard Worker tmp._offset = _offset; 253*890232f2SAndroid Build Coastguard Worker tmp._stack = List.from(_stack); 254*890232f2SAndroid Build Coastguard Worker tmp._stackPointers = List.from(_stackPointers); 255*890232f2SAndroid Build Coastguard Worker tmp._buffer.buffer 256*890232f2SAndroid Build Coastguard Worker .asUint8List() 257*890232f2SAndroid Build Coastguard Worker .setAll(0, _buffer.buffer.asUint8List(0, _offset)); 258*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < tmp._stackPointers.length; i++) { 259*890232f2SAndroid Build Coastguard Worker tmp.end(); 260*890232f2SAndroid Build Coastguard Worker } 261*890232f2SAndroid Build Coastguard Worker final buffer = tmp.finish(); 262*890232f2SAndroid Build Coastguard Worker final bd = ByteData(buffer.lengthInBytes); 263*890232f2SAndroid Build Coastguard Worker bd.buffer.asUint8List().setAll(0, buffer); 264*890232f2SAndroid Build Coastguard Worker return bd.buffer; 265*890232f2SAndroid Build Coastguard Worker } 266*890232f2SAndroid Build Coastguard Worker 267*890232f2SAndroid Build Coastguard Worker void _integrityCheckOnValueAddition() { 268*890232f2SAndroid Build Coastguard Worker if (_finished) { 269*890232f2SAndroid Build Coastguard Worker throw StateError('Adding values after finish is prohibited'); 270*890232f2SAndroid Build Coastguard Worker } 271*890232f2SAndroid Build Coastguard Worker if (_stackPointers.isNotEmpty && _stackPointers.last.isVector == false) { 272*890232f2SAndroid Build Coastguard Worker if (_stack.last.type != ValueType.Key) { 273*890232f2SAndroid Build Coastguard Worker throw StateError( 274*890232f2SAndroid Build Coastguard Worker 'Adding value to a map before adding a key is prohibited'); 275*890232f2SAndroid Build Coastguard Worker } 276*890232f2SAndroid Build Coastguard Worker } 277*890232f2SAndroid Build Coastguard Worker } 278*890232f2SAndroid Build Coastguard Worker 279*890232f2SAndroid Build Coastguard Worker void _integrityCheckOnKeyAddition() { 280*890232f2SAndroid Build Coastguard Worker if (_finished) { 281*890232f2SAndroid Build Coastguard Worker throw StateError('Adding values after finish is prohibited'); 282*890232f2SAndroid Build Coastguard Worker } 283*890232f2SAndroid Build Coastguard Worker if (_stackPointers.isEmpty || _stackPointers.last.isVector) { 284*890232f2SAndroid Build Coastguard Worker throw StateError('Adding key before staring a map is prohibited'); 285*890232f2SAndroid Build Coastguard Worker } 286*890232f2SAndroid Build Coastguard Worker } 287*890232f2SAndroid Build Coastguard Worker 288*890232f2SAndroid Build Coastguard Worker void _finish() { 289*890232f2SAndroid Build Coastguard Worker if (_stack.length != 1) { 290*890232f2SAndroid Build Coastguard Worker throw StateError( 291*890232f2SAndroid Build Coastguard Worker 'Stack has to be exactly 1, but is ${_stack.length}. You have to end all started vectors and maps, before calling [finish]'); 292*890232f2SAndroid Build Coastguard Worker } 293*890232f2SAndroid Build Coastguard Worker final value = _stack[0]; 294*890232f2SAndroid Build Coastguard Worker final byteWidth = _align(value.elementWidth(_offset, 0)); 295*890232f2SAndroid Build Coastguard Worker _writeStackValue(value, byteWidth); 296*890232f2SAndroid Build Coastguard Worker _writeUInt(value.storedPackedType(), 1); 297*890232f2SAndroid Build Coastguard Worker _writeUInt(byteWidth, 1); 298*890232f2SAndroid Build Coastguard Worker _finished = true; 299*890232f2SAndroid Build Coastguard Worker } 300*890232f2SAndroid Build Coastguard Worker 301*890232f2SAndroid Build Coastguard Worker _StackValue _createVector(int start, int vecLength, int step, 302*890232f2SAndroid Build Coastguard Worker [_StackValue? keys]) { 303*890232f2SAndroid Build Coastguard Worker var bitWidth = BitWidthUtil.uwidth(vecLength); 304*890232f2SAndroid Build Coastguard Worker var prefixElements = 1; 305*890232f2SAndroid Build Coastguard Worker if (keys != null) { 306*890232f2SAndroid Build Coastguard Worker var elemWidth = keys.elementWidth(_offset, 0); 307*890232f2SAndroid Build Coastguard Worker if (elemWidth.index > bitWidth.index) { 308*890232f2SAndroid Build Coastguard Worker bitWidth = elemWidth; 309*890232f2SAndroid Build Coastguard Worker } 310*890232f2SAndroid Build Coastguard Worker prefixElements += 2; 311*890232f2SAndroid Build Coastguard Worker } 312*890232f2SAndroid Build Coastguard Worker var vectorType = ValueType.Key; 313*890232f2SAndroid Build Coastguard Worker var typed = keys == null; 314*890232f2SAndroid Build Coastguard Worker for (var i = start; i < _stack.length; i += step) { 315*890232f2SAndroid Build Coastguard Worker final elemWidth = _stack[i].elementWidth(_offset, i + prefixElements); 316*890232f2SAndroid Build Coastguard Worker if (elemWidth.index > bitWidth.index) { 317*890232f2SAndroid Build Coastguard Worker bitWidth = elemWidth; 318*890232f2SAndroid Build Coastguard Worker } 319*890232f2SAndroid Build Coastguard Worker if (i == start) { 320*890232f2SAndroid Build Coastguard Worker vectorType = _stack[i].type; 321*890232f2SAndroid Build Coastguard Worker typed &= ValueTypeUtils.isTypedVectorElement(vectorType); 322*890232f2SAndroid Build Coastguard Worker } else { 323*890232f2SAndroid Build Coastguard Worker if (vectorType != _stack[i].type) { 324*890232f2SAndroid Build Coastguard Worker typed = false; 325*890232f2SAndroid Build Coastguard Worker } 326*890232f2SAndroid Build Coastguard Worker } 327*890232f2SAndroid Build Coastguard Worker } 328*890232f2SAndroid Build Coastguard Worker final byteWidth = _align(bitWidth); 329*890232f2SAndroid Build Coastguard Worker final fix = typed & ValueTypeUtils.isNumber(vectorType) && 330*890232f2SAndroid Build Coastguard Worker vecLength >= 2 && 331*890232f2SAndroid Build Coastguard Worker vecLength <= 4; 332*890232f2SAndroid Build Coastguard Worker if (keys != null) { 333*890232f2SAndroid Build Coastguard Worker _writeStackValue(keys, byteWidth); 334*890232f2SAndroid Build Coastguard Worker _writeUInt(1 << keys.width.index, byteWidth); 335*890232f2SAndroid Build Coastguard Worker } 336*890232f2SAndroid Build Coastguard Worker if (fix == false) { 337*890232f2SAndroid Build Coastguard Worker _writeUInt(vecLength, byteWidth); 338*890232f2SAndroid Build Coastguard Worker } 339*890232f2SAndroid Build Coastguard Worker final vecOffset = _offset; 340*890232f2SAndroid Build Coastguard Worker for (var i = start; i < _stack.length; i += step) { 341*890232f2SAndroid Build Coastguard Worker _writeStackValue(_stack[i], byteWidth); 342*890232f2SAndroid Build Coastguard Worker } 343*890232f2SAndroid Build Coastguard Worker if (typed == false) { 344*890232f2SAndroid Build Coastguard Worker for (var i = start; i < _stack.length; i += step) { 345*890232f2SAndroid Build Coastguard Worker _writeUInt(_stack[i].storedPackedType(), 1); 346*890232f2SAndroid Build Coastguard Worker } 347*890232f2SAndroid Build Coastguard Worker } 348*890232f2SAndroid Build Coastguard Worker if (keys != null) { 349*890232f2SAndroid Build Coastguard Worker return _StackValue.withOffset(vecOffset, ValueType.Map, bitWidth); 350*890232f2SAndroid Build Coastguard Worker } 351*890232f2SAndroid Build Coastguard Worker if (typed) { 352*890232f2SAndroid Build Coastguard Worker final vType = 353*890232f2SAndroid Build Coastguard Worker ValueTypeUtils.toTypedVector(vectorType, fix ? vecLength : 0); 354*890232f2SAndroid Build Coastguard Worker return _StackValue.withOffset(vecOffset, vType, bitWidth); 355*890232f2SAndroid Build Coastguard Worker } 356*890232f2SAndroid Build Coastguard Worker return _StackValue.withOffset(vecOffset, ValueType.Vector, bitWidth); 357*890232f2SAndroid Build Coastguard Worker } 358*890232f2SAndroid Build Coastguard Worker 359*890232f2SAndroid Build Coastguard Worker void _endVector(_StackPointer pointer) { 360*890232f2SAndroid Build Coastguard Worker final vecLength = _stack.length - pointer.stackPosition; 361*890232f2SAndroid Build Coastguard Worker final vec = _createVector(pointer.stackPosition, vecLength, 1); 362*890232f2SAndroid Build Coastguard Worker _stack.removeRange(pointer.stackPosition, _stack.length); 363*890232f2SAndroid Build Coastguard Worker _stack.add(vec); 364*890232f2SAndroid Build Coastguard Worker } 365*890232f2SAndroid Build Coastguard Worker 366*890232f2SAndroid Build Coastguard Worker void _sortKeysAndEndMap(_StackPointer pointer) { 367*890232f2SAndroid Build Coastguard Worker if (((_stack.length - pointer.stackPosition) & 1) == 1) { 368*890232f2SAndroid Build Coastguard Worker throw StateError( 369*890232f2SAndroid Build Coastguard Worker 'The stack needs to hold key value pairs (even number of elements). Check if you combined [addKey] with add... method calls properly.'); 370*890232f2SAndroid Build Coastguard Worker } 371*890232f2SAndroid Build Coastguard Worker 372*890232f2SAndroid Build Coastguard Worker var sorted = true; 373*890232f2SAndroid Build Coastguard Worker for (var i = pointer.stackPosition; i < _stack.length - 2; i += 2) { 374*890232f2SAndroid Build Coastguard Worker if (_shouldFlip(_stack[i], _stack[i + 2])) { 375*890232f2SAndroid Build Coastguard Worker sorted = false; 376*890232f2SAndroid Build Coastguard Worker break; 377*890232f2SAndroid Build Coastguard Worker } 378*890232f2SAndroid Build Coastguard Worker } 379*890232f2SAndroid Build Coastguard Worker 380*890232f2SAndroid Build Coastguard Worker if (sorted == false) { 381*890232f2SAndroid Build Coastguard Worker for (var i = pointer.stackPosition; i < _stack.length; i += 2) { 382*890232f2SAndroid Build Coastguard Worker var flipIndex = i; 383*890232f2SAndroid Build Coastguard Worker for (var j = i + 2; j < _stack.length; j += 2) { 384*890232f2SAndroid Build Coastguard Worker if (_shouldFlip(_stack[flipIndex], _stack[j])) { 385*890232f2SAndroid Build Coastguard Worker flipIndex = j; 386*890232f2SAndroid Build Coastguard Worker } 387*890232f2SAndroid Build Coastguard Worker } 388*890232f2SAndroid Build Coastguard Worker if (flipIndex != i) { 389*890232f2SAndroid Build Coastguard Worker var k = _stack[flipIndex]; 390*890232f2SAndroid Build Coastguard Worker var v = _stack[flipIndex + 1]; 391*890232f2SAndroid Build Coastguard Worker _stack[flipIndex] = _stack[i]; 392*890232f2SAndroid Build Coastguard Worker _stack[flipIndex + 1] = _stack[i + 1]; 393*890232f2SAndroid Build Coastguard Worker _stack[i] = k; 394*890232f2SAndroid Build Coastguard Worker _stack[i + 1] = v; 395*890232f2SAndroid Build Coastguard Worker } 396*890232f2SAndroid Build Coastguard Worker } 397*890232f2SAndroid Build Coastguard Worker } 398*890232f2SAndroid Build Coastguard Worker _endMap(pointer); 399*890232f2SAndroid Build Coastguard Worker } 400*890232f2SAndroid Build Coastguard Worker 401*890232f2SAndroid Build Coastguard Worker void _endMap(_StackPointer pointer) { 402*890232f2SAndroid Build Coastguard Worker final vecLength = (_stack.length - pointer.stackPosition) >> 1; 403*890232f2SAndroid Build Coastguard Worker final offsets = <int>[]; 404*890232f2SAndroid Build Coastguard Worker for (var i = pointer.stackPosition; i < _stack.length; i += 2) { 405*890232f2SAndroid Build Coastguard Worker offsets.add(_stack[i].offset!); 406*890232f2SAndroid Build Coastguard Worker } 407*890232f2SAndroid Build Coastguard Worker final keysHash = _KeysHash(offsets); 408*890232f2SAndroid Build Coastguard Worker _StackValue? keysStackValue; 409*890232f2SAndroid Build Coastguard Worker if (_keyVectorCache.containsKey(keysHash)) { 410*890232f2SAndroid Build Coastguard Worker keysStackValue = _keyVectorCache[keysHash]; 411*890232f2SAndroid Build Coastguard Worker } else { 412*890232f2SAndroid Build Coastguard Worker keysStackValue = _createVector(pointer.stackPosition, vecLength, 2); 413*890232f2SAndroid Build Coastguard Worker _keyVectorCache[keysHash] = keysStackValue; 414*890232f2SAndroid Build Coastguard Worker } 415*890232f2SAndroid Build Coastguard Worker final vec = 416*890232f2SAndroid Build Coastguard Worker _createVector(pointer.stackPosition + 1, vecLength, 2, keysStackValue); 417*890232f2SAndroid Build Coastguard Worker _stack.removeRange(pointer.stackPosition, _stack.length); 418*890232f2SAndroid Build Coastguard Worker _stack.add(vec); 419*890232f2SAndroid Build Coastguard Worker } 420*890232f2SAndroid Build Coastguard Worker 421*890232f2SAndroid Build Coastguard Worker bool _shouldFlip(_StackValue v1, _StackValue v2) { 422*890232f2SAndroid Build Coastguard Worker if (v1.type != ValueType.Key || v2.type != ValueType.Key) { 423*890232f2SAndroid Build Coastguard Worker throw StateError( 424*890232f2SAndroid Build Coastguard Worker 'Stack values are not keys $v1 | $v2. Check if you combined [addKey] with add... method calls properly.'); 425*890232f2SAndroid Build Coastguard Worker } 426*890232f2SAndroid Build Coastguard Worker 427*890232f2SAndroid Build Coastguard Worker late int c1, c2; 428*890232f2SAndroid Build Coastguard Worker var index = 0; 429*890232f2SAndroid Build Coastguard Worker do { 430*890232f2SAndroid Build Coastguard Worker c1 = _buffer.getUint8(v1.offset! + index); 431*890232f2SAndroid Build Coastguard Worker c2 = _buffer.getUint8(v2.offset! + index); 432*890232f2SAndroid Build Coastguard Worker if (c2 < c1) return true; 433*890232f2SAndroid Build Coastguard Worker if (c1 < c2) return false; 434*890232f2SAndroid Build Coastguard Worker index += 1; 435*890232f2SAndroid Build Coastguard Worker } while (c1 != 0 && c2 != 0); 436*890232f2SAndroid Build Coastguard Worker return false; 437*890232f2SAndroid Build Coastguard Worker } 438*890232f2SAndroid Build Coastguard Worker 439*890232f2SAndroid Build Coastguard Worker int _align(BitWidth width) { 440*890232f2SAndroid Build Coastguard Worker final byteWidth = BitWidthUtil.toByteWidth(width); 441*890232f2SAndroid Build Coastguard Worker _offset += BitWidthUtil.paddingSize(_offset, byteWidth); 442*890232f2SAndroid Build Coastguard Worker return byteWidth; 443*890232f2SAndroid Build Coastguard Worker } 444*890232f2SAndroid Build Coastguard Worker 445*890232f2SAndroid Build Coastguard Worker void _writeStackValue(_StackValue value, int byteWidth) { 446*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(byteWidth); 447*890232f2SAndroid Build Coastguard Worker if (value.isOffset) { 448*890232f2SAndroid Build Coastguard Worker final relativeOffset = _offset - value.offset!; 449*890232f2SAndroid Build Coastguard Worker if (byteWidth == 8 || relativeOffset < (1 << (byteWidth * 8))) { 450*890232f2SAndroid Build Coastguard Worker _writeUInt(relativeOffset, byteWidth); 451*890232f2SAndroid Build Coastguard Worker } else { 452*890232f2SAndroid Build Coastguard Worker throw StateError( 453*890232f2SAndroid Build Coastguard Worker 'Unexpected size $byteWidth. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new'); 454*890232f2SAndroid Build Coastguard Worker } 455*890232f2SAndroid Build Coastguard Worker } else { 456*890232f2SAndroid Build Coastguard Worker _pushBuffer(value.asU8List(BitWidthUtil.fromByteWidth(byteWidth))); 457*890232f2SAndroid Build Coastguard Worker } 458*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 459*890232f2SAndroid Build Coastguard Worker } 460*890232f2SAndroid Build Coastguard Worker 461*890232f2SAndroid Build Coastguard Worker void _writeUInt(int value, int byteWidth) { 462*890232f2SAndroid Build Coastguard Worker final newOffset = _newOffset(byteWidth); 463*890232f2SAndroid Build Coastguard Worker _pushUInt(value, BitWidthUtil.fromByteWidth(byteWidth)); 464*890232f2SAndroid Build Coastguard Worker _offset = newOffset; 465*890232f2SAndroid Build Coastguard Worker } 466*890232f2SAndroid Build Coastguard Worker 467*890232f2SAndroid Build Coastguard Worker int _newOffset(int newValueSize) { 468*890232f2SAndroid Build Coastguard Worker final newOffset = _offset + newValueSize; 469*890232f2SAndroid Build Coastguard Worker var size = _buffer.lengthInBytes; 470*890232f2SAndroid Build Coastguard Worker final prevSize = size; 471*890232f2SAndroid Build Coastguard Worker while (size < newOffset) { 472*890232f2SAndroid Build Coastguard Worker size <<= 1; 473*890232f2SAndroid Build Coastguard Worker } 474*890232f2SAndroid Build Coastguard Worker if (prevSize < size) { 475*890232f2SAndroid Build Coastguard Worker final newBuf = ByteData(size); 476*890232f2SAndroid Build Coastguard Worker newBuf.buffer.asUint8List().setAll(0, _buffer.buffer.asUint8List()); 477*890232f2SAndroid Build Coastguard Worker } 478*890232f2SAndroid Build Coastguard Worker return newOffset; 479*890232f2SAndroid Build Coastguard Worker } 480*890232f2SAndroid Build Coastguard Worker 481*890232f2SAndroid Build Coastguard Worker void _pushInt(int value, BitWidth width) { 482*890232f2SAndroid Build Coastguard Worker switch (width) { 483*890232f2SAndroid Build Coastguard Worker case BitWidth.width8: 484*890232f2SAndroid Build Coastguard Worker _buffer.setInt8(_offset, value); 485*890232f2SAndroid Build Coastguard Worker break; 486*890232f2SAndroid Build Coastguard Worker case BitWidth.width16: 487*890232f2SAndroid Build Coastguard Worker _buffer.setInt16(_offset, value, Endian.little); 488*890232f2SAndroid Build Coastguard Worker break; 489*890232f2SAndroid Build Coastguard Worker case BitWidth.width32: 490*890232f2SAndroid Build Coastguard Worker _buffer.setInt32(_offset, value, Endian.little); 491*890232f2SAndroid Build Coastguard Worker break; 492*890232f2SAndroid Build Coastguard Worker case BitWidth.width64: 493*890232f2SAndroid Build Coastguard Worker _buffer.setInt64(_offset, value, Endian.little); 494*890232f2SAndroid Build Coastguard Worker break; 495*890232f2SAndroid Build Coastguard Worker } 496*890232f2SAndroid Build Coastguard Worker } 497*890232f2SAndroid Build Coastguard Worker 498*890232f2SAndroid Build Coastguard Worker void _pushUInt(int value, BitWidth width) { 499*890232f2SAndroid Build Coastguard Worker switch (width) { 500*890232f2SAndroid Build Coastguard Worker case BitWidth.width8: 501*890232f2SAndroid Build Coastguard Worker _buffer.setUint8(_offset, value); 502*890232f2SAndroid Build Coastguard Worker break; 503*890232f2SAndroid Build Coastguard Worker case BitWidth.width16: 504*890232f2SAndroid Build Coastguard Worker _buffer.setUint16(_offset, value, Endian.little); 505*890232f2SAndroid Build Coastguard Worker break; 506*890232f2SAndroid Build Coastguard Worker case BitWidth.width32: 507*890232f2SAndroid Build Coastguard Worker _buffer.setUint32(_offset, value, Endian.little); 508*890232f2SAndroid Build Coastguard Worker break; 509*890232f2SAndroid Build Coastguard Worker case BitWidth.width64: 510*890232f2SAndroid Build Coastguard Worker _buffer.setUint64(_offset, value, Endian.little); 511*890232f2SAndroid Build Coastguard Worker break; 512*890232f2SAndroid Build Coastguard Worker } 513*890232f2SAndroid Build Coastguard Worker } 514*890232f2SAndroid Build Coastguard Worker 515*890232f2SAndroid Build Coastguard Worker void _pushBuffer(List<int> value) { 516*890232f2SAndroid Build Coastguard Worker _buffer.buffer.asUint8List().setAll(_offset, value); 517*890232f2SAndroid Build Coastguard Worker } 518*890232f2SAndroid Build Coastguard Worker} 519*890232f2SAndroid Build Coastguard Worker 520*890232f2SAndroid Build Coastguard Workerclass _StackValue { 521*890232f2SAndroid Build Coastguard Worker late Object _value; 522*890232f2SAndroid Build Coastguard Worker int? _offset; 523*890232f2SAndroid Build Coastguard Worker final ValueType _type; 524*890232f2SAndroid Build Coastguard Worker final BitWidth _width; 525*890232f2SAndroid Build Coastguard Worker 526*890232f2SAndroid Build Coastguard Worker _StackValue.withNull() 527*890232f2SAndroid Build Coastguard Worker : _type = ValueType.Null, 528*890232f2SAndroid Build Coastguard Worker _width = BitWidth.width8; 529*890232f2SAndroid Build Coastguard Worker 530*890232f2SAndroid Build Coastguard Worker _StackValue.withInt(int value) 531*890232f2SAndroid Build Coastguard Worker : _type = ValueType.Int, 532*890232f2SAndroid Build Coastguard Worker _width = BitWidthUtil.width(value), 533*890232f2SAndroid Build Coastguard Worker _value = value; 534*890232f2SAndroid Build Coastguard Worker 535*890232f2SAndroid Build Coastguard Worker _StackValue.withBool(bool value) 536*890232f2SAndroid Build Coastguard Worker : _type = ValueType.Bool, 537*890232f2SAndroid Build Coastguard Worker _width = BitWidth.width8, 538*890232f2SAndroid Build Coastguard Worker _value = value; 539*890232f2SAndroid Build Coastguard Worker 540*890232f2SAndroid Build Coastguard Worker _StackValue.withDouble(double value) 541*890232f2SAndroid Build Coastguard Worker : _type = ValueType.Float, 542*890232f2SAndroid Build Coastguard Worker _width = BitWidthUtil.width(value), 543*890232f2SAndroid Build Coastguard Worker _value = value; 544*890232f2SAndroid Build Coastguard Worker 545*890232f2SAndroid Build Coastguard Worker _StackValue.withOffset(int value, ValueType type, BitWidth width) 546*890232f2SAndroid Build Coastguard Worker : _offset = value, 547*890232f2SAndroid Build Coastguard Worker _type = type, 548*890232f2SAndroid Build Coastguard Worker _width = width; 549*890232f2SAndroid Build Coastguard Worker 550*890232f2SAndroid Build Coastguard Worker BitWidth storedWidth({BitWidth width = BitWidth.width8}) { 551*890232f2SAndroid Build Coastguard Worker return ValueTypeUtils.isInline(_type) 552*890232f2SAndroid Build Coastguard Worker ? BitWidthUtil.max(_width, width) 553*890232f2SAndroid Build Coastguard Worker : _width; 554*890232f2SAndroid Build Coastguard Worker } 555*890232f2SAndroid Build Coastguard Worker 556*890232f2SAndroid Build Coastguard Worker int storedPackedType({BitWidth width = BitWidth.width8}) { 557*890232f2SAndroid Build Coastguard Worker return ValueTypeUtils.packedType(_type, storedWidth(width: width)); 558*890232f2SAndroid Build Coastguard Worker } 559*890232f2SAndroid Build Coastguard Worker 560*890232f2SAndroid Build Coastguard Worker BitWidth elementWidth(int size, int index) { 561*890232f2SAndroid Build Coastguard Worker if (ValueTypeUtils.isInline(_type)) return _width; 562*890232f2SAndroid Build Coastguard Worker final offset = _offset!; 563*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < 4; i++) { 564*890232f2SAndroid Build Coastguard Worker final width = 1 << i; 565*890232f2SAndroid Build Coastguard Worker final bitWidth = BitWidthUtil.uwidth(size + 566*890232f2SAndroid Build Coastguard Worker BitWidthUtil.paddingSize(size, width) + 567*890232f2SAndroid Build Coastguard Worker index * width - 568*890232f2SAndroid Build Coastguard Worker offset); 569*890232f2SAndroid Build Coastguard Worker if (1 << bitWidth.index == width) { 570*890232f2SAndroid Build Coastguard Worker return bitWidth; 571*890232f2SAndroid Build Coastguard Worker } 572*890232f2SAndroid Build Coastguard Worker } 573*890232f2SAndroid Build Coastguard Worker throw StateError( 574*890232f2SAndroid Build Coastguard Worker 'Element is of unknown. Size: $size at index: $index. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new'); 575*890232f2SAndroid Build Coastguard Worker } 576*890232f2SAndroid Build Coastguard Worker 577*890232f2SAndroid Build Coastguard Worker List<int> asU8List(BitWidth width) { 578*890232f2SAndroid Build Coastguard Worker if (ValueTypeUtils.isNumber(_type)) { 579*890232f2SAndroid Build Coastguard Worker if (_type == ValueType.Float) { 580*890232f2SAndroid Build Coastguard Worker if (width == BitWidth.width32) { 581*890232f2SAndroid Build Coastguard Worker final result = ByteData(4); 582*890232f2SAndroid Build Coastguard Worker result.setFloat32(0, _value as double, Endian.little); 583*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 584*890232f2SAndroid Build Coastguard Worker } else { 585*890232f2SAndroid Build Coastguard Worker final result = ByteData(8); 586*890232f2SAndroid Build Coastguard Worker result.setFloat64(0, _value as double, Endian.little); 587*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 588*890232f2SAndroid Build Coastguard Worker } 589*890232f2SAndroid Build Coastguard Worker } else { 590*890232f2SAndroid Build Coastguard Worker switch (width) { 591*890232f2SAndroid Build Coastguard Worker case BitWidth.width8: 592*890232f2SAndroid Build Coastguard Worker final result = ByteData(1); 593*890232f2SAndroid Build Coastguard Worker result.setInt8(0, _value as int); 594*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 595*890232f2SAndroid Build Coastguard Worker case BitWidth.width16: 596*890232f2SAndroid Build Coastguard Worker final result = ByteData(2); 597*890232f2SAndroid Build Coastguard Worker result.setInt16(0, _value as int, Endian.little); 598*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 599*890232f2SAndroid Build Coastguard Worker case BitWidth.width32: 600*890232f2SAndroid Build Coastguard Worker final result = ByteData(4); 601*890232f2SAndroid Build Coastguard Worker result.setInt32(0, _value as int, Endian.little); 602*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 603*890232f2SAndroid Build Coastguard Worker case BitWidth.width64: 604*890232f2SAndroid Build Coastguard Worker final result = ByteData(8); 605*890232f2SAndroid Build Coastguard Worker result.setInt64(0, _value as int, Endian.little); 606*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 607*890232f2SAndroid Build Coastguard Worker } 608*890232f2SAndroid Build Coastguard Worker } 609*890232f2SAndroid Build Coastguard Worker } 610*890232f2SAndroid Build Coastguard Worker if (_type == ValueType.Null) { 611*890232f2SAndroid Build Coastguard Worker final result = ByteData(1); 612*890232f2SAndroid Build Coastguard Worker result.setInt8(0, 0); 613*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 614*890232f2SAndroid Build Coastguard Worker } 615*890232f2SAndroid Build Coastguard Worker if (_type == ValueType.Bool) { 616*890232f2SAndroid Build Coastguard Worker final result = ByteData(1); 617*890232f2SAndroid Build Coastguard Worker result.setInt8(0, _value as bool ? 1 : 0); 618*890232f2SAndroid Build Coastguard Worker return result.buffer.asUint8List(); 619*890232f2SAndroid Build Coastguard Worker } 620*890232f2SAndroid Build Coastguard Worker 621*890232f2SAndroid Build Coastguard Worker throw StateError( 622*890232f2SAndroid Build Coastguard Worker 'Unexpected type: $_type. This might be a bug. Please create an issue https://github.com/google/flatbuffers/issues/new'); 623*890232f2SAndroid Build Coastguard Worker } 624*890232f2SAndroid Build Coastguard Worker 625*890232f2SAndroid Build Coastguard Worker ValueType get type { 626*890232f2SAndroid Build Coastguard Worker return _type; 627*890232f2SAndroid Build Coastguard Worker } 628*890232f2SAndroid Build Coastguard Worker 629*890232f2SAndroid Build Coastguard Worker BitWidth get width { 630*890232f2SAndroid Build Coastguard Worker return _width; 631*890232f2SAndroid Build Coastguard Worker } 632*890232f2SAndroid Build Coastguard Worker 633*890232f2SAndroid Build Coastguard Worker bool get isOffset { 634*890232f2SAndroid Build Coastguard Worker return !ValueTypeUtils.isInline(_type); 635*890232f2SAndroid Build Coastguard Worker } 636*890232f2SAndroid Build Coastguard Worker 637*890232f2SAndroid Build Coastguard Worker int? get offset => _offset; 638*890232f2SAndroid Build Coastguard Worker 639*890232f2SAndroid Build Coastguard Worker bool get isFloat32 { 640*890232f2SAndroid Build Coastguard Worker return _type == ValueType.Float && _width == BitWidth.width32; 641*890232f2SAndroid Build Coastguard Worker } 642*890232f2SAndroid Build Coastguard Worker} 643*890232f2SAndroid Build Coastguard Worker 644*890232f2SAndroid Build Coastguard Workerclass _StackPointer { 645*890232f2SAndroid Build Coastguard Worker int stackPosition; 646*890232f2SAndroid Build Coastguard Worker bool isVector; 647*890232f2SAndroid Build Coastguard Worker 648*890232f2SAndroid Build Coastguard Worker _StackPointer(this.stackPosition, this.isVector); 649*890232f2SAndroid Build Coastguard Worker} 650*890232f2SAndroid Build Coastguard Worker 651*890232f2SAndroid Build Coastguard Workerclass _KeysHash { 652*890232f2SAndroid Build Coastguard Worker final List<int> keys; 653*890232f2SAndroid Build Coastguard Worker 654*890232f2SAndroid Build Coastguard Worker const _KeysHash(this.keys); 655*890232f2SAndroid Build Coastguard Worker 656*890232f2SAndroid Build Coastguard Worker @override 657*890232f2SAndroid Build Coastguard Worker bool operator ==(Object other) { 658*890232f2SAndroid Build Coastguard Worker if (other is _KeysHash) { 659*890232f2SAndroid Build Coastguard Worker if (keys.length != other.keys.length) return false; 660*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < keys.length; i++) { 661*890232f2SAndroid Build Coastguard Worker if (keys[i] != other.keys[i]) return false; 662*890232f2SAndroid Build Coastguard Worker } 663*890232f2SAndroid Build Coastguard Worker return true; 664*890232f2SAndroid Build Coastguard Worker } 665*890232f2SAndroid Build Coastguard Worker return false; 666*890232f2SAndroid Build Coastguard Worker } 667*890232f2SAndroid Build Coastguard Worker 668*890232f2SAndroid Build Coastguard Worker @override 669*890232f2SAndroid Build Coastguard Worker int get hashCode { 670*890232f2SAndroid Build Coastguard Worker var result = 17; 671*890232f2SAndroid Build Coastguard Worker for (var i = 0; i < keys.length; i++) { 672*890232f2SAndroid Build Coastguard Worker result = result * 23 + keys[i]; 673*890232f2SAndroid Build Coastguard Worker } 674*890232f2SAndroid Build Coastguard Worker return result; 675*890232f2SAndroid Build Coastguard Worker } 676*890232f2SAndroid Build Coastguard Worker} 677