mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Add Float32List support to StandardMessageCodec (flutter/engine#26386)
This commit is contained in:
parent
78254e537a
commit
2438363a2e
@ -33,7 +33,7 @@ import java.util.Map.Entry;
|
||||
* <li>BigIntegers (see below)
|
||||
* <li>Floats, Doubles
|
||||
* <li>Strings
|
||||
* <li>byte[], int[], long[], double[]
|
||||
* <li>byte[], int[], long[], float[], double[]
|
||||
* <li>Lists of supported values
|
||||
* <li>Maps with supported keys and values
|
||||
* </ul>
|
||||
@ -49,6 +49,7 @@ import java.util.Map.Entry;
|
||||
* <li>byte[]: Uint8List
|
||||
* <li>int[]: Int32List
|
||||
* <li>long[]: Int64List
|
||||
* <li>float[]: Float32List
|
||||
* <li>double[]: Float64List
|
||||
* <li>List: List
|
||||
* <li>Map: Map
|
||||
@ -104,6 +105,7 @@ public class StandardMessageCodec implements MessageCodec<Object> {
|
||||
private static final byte DOUBLE_ARRAY = 11;
|
||||
private static final byte LIST = 12;
|
||||
private static final byte MAP = 13;
|
||||
private static final byte FLOAT_ARRAY = 14;
|
||||
|
||||
/**
|
||||
* Writes an int representing a size to the specified stream. Uses an expanding code of 1 to 5
|
||||
@ -173,6 +175,11 @@ public class StandardMessageCodec implements MessageCodec<Object> {
|
||||
}
|
||||
}
|
||||
|
||||
/** Writes the specified double as 4 bytes to the specified stream */
|
||||
protected static final void writeFloat(ByteArrayOutputStream stream, float value) {
|
||||
writeInt(stream, Float.floatToIntBits(value));
|
||||
}
|
||||
|
||||
/** Writes the specified double as 8 bytes to the specified stream. */
|
||||
protected static final void writeDouble(ByteArrayOutputStream stream, double value) {
|
||||
writeLong(stream, Double.doubleToLongBits(value));
|
||||
@ -272,6 +279,14 @@ public class StandardMessageCodec implements MessageCodec<Object> {
|
||||
writeValue(stream, entry.getKey());
|
||||
writeValue(stream, entry.getValue());
|
||||
}
|
||||
} else if (value instanceof float[]) {
|
||||
stream.write(FLOAT_ARRAY);
|
||||
final float[] array = (float[]) value;
|
||||
writeSize(stream, array.length);
|
||||
writeAlignment(stream, 4);
|
||||
for (final float f : array) {
|
||||
writeFloat(stream, f);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsupported value: " + value);
|
||||
}
|
||||
@ -412,6 +427,16 @@ public class StandardMessageCodec implements MessageCodec<Object> {
|
||||
result = map;
|
||||
break;
|
||||
}
|
||||
case FLOAT_ARRAY:
|
||||
{
|
||||
final int length = readSize(buffer);
|
||||
final float[] array = new float[length];
|
||||
readAlignment(buffer, 4);
|
||||
buffer.asFloatBuffer().get(array);
|
||||
result = array;
|
||||
buffer.position(buffer.position() + 4 * length);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new IllegalArgumentException("Message corrupted");
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package io.flutter.plugin.common;
|
||||
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
@ -28,6 +29,7 @@ public class StandardMessageCodecTest {
|
||||
private static final byte DOUBLE_ARRAY = 11;
|
||||
private static final byte LIST = 12;
|
||||
private static final byte MAP = 13;
|
||||
private static final byte FLOAT_ARRAY = 14;
|
||||
|
||||
@Test
|
||||
public void itEncodesNullLiterals() {
|
||||
@ -93,4 +95,17 @@ public class StandardMessageCodecTest {
|
||||
expected.flip();
|
||||
assertEquals(expected, message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void itEncodesFloatArrays() {
|
||||
StandardMessageCodec codec = new StandardMessageCodec();
|
||||
|
||||
float[] expectedValues = new float[] {1.0f, 2.2f, 5.3f};
|
||||
|
||||
ByteBuffer message = codec.encodeMessage(expectedValues);
|
||||
message.flip();
|
||||
|
||||
float[] values = (float[]) codec.decodeMessage(message);
|
||||
assertArrayEquals(expectedValues, values, 0.01f);
|
||||
}
|
||||
}
|
||||
|
||||
@ -217,6 +217,9 @@ TEST(EncodableValueTest, Comparison) {
|
||||
EncodableValue(
|
||||
EncodableMap{{EncodableValue(), EncodableValue(1.0)},
|
||||
{EncodableValue("key"), EncodableValue("value")}}),
|
||||
// FloatList
|
||||
EncodableValue(std::vector<float>{0, 1}),
|
||||
EncodableValue(std::vector<float>{0, 100}),
|
||||
};
|
||||
|
||||
for (size_t i = 0; i < values.size(); ++i) {
|
||||
|
||||
@ -110,6 +110,7 @@ using EncodableValueVariant = std::variant<std::monostate,
|
||||
std::vector<double>,
|
||||
EncodableList,
|
||||
EncodableMap,
|
||||
std::vector<float>,
|
||||
CustomEncodableValue>;
|
||||
} // namespace internal
|
||||
|
||||
@ -158,6 +159,7 @@ using EncodableValueVariant = std::variant<std::monostate,
|
||||
// std::vector<double> -> Float64List
|
||||
// EncodableList -> List
|
||||
// EncodableMap -> Map
|
||||
// std::vector<float> -> Float32List
|
||||
class EncodableValue : public internal::EncodableValueVariant {
|
||||
public:
|
||||
// Rely on std::variant for most of the constructors/operators.
|
||||
|
||||
@ -41,6 +41,7 @@ enum class EncodedType {
|
||||
kFloat64List,
|
||||
kList,
|
||||
kMap,
|
||||
kFloat32List,
|
||||
};
|
||||
|
||||
// Returns the encoded type that should be written when serializing |value|.
|
||||
@ -70,6 +71,8 @@ EncodedType EncodedTypeForValue(const EncodableValue& value) {
|
||||
return EncodedType::kList;
|
||||
case 11:
|
||||
return EncodedType::kMap;
|
||||
case 12:
|
||||
return EncodedType::kFloat32List;
|
||||
}
|
||||
assert(false);
|
||||
return EncodedType::kNull;
|
||||
@ -150,7 +153,11 @@ void StandardCodecSerializer::WriteValue(const EncodableValue& value,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 12:
|
||||
case 12: {
|
||||
WriteVector(std::get<std::vector<float>>(value), stream);
|
||||
break;
|
||||
}
|
||||
case 13:
|
||||
std::cerr
|
||||
<< "Unhandled custom type in StandardCodecSerializer::WriteValue. "
|
||||
<< "Custom types require codec extensions." << std::endl;
|
||||
@ -210,6 +217,9 @@ EncodableValue StandardCodecSerializer::ReadValueOfType(
|
||||
}
|
||||
return EncodableValue(map_value);
|
||||
}
|
||||
case EncodedType::kFloat32List: {
|
||||
return ReadVector<float>(stream);
|
||||
}
|
||||
}
|
||||
std::cerr << "Unknown type in StandardCodecSerializer::ReadValueOfType: "
|
||||
<< static_cast<int>(type) << std::endl;
|
||||
|
||||
@ -175,6 +175,13 @@ TEST(StandardMessageCodec, CanEncodeAndDecodeInt64Array) {
|
||||
CheckEncodeDecode(value, bytes);
|
||||
}
|
||||
|
||||
TEST(StandradMessageCodec, CanEncodeAndDecodeFloat32Array) {
|
||||
std::vector<uint8_t> bytes = {0x0e, 0x02, 0x00, 0x00, 0xd8, 0x0f,
|
||||
0x49, 0x40, 0x00, 0x00, 0x7a, 0x44};
|
||||
EncodableValue value(std::vector<float>{3.1415920257568359375f, 1000.0f});
|
||||
CheckEncodeDecode(value, bytes);
|
||||
}
|
||||
|
||||
TEST(StandardMessageCodec, CanEncodeAndDecodeFloat64Array) {
|
||||
std::vector<uint8_t> bytes = {0x0b, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x18, 0x2d, 0x44, 0x54, 0xfb, 0x21, 0x09, 0x40,
|
||||
|
||||
@ -282,6 +282,7 @@ typedef NS_ENUM(NSInteger, FlutterStandardDataType) {
|
||||
FlutterStandardDataTypeUInt8,
|
||||
FlutterStandardDataTypeInt32,
|
||||
FlutterStandardDataTypeInt64,
|
||||
FlutterStandardDataTypeFloat32,
|
||||
FlutterStandardDataTypeFloat64,
|
||||
};
|
||||
|
||||
@ -319,6 +320,14 @@ FLUTTER_DARWIN_EXPORT
|
||||
*/
|
||||
+ (instancetype)typedDataWithInt64:(NSData*)data;
|
||||
|
||||
/**
|
||||
* Creates a `FlutterStandardTypedData` which interprets the specified data
|
||||
* as 32-bit floats.
|
||||
*
|
||||
* @param data the byte data. The length must be divisible by 8.
|
||||
*/
|
||||
+ (instancetype)typedDataWithFloat32:(NSData*)data;
|
||||
|
||||
/**
|
||||
* Creates a `FlutterStandardTypedData` which interprets the specified data
|
||||
* as 64-bit floats.
|
||||
|
||||
@ -162,6 +162,10 @@ using namespace flutter;
|
||||
return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeInt64];
|
||||
}
|
||||
|
||||
+ (instancetype)typedDataWithFloat32:(NSData*)data {
|
||||
return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat32];
|
||||
}
|
||||
|
||||
+ (instancetype)typedDataWithFloat64:(NSData*)data {
|
||||
return [FlutterStandardTypedData typedDataWithData:data type:FlutterStandardDataTypeFloat64];
|
||||
}
|
||||
@ -443,6 +447,7 @@ using namespace flutter;
|
||||
case FlutterStandardFieldUInt8Data:
|
||||
case FlutterStandardFieldInt32Data:
|
||||
case FlutterStandardFieldInt64Data:
|
||||
case FlutterStandardFieldFloat32Data:
|
||||
case FlutterStandardFieldFloat64Data:
|
||||
return [self readTypedDataOfType:FlutterStandardDataTypeForField(field)];
|
||||
case FlutterStandardFieldList: {
|
||||
|
||||
@ -16,22 +16,47 @@ typedef NS_ENUM(NSInteger, FlutterStandardField) {
|
||||
FlutterStandardFieldIntHex,
|
||||
FlutterStandardFieldFloat64,
|
||||
FlutterStandardFieldString,
|
||||
// The following must match the corresponding order from `FlutterStandardDataType`.
|
||||
FlutterStandardFieldUInt8Data,
|
||||
FlutterStandardFieldInt32Data,
|
||||
FlutterStandardFieldInt64Data,
|
||||
FlutterStandardFieldFloat64Data,
|
||||
FlutterStandardFieldList,
|
||||
FlutterStandardFieldMap,
|
||||
FlutterStandardFieldFloat32Data,
|
||||
};
|
||||
|
||||
namespace flutter {
|
||||
FlutterStandardField FlutterStandardFieldForDataType(FlutterStandardDataType type) {
|
||||
return (FlutterStandardField)(type + FlutterStandardFieldUInt8Data);
|
||||
switch (type) {
|
||||
case FlutterStandardDataTypeUInt8:
|
||||
return FlutterStandardFieldUInt8Data;
|
||||
case FlutterStandardDataTypeInt32:
|
||||
return FlutterStandardFieldInt32Data;
|
||||
case FlutterStandardDataTypeInt64:
|
||||
return FlutterStandardFieldInt64Data;
|
||||
case FlutterStandardDataTypeFloat32:
|
||||
return FlutterStandardFieldFloat32Data;
|
||||
case FlutterStandardDataTypeFloat64:
|
||||
return FlutterStandardFieldFloat64Data;
|
||||
}
|
||||
}
|
||||
FlutterStandardDataType FlutterStandardDataTypeForField(FlutterStandardField field) {
|
||||
return (FlutterStandardDataType)(field - FlutterStandardFieldUInt8Data);
|
||||
switch (field) {
|
||||
case FlutterStandardFieldUInt8Data:
|
||||
return FlutterStandardDataTypeUInt8;
|
||||
case FlutterStandardFieldInt32Data:
|
||||
return FlutterStandardDataTypeInt32;
|
||||
case FlutterStandardFieldInt64Data:
|
||||
return FlutterStandardDataTypeInt64;
|
||||
case FlutterStandardFieldFloat32Data:
|
||||
return FlutterStandardDataTypeFloat32;
|
||||
case FlutterStandardFieldFloat64Data:
|
||||
return FlutterStandardDataTypeFloat64;
|
||||
default:
|
||||
return FlutterStandardDataTypeUInt8;
|
||||
}
|
||||
}
|
||||
|
||||
UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type) {
|
||||
switch (type) {
|
||||
case FlutterStandardDataTypeUInt8:
|
||||
@ -40,6 +65,8 @@ UInt8 elementSizeForFlutterStandardDataType(FlutterStandardDataType type) {
|
||||
return 4;
|
||||
case FlutterStandardDataTypeInt64:
|
||||
return 8;
|
||||
case FlutterStandardDataTypeFloat32:
|
||||
return 4;
|
||||
case FlutterStandardDataTypeFloat64:
|
||||
return 8;
|
||||
}
|
||||
|
||||
@ -176,6 +176,13 @@ TEST(FlutterStandardCodec, CanEncodeAndDecodeInt64Array) {
|
||||
checkEncodeDecode(value);
|
||||
}
|
||||
|
||||
TEST(FlutterStandardCodec, CanEncodeAndDecodeFloat32Array) {
|
||||
uint8_t bytes[8] = {0xd8, 0x0f, 0x49, 0x40, 0x00, 0x00, 0x7a, 0x44};
|
||||
NSData* data = [NSData dataWithBytes:bytes length:8];
|
||||
FlutterStandardTypedData* value = [FlutterStandardTypedData typedDataWithFloat32:data];
|
||||
checkEncodeDecode(value);
|
||||
}
|
||||
|
||||
TEST(FlutterStandardCodec, CanEncodeAndDecodeFloat64Array) {
|
||||
uint8_t bytes[16] = {0xBA, 0x5E, 0xBA, 0x11, 0xff, 0xff, 0xff, 0xff,
|
||||
0xBA, 0x5E, 0xBA, 0x11, 0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user